Public/Get-EFComplianceReport.ps1

function Get-EFComplianceReport {
    <#
    .SYNOPSIS
    Checks this computer against a Windows settings checklist.
 
    .DESCRIPTION
    Reads each selected Windows setting and compares it with the expected value in a
    checklist. It does not change Windows. In script output, a checklist is called a
    baseline and each checklist item is called a control. Those names are retained so
    existing PowerShell automation remains compatible.
 
    The report includes results, a score, guidance, and a predictable ExitCode for
    scripts: 0 when checked items match, 2 when an item does not match, or 3 when one or
    more items could not be checked.
 
    Use Test-EFEndpointCompliance when a simple Boolean answer is needed.
 
    .PARAMETER Baseline
    The checklist to use: a built-in name, a checklist JSON file, or an object returned
    by Get-EFBaseline.
 
    .PARAMETER ControlId
    One or more checklist item IDs to check. Every item is checked by default.
 
    .PARAMETER NoProgress
    Suppresses the progress display for non-interactive automation hosts.
 
    .EXAMPLE
    Get-EFComplianceReport
 
    .EXAMPLE
    $report = Get-EFComplianceReport -Baseline .\contoso-baseline.json
    $report.Results | Where-Object Status -ne 'Compliant'
 
    .OUTPUTS
    EndpointForge.ComplianceReport
    #>

    [CmdletBinding()]
    param(
        [Parameter(Position = 0)]
        [AllowNull()]
        [object]$Baseline = 'EnterpriseRecommended',

        [string[]]$ControlId,

        [switch]$NoProgress
    )

    $null = Test-EFWindows -Throw
    $correlationId = [guid]::NewGuid().ToString()
    $resolvedBaseline = Resolve-EFBaseline -Baseline $Baseline
    $controls = @($resolvedBaseline.Controls)

    if ($PSBoundParameters.ContainsKey('ControlId') -and $null -ne $ControlId -and $ControlId.Length -gt 0) {
        $missingIds = @($ControlId | Where-Object { $_ -notin $controls.Id })
        if ($missingIds.Count -gt 0) {
            throw [System.ArgumentException]::new("Unknown control Id(s): $($missingIds -join ', ')")
        }
        $controls = @($controls | Where-Object { $_.Id -in @($ControlId) })
    }

    Write-EFLog -Message "Compliance evaluation started for baseline '$($resolvedBaseline.Name)'." `
        -CorrelationId $correlationId -Data @{ controlCount = $controls.Count }

    $controlIndex = 0
    $baselineCommandArgument = Get-EFBaselineCommandArgument -Baseline $resolvedBaseline
    $results = @(
        foreach ($control in $controls) {
            $controlIndex++
            if (-not $NoProgress) {
                Write-Progress -Id 1102 -Activity 'EndpointForge Windows settings check' `
                    -Status "Checking: $($control.Title)" `
                    -PercentComplete ([math]::Round(($controlIndex / $controls.Count) * 100))
            }
            $controlResult = Get-EFControlState -Control $control
            if ($controlResult.Status -eq 'NonCompliant' -and $controlResult.Remediable) {
                $controlResult.RecommendedAction = if ($null -ne $baselineCommandArgument) {
                    "Preview this supported fix before approval. For scripts: Invoke-EFEndpointRemediation $baselineCommandArgument -ControlId '$($controlResult.ControlId)' -WhatIf"
                }
                else {
                    'Create a fix plan from this same in-memory checklist, then preview the supported change before approval.'
                }
            }
            $controlResult
        }
    )
    if (-not $NoProgress) {
        Write-Progress -Id 1102 -Activity 'EndpointForge Windows settings check' -Completed
    }

    $compliantCount = @($results | Where-Object Status -eq 'Compliant').Count
    $nonCompliantCount = @($results | Where-Object Status -eq 'NonCompliant').Count
    $notApplicableCount = @($results | Where-Object Status -eq 'NotApplicable').Count
    $errorCount = @($results | Where-Object Status -eq 'Error').Count
    $knownCount = $compliantCount + $nonCompliantCount
    $attemptedCount = $knownCount + $errorCount
    $score = if ($knownCount -eq 0) { 100 } else { [math]::Round(($compliantCount / $knownCount) * 100, 1) }
    $coveragePercent = if ($attemptedCount -eq 0) { 100 } else { [math]::Round(($knownCount / $attemptedCount) * 100, 1) }
    $dataStatus = if ($errorCount -eq 0) { 'Complete' } elseif ($knownCount -eq 0) { 'Failed' } else { 'Partial' }
    $isCompliant = $nonCompliantCount -eq 0 -and $errorCount -eq 0
    $exitCode = if ($errorCount -gt 0) { 3 } elseif ($nonCompliantCount -gt 0) { 2 } else { 0 }
    $status = if ($nonCompliantCount -gt 0) { 'NonCompliant' } elseif ($errorCount -gt 0) { 'Incomplete' } else { 'Compliant' }
    $summaryText = if ($isCompliant) {
        "$compliantCount applicable checklist item(s) match the expected settings."
    }
    elseif ($errorCount -gt 0) {
        "The check is incomplete: $nonCompliantCount item(s) do not match and $errorCount could not be checked."
    }
    else {
        "$nonCompliantCount checklist item(s) need attention. $score% of the settings that could be checked match."
    }
    $nextStep = if ($isCompliant) {
        'No supported fix is needed.'
    }
    elseif ($errorCount -gt 0) {
        'Review the items that could not be checked. Some protected information requires PowerShell to be opened with Run as Administrator (also called an elevated session).'
    }
    else {
        'Create a fix plan to see what EndpointForge can safely preview and what needs a person to review.'
    }

    $report = [pscustomobject]@{
        PSTypeName          = 'EndpointForge.ComplianceReport'
        ComputerName        = $env:COMPUTERNAME
        BaselineName        = [string]$resolvedBaseline.Name
        BaselineVersion     = [string]$resolvedBaseline.Version
        ChecklistName       = [string]$resolvedBaseline.Name
        ChecklistVersion    = [string]$resolvedBaseline.Version
        ChecklistItemCount  = $controls.Count
        CorrelationId       = $correlationId
        EvaluatedAtUtc      = [DateTime]::UtcNow
        IsCompliant         = $isCompliant
        Status              = $status
        Score               = $score
        DataStatus          = $dataStatus
        CoveragePercent     = $coveragePercent
        ExitCode            = $exitCode
        Summary             = $summaryText
        NextStep            = $nextStep
        CompliantCount      = $compliantCount
        NonCompliantCount   = $nonCompliantCount
        NotApplicableCount  = $notApplicableCount
        ErrorCount          = $errorCount
        Results             = $results
    }

    Write-EFLog -Message "Compliance evaluation completed for baseline '$($resolvedBaseline.Name)'." `
        -Level $(if ($isCompliant) { 'Information' } else { 'Warning' }) -CorrelationId $correlationId `
        -Data @{ score = $score; exitCode = $exitCode; nonCompliant = $nonCompliantCount; errors = $errorCount }

    return $report
}