Ich habe angefangen ein kleines PowerShell Script zu erstellen, welches dabei unterstützen soll ungültige oder verwaiste Gruppenrichtlinien aufzuspüren. Die erste Version des Scripts sucht nach Gruppenrichtlinien die nicht mit einer OU verbunden sind, keine Sicherheitsfilterung besitzen oder alle Einstellungen der GPO deaktiviert wurden. Das Script werde ich zukünftig noch um weitere Funktionen erweitern und als kleines Tool veröffentlichen. Hier aber erst einmal ein Vorgeschmack.
Das Script gibt den Status “Disabled” aus, wenn alle Einstellungen der Richtlinie deaktiviert wurden, hier ein Beispiel:
Der Status “Not Linked” wird ausgegeben, wenn die Gruppenrichtlinie mit keiner Organisationseinheit (OU) verknüpft ist, wie hier zu sehen:
Wenn die Sicherheitsfilterung leer ist, wird der Status “No Permissions” angegeben:
Das Script erfordert das PowerShell Modul “GroupPolicy”, welches Bestandteil ab Windows Server 2008 R2 ist. Getestet habe ich das Script bisher auf Windows Server 2012 R2, Windows Server 2016 und remote via Windows 10.
So sieht die Ausgabe des Scripts in der PowerShell aus:
Und hier nun das eigentliche Script, welches gerne angepasst oder umgeschrieben werden kann:
$AllGPOs = Get-GPO -All $GPOCount = $AllGPOs.count write-host "" write-host "Found $GPOCount GPOs..." write-host "Analyzing, please wait..." $InvalidGPOs = @() #Disabled GPOs $DisabledGPOs = $AllGPOs | where {$_.GpoStatus -match "AllSettingsDisabled"} foreach ($DisabledGPO in $DisabledGPOs) { $GPOName = $DisabledGPO.Displayname $InvalidGPOs += new-object PSObject -property @{GPOName="$GPOName";State="Disabled"} #write-host "Not active: $GPOName" } #GPO Links / Permissions / Empty GPOs $EnabledGPOs = $AllGPOs | where {$_.GpoStatus -notmatch "AllSettingsDisabled"} foreach ($EnabledGPO in $EnabledGPOs) { $GPOName = $EnabledGPO.Displayname [XML]$GPOReport = Get-GPOReport $GPOName -ReportType XML $GPOLinks = $GPOReport.GPO.LinksTo $GPOApplyPermission = Get-GPPermission $GPOName -All | where {$_.Permission -match "GpoApply"} if ($GPOLinks) { $GPOLinkCount = $GPOLinks.Count $DisabledGPOLinksCount = ($GPOLinks | where {$_.enabled -eq "false"}).Count if ($GPOLinkCount -eq $DisabledGPOLinksCount) { #write-host "All Links disabled: $GPOName" $InvalidGPOs += new-object PSObject -property @{GPOName="$GPOName";State="All Links disabled"} } } if (!$GPOLinks) { $Sitelinked = Get-ADObject -LDAPFilter '(objectClass=site)' -SearchBase "CN=Sites,$((Get-ADRootDSE).configurationNamingContext)" -SearchScope OneLevel -Properties gPLink | Where-Object { $_.gpLink -match $EnabledGPO.Id} if (!$Sitelinked) { #write-host "Not linked: $GPOName" $InvalidGPOs += new-object -TypeName PSObject -Property @{GPOName="$GPOName";State='Not Linked'} } } if (!$GPOApplyPermission) { #write-host "No permissions: $GPOName" $InvalidGPOs += new-object PSObject -property @{GPOName="$GPOName";State="No Permissions"} } if (!$GPOReport.GPO.Computer.ExtensionData -and !$GPOReport.GPO.User.ExtensionData) { #write-host "Empty GPO: $GPOName" $InvalidGPOs += new-object PSObject -property @{GPOName="$GPOName";State="Empty"} } } $InvalidGPOs | sort state | ft GPOName,State $InvalidGPOCount = $InvalidGPOs.Count write-host "Found $InvalidGPOCount invalid GPOs" write-host "" #Optional: delete invalid GPOs foreach ($InvalidGPO in $InvalidGPOs) { Remove-GPO $InvalidGPO.GPOName }
Der untere Teil nach #Optional kann verwendet werden, um die gefundenen ungültigen GPOs zu löschen. Das Objekt “$InvalidGPOs” enthält alle gefunden ungültigen GPOs und lässt sich somit auch weiterverwenden.
Vielleicht nützt es ja jemanden.
Update 15.06.2017: Die aktualisierte Version des Scripts listet nun auch leere Gruppenrichtlinien (ohne Einstellungen) und GPOs auf bei denen alle Verknüpfungen zu OUs deaktiviert sind auf.
Update 01.07.2017: Die aktualisierte Version des Scripts berücksichtigt nun auch GPOs die an AD-Standorte verknüpft wurden. Danke an Torsten für den Hinweis.