Public/Get-ModernDomainScanReport.ps1

# Get-ModernDomainScanReport
# https://dss.globalcyberalliance.org/api/v1/docs#tag/version
# curl https://dss.globalcyberalliance.org/api/v1/scan/example.com

function Get-ModernDomainScanReport {
    <#
    .SYNOPSIS
        Retrieves and optionally displays a domain security scan report from Global Cyber Alliance.
    .DESCRIPTION
        [Global Cyber Alliance](https://github.com/GlobalCyberAlliance/domain-security-scanner)
    .PARAMETER Domain
        The domain name to scan (e.g., example.com).
    .PARAMETER Raw
        If specified, returns the raw 'advice' object instead of formatted output.
    .EXAMPLE
        Get-ModernDomainScanReport -Domain "contoso.com"
    .EXAMPLE
        Get-ModernDomainScanReport -Domain "contoso.com" -Raw
    .LINK
        https://exchangepermissions.alweys.ch/modernmailtools/Get-ModernDomainScanReport
    .INPUTS
        None
    .OUTPUTS
    .NOTES
    #>


    param (
        [Parameter(Mandatory = $true)]
        [string]$Domain, #= "globalcyberalliance.org"
        [switch]$Raw
    )

    $url = "https://dss.globalcyberalliance.org/api/v1/scan/$Domain"

    try {
        $response = Invoke-RestMethod -Uri $url -Method Get -ErrorAction Stop

        If ($Raw) {
            return $response.advice
        } else {
            Write-Output "`n=== Advice Section ===`n"
            foreach ($key in $response.advice.PSObject.Properties.Name) {
                $value = $response.advice.$key
                if ($value -is [System.Collections.IEnumerable] -and -not ($value -is [string])) {
                    Write-Output "${key}:`n$($value -join "`n")`n"
                } else {
                    Write-Output "${key}: $value`n"
                }
            }

            $adviceHashtable = @{}
            foreach ($property in $response.advice.PSObject.Properties) {
                $adviceHashtable[$property.Name] = $property.Value
            }

            $evaluation = EvaluateAdvice -Advice $adviceHashtable
            Write-Output "`n=== Evaluation Section ===`n"
            Write-Output "Actionable Items:`n$($evaluation.ActionableItems -join "`n")`n"
            Write-Output "Warnings:`n$($evaluation.Warnings -join "`n")`n"
            Write-Output "Confirmations:`n$($evaluation.Confirmations -join "`n")`n"

            Write-Output "`n=== Scan Result Section ===`n"
            foreach ($key in $response.scanResult.PSObject.Properties.Name) {
                $value = $response.scanResult.$key
                if ($value -is [System.Collections.IEnumerable] -and -not ($value -is [string])) {
                    Write-Output "${key}:`n$($value -join "`n")`n"
                } else {
                    Write-Output "${key}: $value`n"
                }
            }
        }
    } catch {
        Write-Error "Failed to retrieve scan report: $_"
    }
}

function EvaluateAdvice {
    param (
        [Parameter(Mandatory = $true)]
        [hashtable]$Advice
    )

    $evaluation = @{
        ActionableItems = @()
        Warnings = @()
        Confirmations = @()
    }

    foreach ($key in $Advice.Keys) {
        $value = $Advice[$key]
        if ($value -is [System.Collections.IEnumerable] -and -not ($value -is [string])) {
            foreach ($item in $value) {
                if ($item -match "fix|setup|recommended") {
                    $evaluation.ActionableItems += "${key}: $item"
                } elseif ($item -match "couldn't|failed|not detected") {
                    $evaluation.Warnings += "${key}: $item"
                } elseif ($item -match "is setup|no further action needed") {
                    $evaluation.Confirmations += "${key}: $item"
                } else {
                    $evaluation.Warnings += "${key}: $item" # Default to warnings for ambiguous cases
                }
            }
        } else {
            if ($value -match "fix|setup|recommended") {
                $evaluation.ActionableItems += "${key}: $value"
            } elseif ($value -match "couldn't|failed|not detected") {
                $evaluation.Warnings += "${key}: $value"
            } elseif ($value -match "is setup|no further action needed") {
                $evaluation.Confirmations += "${key}: $value"
            } else {
                $evaluation.Warnings += "${key}: $value" # Default to warnings for ambiguous cases
            }
        }
    }

    return $evaluation
}