diff --git a/CHANGELOG.MD b/CHANGELOG.MD index d56c414..f21d091 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,5 +1,12 @@ # GPOZaurr Release History +## Unreleased +- Fix `WindowsDefender` content detection for newer ADMX categories by supporting both: + - `Windows Components/Windows Defender*` + - `Windows Components/Microsoft Defender Antivirus*` +- Fix `WindowsDefenderExploitGuard` detection for legacy/new category naming variants. +- Add Defender registry fallback parsing (`SOFTWARE\Microsoft\Windows Defender*`) so Defender settings that land in `RegistrySettings` are still surfaced in `WindowsDefender` report output. [#81](https://github.com/EvotecIT/GPOZaurr/issues/81) + ## 1.1.9 - 2024.12.02 - Fixes `Invoke-GPOZaurr` when using SplitReports without path [#58](https://github.com/EvotecIT/GPOZaurr/issues/58) diff --git a/Private/ConvertTo-XMLRegistryDefenderOnReport.ps1 b/Private/ConvertTo-XMLRegistryDefenderOnReport.ps1 new file mode 100644 index 0000000..a698efd --- /dev/null +++ b/Private/ConvertTo-XMLRegistryDefenderOnReport.ps1 @@ -0,0 +1,39 @@ +function ConvertTo-XMLRegistryDefenderOnReport { + <# + .SYNOPSIS + Converts Defender-related raw registry settings from the RegistrySettings report. + + .DESCRIPTION + This function is used as a fallback for Defender settings that are not exposed as + policy categories but are still present in RegistrySettings output. + + .PARAMETER GPO + RegistrySettings report object generated by ConvertTo-XMLRegistrySettings -SingleObject. + #> + [cmdletBinding()] + param( + [PSCustomObject] $GPO + ) + + foreach ($Registry in $GPO.Settings) { + if ($Registry.Key -like 'SOFTWARE\Microsoft\Windows Defender*') { + [PSCustomObject] [ordered] @{ + DisplayName = $GPO.DisplayName + DomainName = $GPO.DomainName + GUID = $GPO.GUID + GpoType = $GPO.GpoType + FallbackSource = 'RegistrySettings' + Hive = $Registry.Hive + Key = $Registry.Key + Name = $Registry.Name + Type = $Registry.Type + Value = $Registry.Value + Changed = $Registry.Changed + Filters = $Registry.Filters + Linked = $GPO.Linked + LinksCount = $GPO.LinksCount + Links = $GPO.Links + } + } + } +} diff --git a/Private/Script.GPODictionary.ps1 b/Private/Script.GPODictionary.ps1 index 5c1ace7..7b14924 100644 --- a/Private/Script.GPODictionary.ps1 +++ b/Private/Script.GPODictionary.ps1 @@ -1170,12 +1170,23 @@ Settings = 'Policy' } ) - GPOPath = 'Policies -> Administrative Templates -> Windows Components/Windows Defender' + ByReports = @( + @{ + Report = 'RegistrySettings' + } + ) + GPOPath = @( + 'Policies -> Administrative Templates -> Windows Components/Windows Defender' + 'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus' + ) Code = { - ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*' + ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*', 'Windows Components/Microsoft Defender Antivirus*' } CodeSingle = { - ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*' -SingleObject + ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*', 'Windows Components/Microsoft Defender Antivirus*' -SingleObject + } + CodeReport = { + ConvertTo-XMLRegistryDefenderOnReport -GPO $GPO } } WindowsDefenderExploitGuard = @{ @@ -1186,12 +1197,15 @@ Settings = 'Policy' } ) - GPOPath = 'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard' + GPOPath = @( + 'Policies -> Administrative Templates -> Windows Components/Windows Defender/Windows Defender Exploit Guard' + 'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard' + ) Code = { - ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*' + ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*/Windows Defender Exploit Guard*', 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*', 'Windows Components/Microsoft Defender Antivirus/Windows Defender Exploit Guard*' } CodeSingle = { - ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*' -SingleObject + ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Defender*/Windows Defender Exploit Guard*', 'Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard*', 'Windows Components/Microsoft Defender Antivirus/Windows Defender Exploit Guard*' -SingleObject } } # WindowsFirewall = @{ @@ -1428,4 +1442,4 @@ ConvertTo-XMLGenericPolicy -GPO $GPO -Category 'Windows Components/Windows Update*', 'Windows Components/Delivery Optimization*' -SingleObject } } -} \ No newline at end of file +} diff --git a/Tests/DefenderContent.Tests.ps1 b/Tests/DefenderContent.Tests.ps1 new file mode 100644 index 0000000..7913045 --- /dev/null +++ b/Tests/DefenderContent.Tests.ps1 @@ -0,0 +1,64 @@ +Describe 'Defender content detection' { + BeforeAll { + Import-Module $PSScriptRoot\..\*.psd1 -Force + } + + It 'WindowsDefender dictionary supports old and new categories' { + InModuleScope GPOZaurr { + $Entry = $Script:GPODitionary['WindowsDefender'] + $Entry.GPOPath | Should -Contain 'Policies -> Administrative Templates -> Windows Components/Windows Defender' + $Entry.GPOPath | Should -Contain 'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus' + $Entry.ByReports.Report | Should -Contain 'RegistrySettings' + $Entry.CodeReport.ToString() | Should -Match 'ConvertTo-XMLRegistryDefenderOnReport' + } + } + + It 'WindowsDefenderExploitGuard supports category variants' { + InModuleScope GPOZaurr { + $Entry = $Script:GPODitionary['WindowsDefenderExploitGuard'] + $Entry.GPOPath | Should -Contain 'Policies -> Administrative Templates -> Windows Components/Windows Defender/Windows Defender Exploit Guard' + $Entry.GPOPath | Should -Contain 'Policies -> Administrative Templates -> Windows Components/Microsoft Defender Antivirus/Microsoft Defender Exploit Guard' + $Entry.Code.ToString() | Should -Match 'Windows Components/Microsoft Defender Antivirus/Windows Defender Exploit Guard\*' + } + } + + It 'ConvertTo-XMLRegistryDefenderOnReport returns only Defender registry settings' { + InModuleScope GPOZaurr { + $GPO = [PSCustomObject] @{ + DisplayName = 'Test Defender GPO' + DomainName = 'contoso.com' + GUID = '11111111-1111-1111-1111-111111111111' + GpoType = 'Computer' + Linked = $true + LinksCount = 1 + Links = @('OU=Workstations,DC=contoso,DC=com') + Settings = @( + [PSCustomObject] @{ + Hive = 'HKEY_LOCAL_MACHINE' + Key = 'SOFTWARE\Microsoft\Windows Defender\MpEngine' + Name = 'MpFolderScanThreadCount' + Type = 'REG_DWORD' + Value = '4' + Changed = [datetime] '2026-02-18T11:15:00' + Filters = $null + } + [PSCustomObject] @{ + Hive = 'HKEY_LOCAL_MACHINE' + Key = 'SOFTWARE\Contoso\Other' + Name = 'Setting' + Type = 'REG_SZ' + Value = 'Value' + Changed = [datetime] '2026-02-18T11:15:00' + Filters = $null + } + ) + } + + [Array] $Result = ConvertTo-XMLRegistryDefenderOnReport -GPO $GPO + $Result.Count | Should -Be 1 + $Result[0].FallbackSource | Should -Be 'RegistrySettings' + $Result[0].Key | Should -Be 'SOFTWARE\Microsoft\Windows Defender\MpEngine' + $Result[0].Name | Should -Be 'MpFolderScanThreadCount' + } + } +}