Spelunking Group Policy


Windows Server 2008 R2, with PowerShell 2.0 and the GroupPolicy management module allows for powerful administration of Active Directory Domain Services (AD DS) based Group Policy. A question came up during a recent session of the Group Policy course, and then again the following week during a session of a PowerShell course. The distilled-down question is essentially: Scripting the GPMC is good for linking GPOs and other such activities, and the W2K8R2 cmdlets let us examine values if we know the particular registry value we’re looking for, but how can we search, peruse, or report on the settings in one or more GPOs without running either a GPO report of resultant set of policy (RSoP) report?

Have you ever wanted to find what registry values a group policy object (GPO) contains? Indeed, you can get a report of one GPO using the Get-GPOReport, or for all GPOs in a domain by adding the -All parameter to that cmdlet, yet in either case, the output is either in HTML or XML format. There is also a wonderful Get-GPResultantSetOfPolicy cmdlet which also gets the effective policy settings, but again in either HTML or XML format. Sure, a text search or parse of the HTML gives some decent results, and reading the XML output is far better, especially with the built-in XML tools in PowerShell, however there is actually an even easier to work with and more powerful alternative.

Consider the following functions, which use the Get-GPRegistryValue cmdlet to do the actual work.

trap [ParameterArgumentValidationException] {
# placeholder for processing bad key errors

if( @(get-module GroupPolicy).count -eq 0 ){
import-module GroupPolicy

function global:Get-GPRegistrySubKey( $gpo, $key ){
$val = @(Get-GPRegistryValue $gpo -Key $key )
$val | %{
if( $_. FullKeyPath -ne $key ){
Get-GPRegistrySubKey $gpo $_. FullKeyPath

function global:Get-GPRegistryKey( $gpo, = “Default Domain Policy”, $key = “HKLMSoftware” ){
Get-GPRegistrySubKey $gpo $key | FT ValueName,PolicyState,HasValue,Type,Path,Value -auto

That’s it. The trap handler and conditional Import-Module block may be optional, depending on the environment in which you’re using the functions. The first function, Get-GPRegistrySubKey, does then actual work, and the second one, Get-GPRegistryKey, formats the results to be more dense and human readable. With these functions defined in your profile or other appropriate script, dealing with the output is more convenient that using the parsed XML output from Get-GPOReport or Get-GPResultantSetOfPolicy.

In its simplest form, this Get-GPRegistryKey function can be called with no parameters, which will assume the default GPO of the Default Domain Policy, and also assumes the registry key HKLMSoftware (the Policies, Computer Configuration portion of the GPO) as the base for the search/report. This function in turn simply calls the other function, Get-GPRegistrySubKey, with these same values, and then formats the output in table form. Get-GPRegistrySubKey fetches all of the values under that key by calling the Get-GPRegistryValue cmdlet with just the GPO name, this base key, and no specific value. Although the variable $val could be optimized out by rewriting the script to send the Get-GPRegistryValue results directly to the ForEach-Object cmdlet (used with its % alias here) loop, this intermediate step of storing the results in a variable and then passing those results down the pipeline to ForEach-Object was retained for troubleshooting purposes. Within the body of the loop through each of the results, the subkey is emitted and then if the subkey is not the same as the key, then Get-GPRegistrySubKey calls itself recursively in order to traverse down to the subkeys and values.

Specific values for the GPO name and registry key could be supplied to these functions for more focused results. Additionally, a number of GPOs could be reported on by using a technique such as:

get-gpo -all | %{
Get-GPRegistryKey $_.displayName “HKLMSoftware”
Get-GPRegistryKey $_.displayName “HKCUSoftware”

The results of Get-GPRegistryKey or this sort of loop which invokes it could be used with filtering mechanisms such as Where-Object. These fairly simple functions not only provide a straightforward way to enumerate and list the settings within a GPO, but also can serve as an example of a more elaborate searching and reporting tools and automation for bringing sanity to GPO management.

Leave a Reply

Your email address will not be published. Required fields are marked *