Note: This script has been updated and posted here:


GPO Scavenger Hunt

Using the Get-GPOReport cmdlet from the Group Policy PowerShell module you can easily create a report of all your Group Policy Objects (GPOs) like this:


PS C:\> Import-Module GroupPolicy
PS C:\> Get-GPOReport -All -ReportType HTML -Path .\GPO.html


This is a great report, but it can be a bit overwhelming.  What if you want a simple spreadsheet listing of the same information?

Back around 2002 I wrote some code for this in VBScript.  You see, back then Group Policy Management Console (GPMC) had not been released yet.  At that time you created GPOs through AD Users and Computers (ADUC).  I was working with Windows 2000 Server designing OUs and GPOs for a large company’s Windows 2000 implementation.  I needed a report to show me where all of these policies were linked, and I also needed to know where inheritance was blocked and where policies were set to “No Override” (now called “Enforced”).  After some recent conversations with peers I decided to rewrite this script in PowerShell.

Understanding GPOs in Active Directory

First off, technically speaking Group Policy is not a feature of Active Directory (AD).  However, so much of the infrastructure rides on AD that most people associate the two.  If you need some help understanding GPOs start here:  Everything you need to get started with Group Policy.

In GPO terms, domains, OUs, and sites are called Scopes of Management (SOMs).  They have an attribute called gPLink that lists all of the GPOs applied to the object.  The gPLink attribute contains a list of GPO distinguished names and a gPLinkOptions value for each one.  This numeric value is a bit switch flagging LinkEnabled status and Enforced status.  SOMs have an attribute call gPOptions which specifies whether Block Inheritance is enabled.  To understand these in more detail you can explore the following links:

The gPLink attribute is a string concatenation that looks something like this:

[LDAP://cn={7BE35F55-E3DF-4D1C-8C3A-38F81F451D86},cn=policies, cn=system,DC=wingtiptoys,DC=local;2][LDAP://cn={046584E4-F1CD-457E-8366-F48B7492FBA2}, cn=policies,cn=system,DC=wingtiptoys,DC=local;0] [LDAP://cn={12845926-AE1B-49C4-A33A-756FF72DCC6B},cn=policies, cn=system,DC=wingtiptoys,DC=local;1]

As you can see, each GPO distinguished name is enclosed with square brackets, and there is a numeric digit following it as described above.  The important point is that GPOs are listed in this string in order of precedence.  In the GPMC GUI you will see multiple linked policies listed top to bottom, 1 through x, with lower numbers winning over higher numbers.  This is just like Stratego.  The #1 policy (Stratego’s marshall) wins over all the others.  Lower numbers always win.


Understanding how policies tie into Active Directory, now you can see that we need a couple targeted LDAP queries to get all of the gPLink and gPOptions attributes from the SOMs.  Then we parse out the attributes and put them into a report.  I am over-simplifying it just a bit, but here is a small portion of the script showing the queries:


# Empty array to hold all possible GPO links            
$gPLinks = @()            
# GPOs linked to the root of the domain            
#  !!! Get-ADDomain does not return the gPLink attribute            
$gPLinks += Get-ADObject -Identity (Get-ADDomain).distinguishedName `
 -Properties name, distinguishedName, gPLink, gPOptions            
# GPOs linked to OUs            
#  !!! Get-GPO does not return the gPLink attribute            
$gPLinks += Get-ADOrganizationalUnit -Filter * -Properties name, `
 distinguishedName, gPLink, gPOptions            
# GPOs linked to sites            
$gPLinks += Get-ADObject -LDAPFilter '(objectClass=site)' `
 -SearchBase "CN=Sites,$((Get-ADRootDSE).configurationNamingContext)" `
 -SearchScope OneLevel -Properties name, distinguishedName, gPLink, gPOptions            


Notice in the script comments that Get-ADDomain and Get-GPO do not return the gPLink attribute.  We have to specifically query for this attribute using other cmdlets.  Also notice that I am not filtering out SOMs without a gPLink attribute.  I want to collect all OUs and sites to round out the report, not just the ones with policies linked.

The output is a CSV file (gPLink_Report.csv) listing all of the linked policies, their locations, and link configurations.  The report contains the following columns:

This script has the following prerequisites:

Unlike Get-GPOReport this script does NOT include any of the following other related information:

With this handy CSV spreadsheet you can easily get an overview of your policies, where they are blocked, and where they are enforced.  Perhaps the helpdesk could use a copy of the script and report when they are troubleshooting group policy calls (in addition to RSOP, of course).

Download the entire script today.

Group Policy Health Check (GPOHC)

As a Microsoft Premier Field Engineer I am part of a global team with many specialties.  Some of my peers are true group policy experts.  You can have one of them visit your company, teach you the ins and outs of group policy, and help optimize your GPOs.  They have many other tricks up their sleeve beyond today’s reporting script.  This service is called the Group Policy Health Check (GPOHC).  Contact me for more information if you would like one of these at your company.