diff --git a/Private/Get-ADAdministrativeGroups.ps1 b/Private/Get-ADAdministrativeGroups.ps1 index 384af87..65dd994 100644 --- a/Private/Get-ADAdministrativeGroups.ps1 +++ b/Private/Get-ADAdministrativeGroups.ps1 @@ -41,10 +41,14 @@ foreach ($Domain in $ForestInformation.Domains) { $ADDictionary[$Domain] = [ordered] @{} - $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] - $DomainInformation = Get-ADDomain -Server $QueryServer - if ($Type -contains 'DomainAdmins') { + $QueryServerInformation = $ForestInformation['QueryServers'][$Domain] + if (-not $QueryServerInformation -or -not $QueryServerInformation['HostName']) { + continue + } + $QueryServer = $QueryServerInformation['HostName'][0] + $DomainInformation = Get-ADDomain -Server $QueryServer + Get-ADGroup -Filter "SID -eq '$($DomainInformation.DomainSID)-512'" -Server $QueryServer -ErrorAction SilentlyContinue | ForEach-Object { $ADDictionary['ByNetBIOS']["$($DomainInformation.NetBIOSName)\$($_.Name)"] = $_ $ADDictionary[$Domain]['DomainAdmins'] = "$($DomainInformation.NetBIOSName)\$($_.Name)" @@ -54,11 +58,18 @@ } foreach ($Domain in $ForestInformation.Forest.Domains) { + if ($Domain -in $ExcludeDomains) { + continue + } if (-not $ADDictionary[$Domain]) { $ADDictionary[$Domain] = [ordered] @{} } if ($Type -contains 'EnterpriseAdmins') { - $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] + $QueryServerInformation = $ForestInformation['QueryServers'][$Domain] + if (-not $QueryServerInformation -or -not $QueryServerInformation['HostName']) { + continue + } + $QueryServer = $QueryServerInformation['HostName'][0] $DomainInformation = Get-ADDomain -Server $QueryServer Get-ADGroup -Filter "SID -eq '$($DomainInformation.DomainSID)-519'" -Server $QueryServer -ErrorAction SilentlyContinue | ForEach-Object { @@ -70,4 +81,4 @@ } $ADDictionary -} \ No newline at end of file +} diff --git a/Public/Get-GPOZaurrRedirect.ps1 b/Public/Get-GPOZaurrRedirect.ps1 index dd9f206..a471f3f 100644 --- a/Public/Get-GPOZaurrRedirect.ps1 +++ b/Public/Get-GPOZaurrRedirect.ps1 @@ -106,7 +106,7 @@ $Splat['Filter'] = -join ($Splat['Filter'], ' -and ((WhenChanged -ge $DateFrom -and WhenChanged -le $DateTo) -or (WhenCreated -ge $DateFrom -and WhenCreated -le $DateTo))') } elseif ($DateProperty -eq 'WhenChanged' -or $DateProperty -eq 'WhenCreated') { $Property = $DateProperty[0] - $Splat['Filter'] = -join ($Splat['Filter'], ' -and ($Property -ge $DateFrom -and $Property -le $DateTo)') + $Splat['Filter'] = -join ($Splat['Filter'], " -and ($Property -ge `$DateFrom -and $Property -le `$DateTo)") } else { Write-Warning -Message "Get-GPOZaurrRedirect - DateProperty parameter is empty. Provide name and try again." continue @@ -118,7 +118,7 @@ $Splat['Filter'] = -join ($Splat['Filter'], ' -and ((WhenChanged -ge $DateFrom -and WhenChanged -le $DateTo) -or (WhenCreated -ge $DateFrom -and WhenCreated -le $DateTo))') } elseif ($DateProperty -eq 'WhenChanged' -or $DateProperty -eq 'WhenCreated') { $Property = $DateProperty[0] - $Splat['Filter'] = -join ($Splat['Filter'], ' -and ($Property -ge $DateFrom -and $Property -le $DateTo)') + $Splat['Filter'] = -join ($Splat['Filter'], " -and ($Property -ge `$DateFrom -and $Property -le `$DateTo)") } else { Write-Warning -Message "Get-GPOZaurrRedirect - DateProperty parameter is empty. Provide name and try again." continue @@ -161,4 +161,4 @@ End { } -} \ No newline at end of file +} diff --git a/Tests/ADAdministrativeGroups.Tests.ps1 b/Tests/ADAdministrativeGroups.Tests.ps1 new file mode 100644 index 0000000..dd201db --- /dev/null +++ b/Tests/ADAdministrativeGroups.Tests.ps1 @@ -0,0 +1,50 @@ +Describe 'Get-ADAdministrativeGroups domain filtering' { + BeforeAll { + Import-Module $PSScriptRoot\..\GPOZaurr.psm1 -Force + } + + It 'skips excluded and unreachable domains without indexing missing query servers' { + InModuleScope GPOZaurr { + function Get-ADDomain { + param([string] $Server) + } + function Get-ADGroup { + param( + [string] $Filter, + [string] $Server, + [System.Management.Automation.ActionPreference] $ErrorAction + ) + } + + Mock Get-WinADForestDetails { + [ordered] @{ + Forest = [PSCustomObject] @{ Domains = @('root.contoso.com', 'excluded.contoso.com', 'offline.contoso.com') } + Domains = @('root.contoso.com', 'offline.contoso.com') + QueryServers = @{ + 'root.contoso.com' = @{ HostName = @('dc1.root.contoso.com') } + } + } + } + Mock Get-ADDomain { + [PSCustomObject] @{ + DomainSID = 'S-1-5-21-1-2-3' + NetBIOSName = 'ROOT' + } + } + Mock Get-ADGroup { + [PSCustomObject] @{ + Name = if ($Filter -match '519') { 'Enterprise Admins' } else { 'Domain Admins' } + ObjectClass = 'group' + SID = [PSCustomObject] @{ Value = if ($Filter -match '519') { 'S-1-5-21-1-2-3-519' } else { 'S-1-5-21-1-2-3-512' } } + } + } + + $Result = Get-ADAdministrativeGroups -Type DomainAdmins, EnterpriseAdmins -ExcludeDomains 'excluded.contoso.com' + + $Result['ByNetBIOS'].Keys | Should -Contain 'ROOT\Domain Admins' + $Result['ByNetBIOS'].Keys | Should -Contain 'ROOT\Enterprise Admins' + $Result.Keys | Should -Not -Contain 'excluded.contoso.com' + Should -Invoke -CommandName Get-ADDomain -Times 2 -Exactly -ParameterFilter { $Server -eq 'dc1.root.contoso.com' } + } + } +} diff --git a/Tests/DateFilters.Tests.ps1 b/Tests/DateFilters.Tests.ps1 new file mode 100644 index 0000000..9683080 --- /dev/null +++ b/Tests/DateFilters.Tests.ps1 @@ -0,0 +1,43 @@ +Describe 'GPO date filters' { + BeforeAll { + Import-Module $PSScriptRoot\..\GPOZaurr.psm1 -Force + } + + BeforeEach { + InModuleScope GPOZaurr { + Mock Get-WinADForestDetails { + [ordered] @{ + Domains = @('root.contoso.com') + QueryServers = @{ 'root.contoso.com' = @{ HostName = @('dc1.root.contoso.com') } } + } + } + Mock Get-ChoosenDates { + [PSCustomObject] @{ + DateFrom = [datetime] '2026-08-01' + DateTo = [datetime] '2026-08-08' + } + } + Mock Get-ADObject {} + } + } + + It 'keeps DateTime variables intact in Get-GPOZaurrAD filters' { + InModuleScope GPOZaurr { + Get-GPOZaurrAD -DateRange Last7Days -DateProperty WhenCreated + + Should -Invoke -CommandName Get-ADObject -Times 1 -Exactly -ParameterFilter { + $Filter -eq "(objectClass -eq 'groupPolicyContainer') -and (WhenCreated -ge `$DateFrom -and WhenCreated -le `$DateTo)" + } + } + } + + It 'keeps DateTime variables intact in Get-GPOZaurrRedirect filters' { + InModuleScope GPOZaurr { + Get-GPOZaurrRedirect -DateRange Last7Days -DateProperty WhenChanged + + Should -Invoke -CommandName Get-ADObject -Times 1 -Exactly -ParameterFilter { + $Filter -eq "(objectClass -eq 'groupPolicyContainer') -and (WhenChanged -ge `$DateFrom -and WhenChanged -le `$DateTo)" + } + } + } +}