At my new job, I needed to do some GPO cleanup. There are a LOT of them, and many are not even linked to anything. I need to remove them, but didn’t want to go through them one-by-one to do it. PowerShell to the rescue!
For the impatient, here is the quick script to show the un-linked GPOs. The explanation of how to get there is below.
Import-Module grouppolicy
$allGPOs = Get-GPO -All | sort DisplayName
ForEach ($gpo in $allGPOs) {
$xml = [xml](Get-GPOReport $gpo.Id xml)
If (!$xml.GPO.LinksTo) {
$gpo.DisplayName
}
}
First off, load the Group Policy module with Import-Module grouppolicy, and find what commands are available with Get-Command -Module grouppolicy:
CommandType Name Definition ----------- ---- ---------- Cmdlet Backup-GPO Backup-GPO -Guid -Path [-Comment... Cmdlet Copy-GPO Copy-GPO -SourceGuid -TargetName ... Cmdlet Get-GPInheritance Get-GPInheritance [-Target] [-Domain <S... Cmdlet Get-GPO Get-GPO [-Guid] [[-Domain] ] [[-S... Cmdlet Get-GPOReport Get-GPOReport [-Guid] [-ReportType] <Repo... Cmdlet Get-GPPermissions Get-GPPermissions -Guid [-TargetName <Str... Cmdlet Get-GPPrefRegistryValue Get-GPPrefRegistryValue -Guid -Context <G... Cmdlet Get-GPRegistryValue Get-GPRegistryValue -Guid -Key [... Cmdlet Get-GPResultantSetOfPolicy Get-GPResultantSetOfPolicy [-Computer ] ... Cmdlet Get-GPStarterGPO Get-GPStarterGPO -Guid [-Domain ]... Cmdlet Import-GPO Import-GPO -BackupId -Path [-Tar... Cmdlet New-GPLink New-GPLink -Guid -Target [-LinkE... Cmdlet New-GPO New-GPO [-Name] [-Comment ] [-D... Cmdlet New-GPStarterGPO New-GPStarterGPO [-Name] [-Comment <Str... Cmdlet Remove-GPLink Remove-GPLink -Guid -Target [-Do... Cmdlet Remove-GPO Remove-GPO -Guid [-Domain ] [-Ser... Cmdlet Remove-GPPrefRegistryValue Remove-GPPrefRegistryValue [[-Server] ] ... Cmdlet Remove-GPRegistryValue Remove-GPRegistryValue [-Guid] [-Key] <St... Cmdlet Rename-GPO Rename-GPO -Guid -TargetName [-D... Cmdlet Restore-GPO Restore-GPO -BackupId -Path [-Do... Cmdlet Set-GPInheritance Set-GPInheritance [-Target] -IsBlocked ... Cmdlet Set-GPLink Set-GPLink -Guid -Target [-LinkE... Cmdlet Set-GPPermissions Set-GPPermissions -Guid -PermissionLevel ... Cmdlet Set-GPPrefRegistryValue Set-GPPrefRegistryValue -Guid -Context <G... Cmdlet Set-GPRegistryValue Set-GPRegistryValue -Guid -Key [...
So, I apparently can create a new Link, or set or remove one, but not simply get one. Nice. And Get-GPO doesn’t include links either:
DisplayName : test DomainName : mydomain.com Owner : MYDOMAIN\Domain Admins Id : 1be29c7a-6cdb-48f8-aaef-18db7ab79b25 GpoStatus : AllSettingsEnabled Description : CreationTime : 9/16/2004 11:10:04 AM ModificationTime : 1/25/2011 5:39:44 PM UserVersion : AD Version: 6, SysVol Version: 6 ComputerVersion : AD Version: 2, SysVol Version: 2 WmiFilter :
So I need more detail. Get-GPOReport has lots of detail, but it's in HTML or XML format. Since PowerShell can read XML, I went that way:
PS> $test = [xml](Get-GPOReport test xml) PS> $test xml GPO --- --- version="1.0" encoding="utf-16" GPO PS> $test.GPO xsi : http://www.w3.org/2001/XMLSchema-instance xsd : http://www.w3.org/2001/XMLSchema xmlns : http://www.microsoft.com/GroupPolicy/Settings Identifier : Identifier Name : test IncludeComments : true CreatedTime : 2004-09-16T15:10:04 ModifiedTime : 2011-01-25T21:39:45 ReadTime : 2011-04-25T14:43:30.3150573Z SecurityDescriptor : SecurityDescriptor FilterDataAvailable : true Computer : Computer User : User LinksTo : LinksTo PS> $test.GPO.LinksTo SOMName SOMPath Enabled NoOverride ------- ------- ------- ---------- TestLab mydomain.com/SomeOU/... true false
So, all I need to do is find the GPOs where the XML doesn’t have a GPO.LinksTo property, or said property is blank.
Import-Module grouppolicy
$allGPOs = Get-GPO -All | sort DisplayName
ForEach ($gpo in $allGPOs) {
$xml = [xml](Get-GPOReport $gpo.Id xml)
If (!$xml.GPO.LinksTo) {
$gpo.DisplayName
}
}
Bam.
Edit 4/25/2011 3:22 PM:
I realized I can also search for the GPOs which are linked, but have no settings at all:
$allGPOs = Get-GPO -All | sort DisplayName
ForEach ($gpo in $allGPOs) {
$xml = [xml](Get-GPOReport $gpo.Id xml)
If ($xml.GPO.LinksTo) {
If (!$xml.GPO.Computer.ExtensionData -and !$xml.GPO.User.ExtensionData) {
$gpo.DisplayName
}
}
}