From 9443906db65bdc4ffefd6ad387a3ebc94aef933c Mon Sep 17 00:00:00 2001 From: Friedrich Weinmann Date: Wed, 6 Dec 2023 13:24:38 +0100 Subject: [PATCH 1/2] update --- DomainManagement/changelog.md | 4 ++ .../grouppolicies/Test-DMGroupPolicy.ps1 | 47 ++++++++++--------- ...LinkedPolicy.ps1 => Get-GroupPolicyEx.ps1} | 10 ++-- .../groupPolicy/Remove-GroupPolicy.ps1 | 2 +- .../groupPolicy/Resolve-PolicyRevision.ps1 | 2 +- 5 files changed, 37 insertions(+), 28 deletions(-) rename DomainManagement/internal/functions/groupPolicy/{Get-LinkedPolicy.ps1 => Get-GroupPolicyEx.ps1} (86%) diff --git a/DomainManagement/changelog.md b/DomainManagement/changelog.md index 7685c74..907adc6 100644 --- a/DomainManagement/changelog.md +++ b/DomainManagement/changelog.md @@ -1,5 +1,9 @@ # Changelog +## ??? + +- Upd: Group Policy - will now detect group policies that have been created but not yet linked as created. + ## 1.8.199 (2023-09-27) - Fix: Groups - When renaming a group from a previous name, it will not find other updates to apply diff --git a/DomainManagement/functions/grouppolicies/Test-DMGroupPolicy.ps1 b/DomainManagement/functions/grouppolicies/Test-DMGroupPolicy.ps1 index 892d267..2169c56 100644 --- a/DomainManagement/functions/grouppolicies/Test-DMGroupPolicy.ps1 +++ b/DomainManagement/functions/grouppolicies/Test-DMGroupPolicy.ps1 @@ -72,23 +72,23 @@ #region Gather data $desiredPolicies = Get-DMGroupPolicy - $managedPolicies = Get-LinkedPolicy @parameters - foreach ($managedPolicy in $managedPolicies) { - if (-not $managedPolicy.DisplayName) { - Write-PSFMessage -Level Warning -String 'Test-DMGroupPolicy.ADObjectAccess.Failed' -StringValues $managedPolicy.DistinguishedName -Target $managedPolicy - New-TestResult @resultDefaults -Type 'ADAccessFailed' -Identity $managedPolicy.DistinguishedName -ADObject $managedPolicy + $allPolicies = Get-GroupPolicyEx @parameters + foreach ($groupPolicy in $allPolicies) { + if (-not $groupPolicy.DisplayName) { + Write-PSFMessage -Level Warning -String 'Test-DMGroupPolicy.ADObjectAccess.Failed' -StringValues $groupPolicy.DistinguishedName -Target $groupPolicy + New-TestResult @resultDefaults -Type 'ADAccessFailed' -Identity $groupPolicy.DistinguishedName -ADObject $groupPolicy continue } - # Resolve-PolicyRevision updates the content of $managedPolicy without producing output - try { Resolve-PolicyRevision -Policy $managedPolicy -Session $session } - catch { Write-PSFMessage -Level Warning -String 'Test-DMGroupPolicy.PolicyRevision.Lookup.Failed' -StringValues $managedPolicies.DisplayName -ErrorRecord $_ -EnableException $EnableException.ToBool() } + # Resolve-PolicyRevision updates the content of $groupPolicy without producing output + try { Resolve-PolicyRevision -Policy $groupPolicy -Session $session } + catch { Write-PSFMessage -Level Warning -String 'Test-DMGroupPolicy.PolicyRevision.Lookup.Failed' -StringValues $allPolicies.DisplayName -ErrorRecord $_ -EnableException $EnableException.ToBool() } } $desiredHash = @{ } - $managedHash = @{ } + $policyHash = @{ } foreach ($desiredPolicy in $desiredPolicies) { $desiredHash[$desiredPolicy.DisplayName] = $desiredPolicy } - foreach ($managedPolicy in $managedPolicies) { - if (-not $managedPolicy.DisplayName) { continue } - $managedHash[$managedPolicy.DisplayName] = $managedPolicy + foreach ($groupPolicy in $allPolicies) { + if (-not $groupPolicy.DisplayName) { continue } + $policyHash[$groupPolicy.DisplayName] = $groupPolicy } #endregion Gather data @@ -100,19 +100,19 @@ Configuration = $desiredPolicy } - if (-not $managedHash[$desiredPolicy.DisplayName]) { + if (-not $policyHash[$desiredPolicy.DisplayName]) { New-TestResult @resultUpdateDefaults -Type 'Create' continue } - $resultUpdateDefaults.ADObject = $managedHash[$desiredPolicy.DisplayName] + $resultUpdateDefaults.ADObject = $policyHash[$desiredPolicy.DisplayName] - switch ($managedHash[$desiredPolicy.DisplayName].State) { + switch ($policyHash[$desiredPolicy.DisplayName].State) { 'ConfigError' { New-TestResult @resultUpdateDefaults -Type 'ConfigError' } 'CriticalError' { New-TestResult @resultUpdateDefaults -Type 'CriticalError' } 'Healthy' { $changes = [System.Collections.ArrayList]@() - $policyObject = $managedHash[$desiredPolicy.DisplayName] + $policyObject = $policyHash[$desiredPolicy.DisplayName] if ($policyObject.Version -ne $policyObject.ADVersion) { $change = New-Change -Property Modified -OldValue $policyObject.Version -NewValue $policyObject.ADVersion -Identity $desiredPolicy.DisplayName -Type AdmfVersion $null = $changes.Add($change) @@ -128,8 +128,8 @@ $null = $changes.Add($change) } } - if ("$($desiredPolicy.WmiFilter)" -ne "$($managedHash[$desiredPolicy.DisplayName].WmiFilter)") { - $change = New-Change -Property WmiFilter -OldValue $managedHash[$desiredPolicy.DisplayName].WmiFilter -NewValue $desiredPolicy.WmiFilter -Identity $desiredPolicy.DisplayName -Type WmiFilterAssignment + if ("$($desiredPolicy.WmiFilter)" -ne "$($policyHash[$desiredPolicy.DisplayName].WmiFilter)") { + $change = New-Change -Property WmiFilter -OldValue $policyHash[$desiredPolicy.DisplayName].WmiFilter -NewValue $desiredPolicy.WmiFilter -Identity $desiredPolicy.DisplayName -Type WmiFilterAssignment $null = $changes.Add($change) } if ($changes.Count -gt 0) { @@ -144,10 +144,13 @@ #endregion Compare configuration to actual state #region Compare actual state to configuration - foreach ($managedPolicy in $managedHash.Values) { - if ($desiredHash[$managedPolicy.DisplayName]) { continue } - if ($managedPolicy.IsCritical) { continue } - New-TestResult @resultDefaults -Type 'Delete' -Identity $managedPolicy.DisplayName -ADObject $managedPolicy + foreach ($groupPolicy in $policyHash.Values) { + if ($desiredHash[$groupPolicy.DisplayName]) { continue } + if ($groupPolicy.IsCritical) { continue } + + # Don't delete any GPOs that have not been linked under a managed OU while not being desired + if (-not $groupPolicy.IsManageLinked) { continue } + New-TestResult @resultDefaults -Type 'Delete' -Identity $groupPolicy.DisplayName -ADObject $groupPolicy } #endregion Compare actual state to configuration } diff --git a/DomainManagement/internal/functions/groupPolicy/Get-LinkedPolicy.ps1 b/DomainManagement/internal/functions/groupPolicy/Get-GroupPolicyEx.ps1 similarity index 86% rename from DomainManagement/internal/functions/groupPolicy/Get-LinkedPolicy.ps1 rename to DomainManagement/internal/functions/groupPolicy/Get-GroupPolicyEx.ps1 index aa7a377..76492a2 100644 --- a/DomainManagement/internal/functions/groupPolicy/Get-LinkedPolicy.ps1 +++ b/DomainManagement/internal/functions/groupPolicy/Get-GroupPolicyEx.ps1 @@ -1,4 +1,4 @@ -function Get-LinkedPolicy { +function Get-GroupPolicyEx { <# .SYNOPSIS Scans all managed OUs and returns linked GPOs. @@ -14,7 +14,7 @@ The credentials to use for this operation. .EXAMPLE - PS C:\> Get-LinkedPolicy @parameters + PS C:\> Get-GroupPolicyEx @parameters Returns all group policy objects that are linked to OUs under management. #> @@ -47,10 +47,11 @@ $adObjects = foreach ($searchBase in (Resolve-ContentSearchBase @parameters)) { Get-ADObject @parameters -LDAPFilter '(gPLink=*)' -SearchBase $searchBase.SearchBase -SearchScope $translateScope[$searchBase.SearchScope] -Properties gPLink } + $managedGPs = $adObjects.gPLink | Split-GPLink | Sort-Object -Unique foreach ($adObject in $adObjects) { Add-Member -InputObject $adObject -MemberType NoteProperty -Name LinkedGroupPolicyObjects -Value ($adObject.gPLink | Split-GPLink) -Force } - foreach ($adPolicyObject in ($adObjects.LinkedGroupPolicyObjects | Select-Object -Unique | Get-ADObject @parameters -Properties $gpoProperties)) { + foreach ($adPolicyObject in Get-ADObject @parameters -LDAPFilter '(objectCategory=groupPolicyContainer)' -Properties $gpoProperties) { $result = [PSCustomObject]@{ PSTypeName = 'DomainManagement.GroupPolicy.Linked' DisplayName = $adPolicyObject.DisplayName @@ -63,6 +64,7 @@ Path = $adPolicyObject.gPCFileSysPath ObjectGUID = $adPolicyObject.ObjectGUID IsCritical = $adPolicyObject.isCriticalSystemObject + IsManageLinked = $adPolicyObject.DistinguishedName -in $managedGPs ADVersion = $adPolicyObject.VersionNumber ExportID = $null ImportTime = $null @@ -74,7 +76,7 @@ if ($adPolicyObject.gPCWQLFilter) { $result.WmiFilter = "" $registeredID = ($adPolicyObject.gPCWQLFilter -split ";")[1] - $wmiFilter = $wmiFilters | Where-Object ID -eq $registeredID + $wmiFilter = $wmiFilters | Where-Object ID -EQ $registeredID if ($wmiFilter) { $result.WmiFilter = $wmiFilter.Name } } $result diff --git a/DomainManagement/internal/functions/groupPolicy/Remove-GroupPolicy.ps1 b/DomainManagement/internal/functions/groupPolicy/Remove-GroupPolicy.ps1 index 046b51c..03b413c 100644 --- a/DomainManagement/internal/functions/groupPolicy/Remove-GroupPolicy.ps1 +++ b/DomainManagement/internal/functions/groupPolicy/Remove-GroupPolicy.ps1 @@ -11,7 +11,7 @@ PowerShell remoting session to the server on which to perform the operation. .PARAMETER ADObject - AD object data retrieved when scanning the domain using Get-LinkedPolicy. + AD object data retrieved when scanning the domain using Get-GroupPolicyEx. .EXAMPLE PS C:\> Remove-GroupPolicy -Session $session -ADObject $testItem.ADObject -ErrorAction Stop diff --git a/DomainManagement/internal/functions/groupPolicy/Resolve-PolicyRevision.ps1 b/DomainManagement/internal/functions/groupPolicy/Resolve-PolicyRevision.ps1 index d2bb16c..3088f79 100644 --- a/DomainManagement/internal/functions/groupPolicy/Resolve-PolicyRevision.ps1 +++ b/DomainManagement/internal/functions/groupPolicy/Resolve-PolicyRevision.ps1 @@ -101,7 +101,7 @@ else { $Policy.State = 'CriticalError' Write-PSFMessage -Level Debug -String 'Resolve-PolicyRevision.Result.PolicyError' -StringValues $Policy.DisplayName -Target $Policy - throw "Policy object not found in filesystem. Check existence and permissions!" + throw "Policy object not found in filesystem. Check existence and permissions! $($Policy.DisplayName) ($($Policy.ObjectGUID))" } } else { From 95dd6f97723d7cb429c6c89115b131cce374d8a2 Mon Sep 17 00:00:00 2001 From: Friedrich Weinmann Date: Fri, 8 Dec 2023 09:59:54 +0100 Subject: [PATCH 2/2] Added MayModify parameter for GPOs --- DomainManagement/DomainManagement.psd1 | 2 +- DomainManagement/changelog.md | 3 ++- .../functions/grouppolicies/Register-DMGroupPolicy.ps1 | 8 ++++++++ .../functions/grouppolicies/Test-DMGroupPolicy.ps1 | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/DomainManagement/DomainManagement.psd1 b/DomainManagement/DomainManagement.psd1 index c4cf1b0..af0c4d8 100644 --- a/DomainManagement/DomainManagement.psd1 +++ b/DomainManagement/DomainManagement.psd1 @@ -3,7 +3,7 @@ RootModule = 'DomainManagement.psm1' # Version number of this module. - ModuleVersion = '1.8.199' + ModuleVersion = '1.8.201' # ID used to uniquely identify this module GUID = '0a405382-ebc2-445b-8325-541535810193' diff --git a/DomainManagement/changelog.md b/DomainManagement/changelog.md index 907adc6..6005809 100644 --- a/DomainManagement/changelog.md +++ b/DomainManagement/changelog.md @@ -1,8 +1,9 @@ # Changelog -## ??? +## 1.8.201 (2023-12-08) - Upd: Group Policy - will now detect group policies that have been created but not yet linked as created. +- Upd: Group Policy - supports a setting (`-MayModify`) to ignore manual changes after deploying a GPO via ADMF. ## 1.8.199 (2023-09-27) diff --git a/DomainManagement/functions/grouppolicies/Register-DMGroupPolicy.ps1 b/DomainManagement/functions/grouppolicies/Register-DMGroupPolicy.ps1 index 42ff5b1..4579e7b 100644 --- a/DomainManagement/functions/grouppolicies/Register-DMGroupPolicy.ps1 +++ b/DomainManagement/functions/grouppolicies/Register-DMGroupPolicy.ps1 @@ -22,6 +22,9 @@ .PARAMETER ExportID The tracking ID assigned to the GPO in order to detect its revision. + .PARAMETER MayModify + The group policy may be modified manually after deployment. + .PARAMETER WmiFilter The WmiFilter to apply to the group policy object. @@ -58,6 +61,10 @@ [string] $ExportID, + [Parameter(ValueFromPipelineByPropertyName = $true)] + [switch] + $MayModify, + [Parameter(ValueFromPipelineByPropertyName = $true)] [string] $WmiFilter, @@ -74,6 +81,7 @@ ID = $ID Path = $Path ExportID = $ExportID + MayModify = $MayModify WmiFilter = $WmiFilter ContextName = $ContextName } diff --git a/DomainManagement/functions/grouppolicies/Test-DMGroupPolicy.ps1 b/DomainManagement/functions/grouppolicies/Test-DMGroupPolicy.ps1 index 2169c56..89bb9ce 100644 --- a/DomainManagement/functions/grouppolicies/Test-DMGroupPolicy.ps1 +++ b/DomainManagement/functions/grouppolicies/Test-DMGroupPolicy.ps1 @@ -113,7 +113,7 @@ 'Healthy' { $changes = [System.Collections.ArrayList]@() $policyObject = $policyHash[$desiredPolicy.DisplayName] - if ($policyObject.Version -ne $policyObject.ADVersion) { + if (-not $desiredPolicy.MayModify -and $policyObject.Version -ne $policyObject.ADVersion) { $change = New-Change -Property Modified -OldValue $policyObject.Version -NewValue $policyObject.ADVersion -Identity $desiredPolicy.DisplayName -Type AdmfVersion $null = $changes.Add($change) }