microsoft / PowerStig

STIG Automation
https://www.powershellgallery.com/packages/PowerSTIG
Other
547 stars 114 forks source link

Incorrect Initialization of $script:allResources exposed with multiple New-StigCheckList #1383

Open david-rse opened 2 months ago

david-rse commented 2 months ago

Describe the bug

With multiple DSC configurations applied, invoking New-StigCheckList results with not updating the STATUS for each rule correctly i.e., the status always remains as Not_Reviewed even though the rule is in the desired state. This is because $script:allResources may be initialized with the incorrect resource/configuration and therefore never initializes to the DSCResults from Test-DscConfiguration. This is true to every call to New-StigCheckList after the first call in which a different DSC configuration is tested.

In line 394 of Functions.Checklist.ps1 we see that $setting is always null in this use case (after the first call to New-StigCheckLit.

$setting = Get-SettingsFromResult -DscResults $DscResults -Id $vid

From the function Get-SettingsFromResult on line 643, we see that $script:allResources is already initialized, but not to the correct resource. So the results from Test-DscConfiguration is always ignored.

    if (-not $script:allResources)
    {
        $script:allResources = $DscResults.ResourcesNotInDesiredState + $DscResults.ResourcesInDesiredState
    }

    return $script:allResources.Where({$PSItem.ResourceID -match $id})

which leads to (line 424); and the status is never really evaulated.

$status = $statusMap['NotReviewed']

To Reproduce

1) Create DSC configurations for multiple composite resources. This example shows Chrome, Windows Defender AV, and Windows Client 11. 2) Compile and apply said configurations. 3) Run the below script. Checklists are made, but the status for each rule is in a Not_Reviewed state.

# Workaround for https://github.com/microsoft/PowerStig/issues/443; source the missing cmdlet.
# Get-StigXccdfBenchmarkContent : The term 'Get-StigXccdfBenchmarkContent' is not recognized as the name of a cmdlet
. 'C:\Program Files\WindowsPowerShell\Modules\PowerSTIG\4.22.0\Module\Common\Function.Xccdf'

function Generate-StigReport {
    param (
        [string]$ReferenceConfigurationPath,
        [string]$XccdfPath,
        [string]$OutputFileName
    )

    # Resolve paths
    $ReferenceConfiguration = Resolve-Path -Path $ReferenceConfigurationPath
    $XccdfPathResolved = Resolve-Path -Path $XccdfPath
    $OutputPath = Join-Path -Path (Get-Location).Path -ChildPath $OutputFileName

    # Test DSC Configuration
    $audit = Test-DscConfiguration -ReferenceConfiguration $ReferenceConfiguration.Path

    # Generate STIG Checklist
    New-StigCheckList -DscResults $audit -XccdfPath $XccdfPathResolved -OutputPath $OutputPath

    # Output path of the generated report for confirmation
    Write-Output "Report generated at: $OutputPath"
}

Generate-StigReport `
    -ReferenceConfigurationPath '.\dsc\Chrome\localhost.mof' `
    -XccdfPath "C:\Program Files\WindowsPowerShell\Modules\PowerSTIG\4.22.0\StigData\Archive\Chrome\U_Google_Chrome_STIG_V2R9_Manual-xccdf.xml" `
    -OutputFileName 'dsc\_ckl\chrome_mof.ckl'

Generate-StigReport `
    -ReferenceConfigurationPath '.\dsc\WindowsDefender\localhost.mof' `
    -XccdfPath "C:\Program Files\WindowsPowerShell\Modules\PowerSTIG\4.22.0\StigData\Archive\Windows.Defender\U_MS_Windows_Defender_Antivirus_STIG_V2R4_Manual-xccdf.xml" `
    -OutputFileName 'dsc\_ckl\windows_defender_av_mof.ckl'

Generate-StigReport `
    -ReferenceConfigurationPath '.\dsc\WindowsClient\localhost.mof' `
    -XccdfPath "C:\Program Files\WindowsPowerShell\Modules\PowerSTIG\4.22.0\StigData\Archive\Windows.Client\U_MS_Windows_11_STIG_V1R6_Manual-xccdf.xml" `
    -OutputFileName 'dsc\_ckl\windows_client_mof.ckl'

Expected behavior The results from DscResults are evaluated and reflected in the checklists.

Screenshots Demonstrating that $script:allResources here is inconsistent to what is expected. Here we see that this variable is a collection of the CimInstance for Chrome rather than WindowsDefender.

DscResults are for WindowsDefender Screenshot (2)

$script:allResources are for Chrome Screenshot (3)

Additional context Note that multiple DSC configurations must be applied and using a single file for each resource.

hinderjd commented 1 month ago

Incorporate the reset into your script to prevent conflicts between multiple calls of New-StigCheckList. This should ensure that the DscResults are properly evaluated for each configuration. Here's a sample structure:

function Generate-StigReport { param ( [string]$ReferenceConfigurationPath, [string]$XccdfPath, [string]$OutputFileName )

# Resolve paths
$ReferenceConfiguration = Resolve-Path -Path $ReferenceConfigurationPath
$XccdfPathResolved = Resolve-Path -Path $XccdfPath
$OutputPath = Join-Path -Path (Get-Location).Path -ChildPath $OutputFileName

# Test DSC Configuration
$audit = Test-DscConfiguration -ReferenceConfiguration $ReferenceConfiguration.Path

# Reset the $script:allResources variable
$script:allResources = $null

# Generate STIG Checklist
New-StigCheckList -DscResults $audit -XccdfPath $XccdfPathResolved -OutputPath $OutputPath

# Output path of the generated report for confirmation
Write-Output "Report generated at: $OutputPath"

}