PS without BS: Some useful GPO cleanup scripts

Just a quick blog with a lot of punch to it: Some easy and great ways to clean up Group Policy.

What are some of the reasons for this? Well...

  • Your GPO infrastructure may be out of control.
  • You may have forgotten what policies are linked
  • You may have policies that are enforced without settings
  • You may have policies that are completely empty and possibly linked.

Cleaning Group Policy, you will be able to start the healing process of removing old and unused scripts. In addition, you'll be as potentially helping clients perform Group Policy application a little faster by not processing what wasn't needed.

Keep in mind that as always, these scripts are provided to you as part of a project or something I am working on for me. Using these scripts, you do assume all responsibility for what happens as a result. It's always to look at what is detected before deleting things as you may actually delete something neglegently (as not confirming deletions is not considered an accident). Authoritative restores are no fun. :)

But, on to the scripts...

Block 1: Detecting Unlinked GPOs
Unlinked GPOs are just simply policies that aren't applied to any OU or site. These policies aren't

 
$BackupPath="C:\temp\GPOBackups"

Get-GPO -All | Sort-Object displayname | 
Where-Object { If ( $_ | Get-GPOReport -ReportType XML | 
Select-String -NotMatch "<LinksTo>" )

{
Backup-GPO -name $_.DisplayName -path $BackupPath
$_.DisplayName | Out-File $BackupPath\unlinked.txt -Append
#Outputting the results to the screen
$_.Displayname | Select-Object DisplayName
#Uncomment this when you're ready to delete all the ones the script finds..
# $_.Displayname | remove-gpo
}
}

Block 2: Detecting GPOs that have either no computer or user settings
These policies generally are meant for just computer or user settings. This script will disable the empty settings (for example, if a GPO has only computer setttings, it will disable user settings). This is important as it does speed up performance by not having to process empty policies.

 
Import-Module GroupPolicy
$GPOs = Get-GPO -All
foreach ($GPO in $GPOs)
{
if (($GPO.Computer.DSVersion -eq 0) -and ($GPO.GpoStatus -ne "ComputerSettingsDisabled")) {
    write-host $GPO.DisplayName has no computer settings and not disabled.  Disabling...
    $GPO.GpoStatus="ComputerSettingsDisabled"
    }

if (($GPO.User.DSVersion -eq 0) -and ($GPO.GpoStatus -ne "UserSettingsDisabled")) {
    write-host $GPO.DisplayName has no user settings and not disabled.  Disabling...
    $GPO.GpoStatus="UserSettingsDisabled"
    }
}

Block 3: Delete Empty GPOs
This script will look for GPOs which have no settings at all and delete them.

 
Import-Module GroupPolicy
$GPOs = Get-GPO -All
foreach ($GPO in $GPOs)
{
if (($GPO.Computer.DSVersion -eq 0) -and ($GPO.User.DSVersion -eq 0)) {
    write-host $GPO.DisplayName is an empty GPO.
    $GPO.DisplayName | Remove-GPO
    }
}

Happy Scripting!

— Easy link to my blog: https://aka.ms/leesteve
If you like my blogs, please share it on social media and/or leave a comment.

Comments

  • Anonymous
    March 09, 2018
    To add a bit useful stuff:#let's find linked GPOs that do not have a SOM (so basically the GPO does nothing)import-module grouppolicy function IsNotLinked($xmldata){ If ($xmldata.GPO.LinksTo -eq $null) { Return $true } Return $false } $unlinkedGPOs = @() Get-GPO -All | ForEach { $gpo = $_ ; $_ | Get-GPOReport -ReportType xml | ForEach { If(IsNotLinked([xml]$_)){$unlinkedGPOs += $gpo} }} If ($unlinkedGPOs.Count -eq 0) { "No Unlinked GPO's Found" } Else{ $unlinkedGPOs | Select DisplayName,ID | Sort-Object -Property Displayname "Found $(($unlinkedGPOs).count) GPOs with SOM but no active links to OUs"}
    • Anonymous
      March 09, 2018
      @MrBisich: Thanks for the contribution! Block 3 sort of does this, but doesn't tell if it's linked or not linked. But, thanks for a different take on this.