Public/Invoke-DotNetCheckVulnerabilities.ps1

function Invoke-DotNetCheckVulnerabilities {
    param(
        [string]$Folder = (Get-Location).Path,
        [switch]$Transitive,
        [switch]$Interactive,
        [string[]]$Level = @('High', 'Critical'),
        [string]$AllowedFile = "allowed_vulnerabilities.json"
    )
    Test-Tool 'dotnet' -Assert
    Write-Log "dotnet check vulnerabilities..."
    Write-Log "Folder: $Folder" -Level Debug

    $AllowedFilePath = Join-Path $Folder $AllowedFile
    $Allowed = @{ packages = @(); vulnerabilities = @() }
    If (Test-Path "$AllowedFilePath") {
        $Allowed = Get-Content $AllowedFilePath -Raw | ConvertFrom-Json
    }

    $ProjOrSlnFile = Find-FirstFileByPattern -Path $Folder -Pattern "*.sln,*.csproj"
    Assert-Condition (Test-Path $ProjOrSlnFile) "solution or project file exists"
    $Arg1 = If ($Transitive.IsPresent) { '--include-transitive' } Else { '' }
    $Arg2 = If ($Interactive.IsPresent) { '--interactive' } Else { '' }
    $raw = Invoke-ShellCommand "dotnet list ${ProjOrSlnFile} package --format json --vulnerable $Arg1 $Arg2" 'dotnet audit' -WorkingDirectory $Folder -Result

    $Successful = $true
    $PackageNames = @()

    $allPackages = $raw | ConvertFrom-Json | Select-Object -ExpandProperty projects | Where-Object { $_.frameworks } | Select-Object -ExpandProperty frameworks | ForEach-Object { $_.topLevelPackages + $_.transitivePackages }
    $allPackages | ForEach-Object {
        $packages = $_
        $packages | ForEach-Object {
            $package = $_
            $key = "$($package.id)@$($package.resolvedVersion)"
            If ($PackageNames -contains $key) {
                RETURN
            }

            $PackageNames += $key
            $PackageSkip = $Allowed.packages -contains $key
            $package.vulnerabilities | ForEach-Object {
                $vulnerability = $_
                $LevelAllowed = (-Not ($Level -contains $vulnerability.severity))
                $VulnerabilityIgnore = $Allowed.vulnerabilities -contains $vulnerability.advisoryurl
                $Status = If ($PackageSkip) { "Skipped" } ElseIf ($LevelAllowed) { "Allowed" } ElseIf ($VulnerabilityIgnore) { "Ignore" } Else { "Vulnerable" }
                If ($Status -eq "Vulnerable") {
                    $Successful = $false
                }

                Write-Log "| $($key.PadRight(50)) | $($Status.PadRight(10)) | $($vulnerability.severity.PadRight(8)) | $($vulnerability.advisoryurl) |"
            }
        }
    }

    Assert-Condition ($Successful) "vulnerabilities"
}

enum PackageStatus {
    Vulnerable
    Allowed
    Ignore
    Skipped
}