From 3ddaa0fe4518fbfb42dc0776ffc3fa2ad1936467 Mon Sep 17 00:00:00 2001 From: Brian Wilhite Date: Tue, 6 Oct 2020 13:34:07 -0400 Subject: [PATCH 1/8] introducing back compat functions to checklist --- source/Module/STIG/Functions.Checklist.ps1 | 49 +++++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/source/Module/STIG/Functions.Checklist.ps1 b/source/Module/STIG/Functions.Checklist.ps1 index c1ca5731c..4f997f6c2 100644 --- a/source/Module/STIG/Functions.Checklist.ps1 +++ b/source/Module/STIG/Functions.Checklist.ps1 @@ -136,7 +136,7 @@ function New-StigCheckList } else { - throw "$($_) is not a valid path to a ManualChecklistEntriesFile.xml file. Provide a full valid path and filename." + throw "$($_) is not a valid path to a Manual Checklist Entries File file. Provide a full valid path and filename." } } )] @@ -171,7 +171,24 @@ function New-StigCheckList if ($PSBoundParameters.ContainsKey('ManualChecklistEntriesFile')) { - [xml] $manualCheckData = Get-Content -Path $ManualChecklistEntriesFile + <# + ******* TO-DO ******* need function to detect correct STIG ID for psd1 since it is used in the xml version + #> + $manualCheckListPath = Get-Item -Path $ManualChecklistEntriesFile + switch ($manualCheckListPath.Extension) + { + '.xml' + { + $manualCheckData = ConvertTo-ManualCheckListHashTable -Path $ManualChecklistEntriesFile + break + } + '.psd1' + { + $manualCheckData = Import-PowerShellDataFile -Path $ManualChecklistEntriesFile + break + } + } + } # Values for some of these fields can be read from the .mof file or the DSC results file @@ -356,6 +373,7 @@ function New-StigCheckList if ($PSCmdlet.ParameterSetName -eq 'mof') { $setting = Get-SettingsFromMof -ReferenceConfiguration $ReferenceConfiguration -Id $vid + # **** logic conversion here, to reference hashtable structure rather than xml structure $manualCheck = $manualCheckData.stigManualChecklistData.stigRuleData | Where-Object -FilterScript {$_.STIG -eq $stigFileName -and $_.ID -eq $vid} if ($setting) { @@ -377,6 +395,7 @@ function New-StigCheckList } elseif ($PSCmdlet.ParameterSetName -eq 'dsc') { + # **** logic conversion here, to reference hashtable structure rather than xml structure $manualCheck = $manualCheckData.stigManualChecklistData.stigRuleData | Where-Object -FilterScript {$_.STIG -eq $stigFileName -and $_.ID -eq $vid} if ($manualCheck) { @@ -794,3 +813,29 @@ function ConvertTo-SafeXml $escapedXml = [System.Security.SecurityElement]::Escape($UnescapedXmlString) return $escapedXml } + +function ConvertTo-ManualCheckListHashTable +{ + [OutputType([hashtable[]])] + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [string] + $Path + ) + + # Import ManualCheckList xml contents to convert to hashtable to match psd1 back compat + [xml] $xmlToConvert = Get-Content @PSBoundParameters + + foreach ($stigRuleData in $xmlToConvert.stigManualChecklistData.stigRuleData) + { + $stigRuleManualCheck = @{} + $stigRuleDataPropertyNames = (Get-Member -InputObject $stigRuleData -MemberType 'Property').Name + foreach ($stigRuleDataPropertyName in $stigRuleDataPropertyNames) + { + $stigRuleManualCheck.Add($stigRuleDataPropertyName, $stigRuleData.$stigRuleDataPropertyName) + } + $stigRuleManualCheck + } +} From b179b91c275cb1eab9c512427734086065a8e584 Mon Sep 17 00:00:00 2001 From: Brian Wilhite Date: Tue, 6 Oct 2020 17:34:00 -0400 Subject: [PATCH 2/8] new-checklist back compat fix --- source/Module/STIG/Functions.Checklist.ps1 | 121 ++++++++++++++++----- 1 file changed, 93 insertions(+), 28 deletions(-) diff --git a/source/Module/STIG/Functions.Checklist.ps1 b/source/Module/STIG/Functions.Checklist.ps1 index 4f997f6c2..54a47b0b6 100644 --- a/source/Module/STIG/Functions.Checklist.ps1 +++ b/source/Module/STIG/Functions.Checklist.ps1 @@ -171,24 +171,7 @@ function New-StigCheckList if ($PSBoundParameters.ContainsKey('ManualChecklistEntriesFile')) { - <# - ******* TO-DO ******* need function to detect correct STIG ID for psd1 since it is used in the xml version - #> - $manualCheckListPath = Get-Item -Path $ManualChecklistEntriesFile - switch ($manualCheckListPath.Extension) - { - '.xml' - { - $manualCheckData = ConvertTo-ManualCheckListHashTable -Path $ManualChecklistEntriesFile - break - } - '.psd1' - { - $manualCheckData = Import-PowerShellDataFile -Path $ManualChecklistEntriesFile - break - } - } - + $manualCheckData = ConvertTo-ManualCheckListHashTable -Path $ManualChecklistEntriesFile } # Values for some of these fields can be read from the .mof file or the DSC results file @@ -374,7 +357,7 @@ function New-StigCheckList { $setting = Get-SettingsFromMof -ReferenceConfiguration $ReferenceConfiguration -Id $vid # **** logic conversion here, to reference hashtable structure rather than xml structure - $manualCheck = $manualCheckData.stigManualChecklistData.stigRuleData | Where-Object -FilterScript {$_.STIG -eq $stigFileName -and $_.ID -eq $vid} + $manualCheck = $manualCheckData | Where-Object -FilterScript {$_.STIG -eq $stigFileName -and $_.ID -eq $vid} if ($setting) { $status = $statusMap['Open'] @@ -396,7 +379,7 @@ function New-StigCheckList elseif ($PSCmdlet.ParameterSetName -eq 'dsc') { # **** logic conversion here, to reference hashtable structure rather than xml structure - $manualCheck = $manualCheckData.stigManualChecklistData.stigRuleData | Where-Object -FilterScript {$_.STIG -eq $stigFileName -and $_.ID -eq $vid} + $manualCheck = $manualCheckData | Where-Object -FilterScript {$_.STIG -eq $stigFileName -and $_.ID -eq $vid} if ($manualCheck) { $status = $statusMap["$($manualCheck.Status)"] @@ -814,6 +797,22 @@ function ConvertTo-SafeXml return $escapedXml } +<# + .SYNOPSIS + Short description + + .DESCRIPTION + Long description + + .PARAMETER Path + Parameter description + + .EXAMPLE + An example + + .NOTES + General notes +#> function ConvertTo-ManualCheckListHashTable { [OutputType([hashtable[]])] @@ -825,17 +824,83 @@ function ConvertTo-ManualCheckListHashTable $Path ) - # Import ManualCheckList xml contents to convert to hashtable to match psd1 back compat - [xml] $xmlToConvert = Get-Content @PSBoundParameters + $fileDetail = Get-Item @PSBoundParameters - foreach ($stigRuleData in $xmlToConvert.stigManualChecklistData.stigRuleData) + switch ($fileDetail.Extension) { - $stigRuleManualCheck = @{} - $stigRuleDataPropertyNames = (Get-Member -InputObject $stigRuleData -MemberType 'Property').Name - foreach ($stigRuleDataPropertyName in $stigRuleDataPropertyNames) + '.xml' { - $stigRuleManualCheck.Add($stigRuleDataPropertyName, $stigRuleData.$stigRuleDataPropertyName) + # Import ManualCheckList xml contents to convert to hashtable to match psd1 back compat + [xml] $xmlToConvert = Get-Content @PSBoundParameters + + foreach ($stigRuleData in $xmlToConvert.stigManualChecklistData.stigRuleData) + { + $stigRuleManualCheck = @{} + $stigRuleDataPropertyNames = (Get-Member -InputObject $stigRuleData -MemberType 'Property').Name + foreach ($stigRuleDataPropertyName in $stigRuleDataPropertyNames) + { + $stigRuleManualCheck.Add($stigRuleDataPropertyName, $stigRuleData.$stigRuleDataPropertyName) + } + $stigRuleManualCheck + } + } + '.psd1' + { + $formattedPsd1ToConvert = (Get-Content @PSBoundParameters -Raw) -replace '"|@{' -split '}' + $convertedPsd1HashTable = $formattedPsd1ToConvert | ConvertFrom-StringData + foreach ($convertedHash in $convertedPsd1HashTable) + { + if ($convertedHash.Count -ne 0) + { + $stigFileName = Get-StigXccdfFileName -VulnId $convertedHash.VulID + $convertedHash.Add('STIG', $stigFileName.FileName) + $convertedHash.Add('Details', $convertedHash.Comments) + $convertedHash + } + } + } + } +} + +<# + .SYNOPSIS + Short description + + .DESCRIPTION + Long description + + .PARAMETER VulnId + Parameter description + + .EXAMPLE + An example + + .NOTES + General notes +#> +function Get-StigXccdfFileName +{ + [CmdletBinding()] + [OutputType([string])] + param + ( + [Parameter(Mandatory = $true)] + [string] + $VulnId + ) + + $processedXmlPath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\StigData\Processed\*.xml' + $processedXml = Select-String -Path $processedXmlPath -Pattern $VulnId -Exclude '*.org.default.xml' | Sort-Object -Property Pattern + + $stigVersionData = @() + foreach ($xmlPath in $processedXml.Path) + { + [xml] $xml = Get-Content -Path $xmlPath + $stigVersionData += [PSCustomObject] @{ + Version = [version] $xml.DISASTIG.fullversion + FileName = $xml.DISASTIG.filename } - $stigRuleManualCheck } + + $stigVersionData | Sort-Object -Property Version -Descending | Select-Object -First 1 } From 87c171aeedb6eec5ebf4b9a424c3bb85ab925bb2 Mon Sep 17 00:00:00 2001 From: Brian Wilhite Date: Wed, 7 Oct 2020 14:20:49 -0400 Subject: [PATCH 3/8] updated functions based on feedback --- source/Module/STIG/Functions.Checklist.ps1 | 87 ++++++++++++++++------ 1 file changed, 63 insertions(+), 24 deletions(-) diff --git a/source/Module/STIG/Functions.Checklist.ps1 b/source/Module/STIG/Functions.Checklist.ps1 index 54a47b0b6..46c410731 100644 --- a/source/Module/STIG/Functions.Checklist.ps1 +++ b/source/Module/STIG/Functions.Checklist.ps1 @@ -23,7 +23,7 @@ The location where the checklist .ckl file will be created. Must include the filename with .ckl on the end. .PARAMETER ManualChecklistEntriesFile - Location of a .xml file containing the input for Vulnerabilities unmanaged via DSC/PowerSTIG. + Location of a .xml or .psd1 file containing the input for Vulnerabilities unmanaged via DSC/PowerSTIG i.e.: Document/Manual Rules. This file can be created manually or by exporting an Excel worksheet as XML. The file format should look like the following: @@ -171,7 +171,7 @@ function New-StigCheckList if ($PSBoundParameters.ContainsKey('ManualChecklistEntriesFile')) { - $manualCheckData = ConvertTo-ManualCheckListHashTable -Path $ManualChecklistEntriesFile + $manualCheckData = ConvertTo-ManualCheckListHashTable -Path $ManualChecklistEntriesFile -XccdfPath $XccdfPath } # Values for some of these fields can be read from the .mof file or the DSC results file @@ -799,19 +799,24 @@ function ConvertTo-SafeXml <# .SYNOPSIS - Short description + Converts the xml or psd1 in to a consistent data structure (hashtable) for use with the New-StigCheckList function. .DESCRIPTION - Long description + Converts the xml or psd1 in to a consistent data structure (hashtable) for use with the New-StigCheckList function. .PARAMETER Path - Parameter description + Location of a .xml or .psd1 file containing the input for Vulnerabilities unmanaged via DSC/PowerSTIG i.e.: Document/Manual Rules. + + .PARAMETER XccdfPath + The path to a DISA STIG .xccdf file. PowerSTIG includes the supported files in the /PowerShell/StigData/Archive folder. .EXAMPLE - An example + PS> ConvertTo-ManualCheckListHashTable -Path C:\dev\ManualEntryData.psd1 -XccdfPath $xccdfPath + + Returns a hashtable that constains checklist data that will be used to inject into the ckl in the New-StigCheckList function. .NOTES - General notes + Internal use only function, not for Export-ModuleMember #> function ConvertTo-ManualCheckListHashTable { @@ -821,17 +826,21 @@ function ConvertTo-ManualCheckListHashTable ( [Parameter(Mandatory = $true)] [string] - $Path + $Path, + + [Parameter(Mandatory = $true)] + [string[]] + $XccdfPath ) - $fileDetail = Get-Item @PSBoundParameters + $fileDetail = Get-Item -Path $Path switch ($fileDetail.Extension) { '.xml' { # Import ManualCheckList xml contents to convert to hashtable to match psd1 back compat - [xml] $xmlToConvert = Get-Content @PSBoundParameters + [xml] $xmlToConvert = Get-Content -Path $Path foreach ($stigRuleData in $xmlToConvert.stigManualChecklistData.stigRuleData) { @@ -846,16 +855,16 @@ function ConvertTo-ManualCheckListHashTable } '.psd1' { - $formattedPsd1ToConvert = (Get-Content @PSBoundParameters -Raw) -replace '"|@{' -split '}' + $formattedPsd1ToConvert = (Get-Content -Path $Path -Raw) -replace '"|@{' -split '}' $convertedPsd1HashTable = $formattedPsd1ToConvert | ConvertFrom-StringData - foreach ($convertedHash in $convertedPsd1HashTable) + foreach ($stigRuleManualCheck in $convertedPsd1HashTable) { - if ($convertedHash.Count -ne 0) + if ($stigRuleManualCheck.Count -ne 0) { - $stigFileName = Get-StigXccdfFileName -VulnId $convertedHash.VulID - $convertedHash.Add('STIG', $stigFileName.FileName) - $convertedHash.Add('Details', $convertedHash.Comments) - $convertedHash + $stigFileName = Get-StigXccdfFileName -VulnId $stigRuleManualCheck.VulID -XccdfPath $XccdfPath + $stigRuleManualCheck.Add('STIG', $stigFileName) + $stigRuleManualCheck.Add('Details', $stigRuleManualCheck.Comments) + $stigRuleManualCheck } } } @@ -864,19 +873,24 @@ function ConvertTo-ManualCheckListHashTable <# .SYNOPSIS - Short description + Used to detect the correct STIG property when a psd1 is specified. .DESCRIPTION - Long description + Used to detect the correct STIG property when a psd1 is specified. .PARAMETER VulnId - Parameter description + The VulnId or RuleId for a given STIG Rule + + .PARAMETER XccdfPath + The path to a DISA STIG .xccdf file. PowerSTIG includes the supported files in the /PowerShell/StigData/Archive folder. .EXAMPLE - An example + PS> Get-StigXccdfFileName -VulnId 'V-1114' -XccdfPath C:\PowerStig\StigData\Archive\Windows.Server.2012R2\U_MS_Windows_2012_and_2012_R2_DC_STIG_V2R19_Manual-xccdf.xml + + Returns U_MS_Windows_2012_and_2012_R2_DC_STIG_V2R19_Manual-xccdf.xml as the correct xccdf file specified by the user. .NOTES - General notes + Internal use only function, not for Export-ModuleMember #> function Get-StigXccdfFileName { @@ -886,7 +900,11 @@ function Get-StigXccdfFileName ( [Parameter(Mandatory = $true)] [string] - $VulnId + $VulnId, + + [Parameter(Mandatory = $true)] + [string[]] + $XccdfPath ) $processedXmlPath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\StigData\Processed\*.xml' @@ -902,5 +920,26 @@ function Get-StigXccdfFileName } } - $stigVersionData | Sort-Object -Property Version -Descending | Select-Object -First 1 + # populate the STIG value based on Xccdf Path passed by user + $compareObjectParams = @{ + ReferenceObject = $(Split-Path -Path $XccdfPath -Leaf) + DifferenceObject = $stigVersionData.FileName + IncludeEqual = $true + ExcludeDifferent = $true + } + + $xccdfFileDetection = (Compare-Object @compareObjectParams).InputObject + + if ($xccdfFileDetection.Count -eq 1) + { + return $xccdfFileDetection + } + elseif ($xccdfFileDetection.Count -gt 1) + { + throw 'Unable to determine correct Xccdf file for psd1 usage, ensure that the correct Xccdf file(s) are used.' + } + else + { + return ($stigVersionData | Sort-Object -Property Version -Descending | Select-Object -First 1).FileName + } } From 78814cd94ddc82cdf2010effa1d06b7c0a64d620 Mon Sep 17 00:00:00 2001 From: Brian Wilhite Date: Wed, 7 Oct 2020 16:18:50 -0400 Subject: [PATCH 4/8] updated ConvertTo-ManualCheckListHashTable with correct property id --- source/Module/STIG/Functions.Checklist.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/Module/STIG/Functions.Checklist.ps1 b/source/Module/STIG/Functions.Checklist.ps1 index 46c410731..396deeb31 100644 --- a/source/Module/STIG/Functions.Checklist.ps1 +++ b/source/Module/STIG/Functions.Checklist.ps1 @@ -864,6 +864,8 @@ function ConvertTo-ManualCheckListHashTable $stigFileName = Get-StigXccdfFileName -VulnId $stigRuleManualCheck.VulID -XccdfPath $XccdfPath $stigRuleManualCheck.Add('STIG', $stigFileName) $stigRuleManualCheck.Add('Details', $stigRuleManualCheck.Comments) + $stigRuleManualCheck.Add('ID', $stigRuleManualCheck['VulId']) + $stigRuleManualCheck.Remove('VulId') $stigRuleManualCheck } } From e423249086f2b34fb3e0a68c2ca4cd99fb0a2cbe Mon Sep 17 00:00:00 2001 From: Brian Wilhite Date: Thu, 8 Oct 2020 09:01:39 -0400 Subject: [PATCH 5/8] updated changelog.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac447505c..a394bbfe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +* Fixed [#746](https://github.com/microsoft/PowerStig/issues/746): Functions.Checklist Manual Checks need to leverage psd1 files - Backward Compat Issue + ## [4.5.0] - 2020-09-01 * Update PowerSTIG to successfully parse/apply Windows 2012 R2 DC Version 2, Rev 21: [#677](https://github.com/microsoft/PowerStig/issues/677) From 6b79694e70db6610168a9c2abce9ba2ff21234e1 Mon Sep 17 00:00:00 2001 From: Brian Wilhite Date: Thu, 8 Oct 2020 10:44:03 -0400 Subject: [PATCH 6/8] removed unneeded comments. --- source/Module/STIG/Functions.Checklist.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/Module/STIG/Functions.Checklist.ps1 b/source/Module/STIG/Functions.Checklist.ps1 index 396deeb31..0824d5adf 100644 --- a/source/Module/STIG/Functions.Checklist.ps1 +++ b/source/Module/STIG/Functions.Checklist.ps1 @@ -356,7 +356,6 @@ function New-StigCheckList if ($PSCmdlet.ParameterSetName -eq 'mof') { $setting = Get-SettingsFromMof -ReferenceConfiguration $ReferenceConfiguration -Id $vid - # **** logic conversion here, to reference hashtable structure rather than xml structure $manualCheck = $manualCheckData | Where-Object -FilterScript {$_.STIG -eq $stigFileName -and $_.ID -eq $vid} if ($setting) { @@ -378,7 +377,6 @@ function New-StigCheckList } elseif ($PSCmdlet.ParameterSetName -eq 'dsc') { - # **** logic conversion here, to reference hashtable structure rather than xml structure $manualCheck = $manualCheckData | Where-Object -FilterScript {$_.STIG -eq $stigFileName -and $_.ID -eq $vid} if ($manualCheck) { From 2c0045054963bee3b741cb81563e516bd40f6f79 Mon Sep 17 00:00:00 2001 From: Brian Wilhite Date: Thu, 8 Oct 2020 11:05:40 -0400 Subject: [PATCH 7/8] updated comment based help. --- source/Module/STIG/Functions.Checklist.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Module/STIG/Functions.Checklist.ps1 b/source/Module/STIG/Functions.Checklist.ps1 index 0824d5adf..c95336c7e 100644 --- a/source/Module/STIG/Functions.Checklist.ps1 +++ b/source/Module/STIG/Functions.Checklist.ps1 @@ -25,7 +25,7 @@ .PARAMETER ManualChecklistEntriesFile Location of a .xml or .psd1 file containing the input for Vulnerabilities unmanaged via DSC/PowerSTIG i.e.: Document/Manual Rules. - This file can be created manually or by exporting an Excel worksheet as XML. The file format should look like the following: + This file can be created manually or by exporting an Excel worksheet as XML or psd1. The file format should look like the following: From 363426df1b84b3b2c8c841e1c032abf95fb721e5 Mon Sep 17 00:00:00 2001 From: Brian Wilhite Date: Thu, 8 Oct 2020 15:31:18 -0400 Subject: [PATCH 8/8] updated throw message --- source/Module/STIG/Functions.Checklist.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Module/STIG/Functions.Checklist.ps1 b/source/Module/STIG/Functions.Checklist.ps1 index c95336c7e..ea64a5ca6 100644 --- a/source/Module/STIG/Functions.Checklist.ps1 +++ b/source/Module/STIG/Functions.Checklist.ps1 @@ -136,7 +136,7 @@ function New-StigCheckList } else { - throw "$($_) is not a valid path to a Manual Checklist Entries File file. Provide a full valid path and filename." + throw "$($_) is not a valid path to a Manual Checklist Entries File. Provide a full valid path and filename." } } )]