From 25b64d0158b415dd824804ff4dc7187ff56091f3 Mon Sep 17 00:00:00 2001 From: Frederick Morlock Date: Wed, 17 Jun 2026 09:03:40 -0700 Subject: [PATCH 1/2] Duplicate AuditPolicyRule Convert module, verbatim No code has been changed. This new module will be modified for "Advanced" audit policy parsing in another commit. Making a copy here makes the changes in subsequent commits more obvious. --- .../AuditPolicyRuleAdvanced.Convert.psm1 | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 source/Module/Rule.AuditPolicy/Convert/AuditPolicyRuleAdvanced.Convert.psm1 diff --git a/source/Module/Rule.AuditPolicy/Convert/AuditPolicyRuleAdvanced.Convert.psm1 b/source/Module/Rule.AuditPolicy/Convert/AuditPolicyRuleAdvanced.Convert.psm1 new file mode 100644 index 000000000..69d98950f --- /dev/null +++ b/source/Module/Rule.AuditPolicy/Convert/AuditPolicyRuleAdvanced.Convert.psm1 @@ -0,0 +1,126 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +using module .\..\..\Common\Common.psm1 +using module .\..\AuditPolicyRule.psm1 +using namespace System.Text +# Header + +<# + .SYNOPSIS + Converts the xccdf check-content element into an audit policy object. +#> +class AuditPolicyRuleConvert : AuditPolicyRule +{ + <# + .SYNOPSIS + Empty constructor for SplitFactory + #> + AuditPolicyRuleConvert () + { + } + + <# + .SYNOPSIS + Converts an xccdf stig rule element into a Audit Policy Rule + .PARAMETER XccdfRule + The STIG rule to convert + #> + AuditPolicyRuleConvert ([xml.xmlelement] $XccdfRule) : base ($XccdfRule, $true) + { + $tokens = $this.ExtractProperties() + $this.SetSubcategory($tokens) + $this.SetAuditFlag($tokens) + $this.Ensure = [Ensure]::Present + $this.SetDuplicateRule() + $this.SetDscResource() + } + + <# + .SYNOPSIS + Extracts and returns the audit policy settings from the check-content. + .DESCRIPTION + This match looks for the following patterns + 1. Category >> Subcategory - AuditFlag + 2. Category -> Subcategory - AuditFlag + .NOTES + If any rule does not match this pattern, please update the xccdf + change log file to align to one of these options. + #> + [RegularExpressions.MatchCollection] ExtractProperties () + { + return [regex]::Matches( + $this.RawString, + '(?:(?:\w+(?:\s|\/))+(?:(?: >|>|-)>(?:\s+)?))(?(?:.+?(?=\s-\s)))\s-\s(?(?:\w+)+)' + ) + } + + <# + .SYNOPSIS + Set the subcategory name + .DESCRIPTION + Set the subcategory value. If the returned audit policy subcategory + is not valid, the parser status is set to fail. + #> + [void] SetSubcategory ([RegularExpressions.MatchCollection] $Regex) + { + $thisSubcategory = $regex.Groups.Where( + {$_.Name -eq 'subcategory'} + ).Value + + # Windows STIGS have 'Audit Audit' as part of the string, but the actual policy is 'Audit Policy Change' + $thisSubcategory = $thisSubcategory -replace 'Audit Audit', 'Audit' + + if (-not $this.SetStatus($thisSubcategory)) + { + $this.set_Subcategory($thisSubcategory.trim()) + } + } + + <# + .SYNOPSIS + Set the subcategory flag + .DESCRIPTION + Set the subcategory flag. If the returned audit policy subcategory + is not valid, the parser status is set to fail. + #> + [void] SetAuditFlag ([RegularExpressions.MatchCollection] $Regex) + { + $thisAuditFlag = $Regex.Groups.Where( + {$_.Name -eq 'auditflag'} + ).Value + + if (-not $this.SetStatus($thisAuditFlag)) + { + $this.set_AuditFlag($thisAuditFlag) + } + } + + hidden [void] SetDscResource () + { + if ($null -eq $this.DuplicateOf) + { + $this.DscResource = 'AuditPolicySubcategory' + } + else + { + $this.DscResource = 'None' + } + } + + <# + .SYNOPSIS + Checks if a rule matches an audit policy setting. + #> + static [bool] Match ([string] $CheckContent) + { + if + ( + $CheckContent -Match "\bAuditpol\b" -and + $CheckContent -NotMatch "resourceSACL" + ) + { + return $true + } + return $false + } +} From e7e264abce16bd49f0c3f6ffe83f1d9b5d7981a1 Mon Sep 17 00:00:00 2001 From: Frederick Morlock Date: Wed, 17 Jun 2026 09:05:53 -0700 Subject: [PATCH 2/2] "Advanced Audit Policy" parsing proof-of-concept This assumes a certain stability in the RawString text, but the pattern seems to hold for now. --- .../AuditPolicyRuleAdvanced.Convert.psm1 | 32 ++++++++++--------- .../Module/Rule/Convert/ConvertFactory.psm1 | 7 ++++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/source/Module/Rule.AuditPolicy/Convert/AuditPolicyRuleAdvanced.Convert.psm1 b/source/Module/Rule.AuditPolicy/Convert/AuditPolicyRuleAdvanced.Convert.psm1 index 69d98950f..afb4c58c8 100644 --- a/source/Module/Rule.AuditPolicy/Convert/AuditPolicyRuleAdvanced.Convert.psm1 +++ b/source/Module/Rule.AuditPolicy/Convert/AuditPolicyRuleAdvanced.Convert.psm1 @@ -9,13 +9,13 @@ using namespace System.Text .SYNOPSIS Converts the xccdf check-content element into an audit policy object. #> -class AuditPolicyRuleConvert : AuditPolicyRule +class AuditPolicyRuleAdvancedConvert : AuditPolicyRule { <# .SYNOPSIS Empty constructor for SplitFactory #> - AuditPolicyRuleConvert () + AuditPolicyRuleAdvancedConvert () { } @@ -25,7 +25,7 @@ class AuditPolicyRuleConvert : AuditPolicyRule .PARAMETER XccdfRule The STIG rule to convert #> - AuditPolicyRuleConvert ([xml.xmlelement] $XccdfRule) : base ($XccdfRule, $true) + AuditPolicyRuleAdvancedConvert ([xml.xmlelement] $XccdfRule) : base ($XccdfRule, $true) { $tokens = $this.ExtractProperties() $this.SetSubcategory($tokens) @@ -39,18 +39,24 @@ class AuditPolicyRuleConvert : AuditPolicyRule .SYNOPSIS Extracts and returns the audit policy settings from the check-content. .DESCRIPTION - This match looks for the following patterns - 1. Category >> Subcategory - AuditFlag - 2. Category -> Subcategory - AuditFlag + This match looks for the policy path and the required audit flag in + the following format: + + Computer Configuration >> ... >> Audit . + If "Audit " is not set to "", this is a finding + + The subcategory is taken from the final line of the RawString (the + leading "Audit " prefix is dropped), and the audit flag is taken from + the quoted value in the "is [not] set to" clause. .NOTES If any rule does not match this pattern, please update the xccdf - change log file to align to one of these options. + change log file to align to this option. #> [RegularExpressions.MatchCollection] ExtractProperties () { return [regex]::Matches( $this.RawString, - '(?:(?:\w+(?:\s|\/))+(?:(?: >|>|-)>(?:\s+)?))(?(?:.+?(?=\s-\s)))\s-\s(?(?:\w+)+)' + '"(?:Audit\s+)?(?[^"]+)"\s+is(?: not)? set to\s+"(?[^"]+)"' ) } @@ -64,12 +70,9 @@ class AuditPolicyRuleConvert : AuditPolicyRule [void] SetSubcategory ([RegularExpressions.MatchCollection] $Regex) { $thisSubcategory = $regex.Groups.Where( - {$_.Name -eq 'subcategory'} + { $_.Name -eq 'subcategory' } ).Value - # Windows STIGS have 'Audit Audit' as part of the string, but the actual policy is 'Audit Policy Change' - $thisSubcategory = $thisSubcategory -replace 'Audit Audit', 'Audit' - if (-not $this.SetStatus($thisSubcategory)) { $this.set_Subcategory($thisSubcategory.trim()) @@ -86,7 +89,7 @@ class AuditPolicyRuleConvert : AuditPolicyRule [void] SetAuditFlag ([RegularExpressions.MatchCollection] $Regex) { $thisAuditFlag = $Regex.Groups.Where( - {$_.Name -eq 'auditflag'} + { $_.Name -eq 'auditflag' } ).Value if (-not $this.SetStatus($thisAuditFlag)) @@ -115,8 +118,7 @@ class AuditPolicyRuleConvert : AuditPolicyRule { if ( - $CheckContent -Match "\bAuditpol\b" -and - $CheckContent -NotMatch "resourceSACL" + $CheckContent -Match ">> Advanced Audit Policy Configuration >>" ) { return $true diff --git a/source/Module/Rule/Convert/ConvertFactory.psm1 b/source/Module/Rule/Convert/ConvertFactory.psm1 index 7ede2e8d2..9a3548aab 100644 --- a/source/Module/Rule/Convert/ConvertFactory.psm1 +++ b/source/Module/Rule/Convert/ConvertFactory.psm1 @@ -4,6 +4,7 @@ using module .\..\..\Common\Common.psm1 using module .\..\..\Rule.HardCoded\Convert\HardCodedRule.Convert.psm1 using module .\..\..\Rule.AccountPolicy\Convert\AccountPolicyRule.Convert.psm1 using module .\..\..\Rule.AuditPolicy\Convert\AuditPolicyRule.Convert.psm1 +using module .\..\..\Rule.AuditPolicy\Convert\AuditPolicyRuleAdvanced.Convert.psm1 using module .\..\..\Rule.DnsServerRootHint\Convert\DnsServerRootHintRule.Convert.psm1 using module .\..\..\Rule.DnsServerSetting\Convert\DnsServerSettingRule.Convert.psm1 using module .\..\..\Rule.Document\Convert\DocumentRule.Convert.psm1 @@ -148,6 +149,12 @@ class ConvertFactory [AuditPolicyRuleConvert]::new($Rule).AsRule() ) } + {[AuditPolicyRuleAdvancedConvert]::Match($PSItem)} + { + $null = $ruleTypeList.Add( + [AuditPolicyRuleAdvancedConvert]::new($Rule).AsRule() + ) + } {[DnsServerSettingRuleConvert]::Match($PSItem)} { $null = $ruleTypeList.Add(