none
Documenting GPO's RRS feed

  • Question

  • I am trying to compare GPO settings, and have taken a look at the script Compare-GPOs.ps1 submitted by Ed Wilson ( https://gallery.technet.microsoft.com/scriptcenter/18dea308-4faf-44bf-9e1c-e83d47edb866 )

    However, the syntax on the script is not working.  Specifically, the command "$xml1.gpo.Computer.extensiondata.extension.ChildNodes" returns no data. 

    It appears that .ChildNodes is not a valid method for .Extension.   I am running Windows 2008 R2 Domain Controllers with a win2008R2 functional level.

    The following commands do return data.  If I type

    "$xml1.gpo.Computer.extensiondata | foreach-Object {$_.name}", I get a list of extensions, and if I type "$xml1.gpo.Computer.extensiondata | foreach-Object {$_.extension}", I then get the extensions. 

    I am wondering what has changed and if there is an update to Ed Wilson's excellent script that does work.

    Also, I am trying to figure out the syntax to script the extensions, to achieve what I think Ed's original script did when it was written.  It should enumerate the extensions and return the properties within.  

    Thursday, August 6, 2015 6:15 PM

Answers

  • I have an AHAH moment.

    I tested this on another domain and found that indeed it works correctly on the other domain. 

    The properties/Methods on the other domain contain a ".ChildNodes" for the object.  ($xml1.GPO.Computer.ExtensionData.ChildNodes)

    A tab-to-complete confirms this.  

    They do not exist in the production domain that I am trying to document.   Argh!!!


    Pat Spencer MCSE 2012

    It is not that they don't exist.  It is that the GPO does not have any entries in that section.  This is also not a reliable way to compare GPOs.  There are sections that are provider dependent and have to be  treated differently.

    Ed was really only trying to demonstrate how you can access GPO object's XML and compare it.  It is minimally useful.

    The GPO schema on WS2010R2 has newer namespaces and will not work exactly the same.  You can extend the script to compare other sections and select the data to compare in meaningful ways.  Use this as an example of how to build other comparators.


    \_(ツ)_/

    • Marked as answer by Pat Spencer Friday, August 7, 2015 4:53 AM
    Thursday, August 6, 2015 10:15 PM

All replies

  • Works fine for me.


    \_(ツ)_/

    Thursday, August 6, 2015 7:30 PM
  • Interesting.  So now my challenge is to determine what it causing it to not work for me.

    Specifically, I am typing the following three commands:

    (get-gpo -name "Standard Srv 2012").GenerateReportToFile("xml","c:\fso\sample.xml")

    [xml]$xml1 = Get-Content -path "C:\fso\sample.xml"

    $xml1.gpo.Computer.extensiondata.extenstion.ChildNodes

    The results of the above are blank.  No data.  No object returned.

    however, if I now type "$xml1.gpo.Computer.extensiondata", I see a list of 5 extensions, with names like "Security", "Windows Firewall", etc.

    If I now type "$xml1.gpo.Computer.extensiondata | %{$_.extension}" I get a list of 5 objects, with first lines of each "q1","q2", etc. 

    I have tried this both on my management workstation (Win7) as well as on a DC (2008R2).


    Pat Spencer MCSE 2012

    Thursday, August 6, 2015 8:44 PM
  • You said you were using the script.  What is all oof that?

    Put the scrip in a file and run it like this:

    PS >.\Compare-GPO.ps1 -computer -gponame 'time policy,printer policy' -folder c:\temp -domain testnet.local -server DC01

    It just works.  No need to do anything else.


    \_(ツ)_/

    Thursday, August 6, 2015 8:54 PM
  • Thanks JRV, but if I run the script exactly as you suggest, it is only giving me the result:

    "Computer GPO C:\fso\Standard srv 2012.xml not set" and "Computer GPO C:\fso\Standard srv 2012 - web.xml not set".

    If I debug the script, it is the line that tests if $regPolicyComputerNodes1 and 2 is set.  ( "If ($regPolicyComputerNodes1) {...} else {"... not set"} )

    Obviously neither Nodes1 or Nodes2 are set.   The lines that I typed earlier are my attempt to debug the script even further.  

    What version of AD, and GroupPolicy module are you running?  As I said, I am on Win7 and am runnign RSAT 7 and Windows Server 2008 R2.


    Pat Spencer MCSE 2012

    Thursday, August 6, 2015 9:05 PM
  • You are not generating any XML files.  Perhaps these GPOs do not exits.

    Get-Gpo -all |select DisplayName

    Use displayname to find the GPO.


    \_(ツ)_/


    • Edited by jrv Thursday, August 6, 2015 9:17 PM
    Thursday, August 6, 2015 9:12 PM
  • This should work anywhere. These two policies must exist.   Change the DC name and domain.  Use the file exactly as copied from the gallery.

    $gponames='Default Domain Policy,Default Domain Controllers Policy'

    PS >.\Compare-GPO.ps1 -computer -gponame $gponames -folder c:\temp -domain testnet.local -server DC01


    \_(ツ)_/

    Thursday, August 6, 2015 9:19 PM
  • I have an AHAH moment.

    I tested this on another domain and found that indeed it works correctly on the other domain. 

    The properties/Methods on the other domain contain a ".ChildNodes" for the object.  ($xml1.GPO.Computer.ExtensionData.ChildNodes)

    A tab-to-complete confirms this.  

    They do not exist in the production domain that I am trying to document.   Argh!!!


    Pat Spencer MCSE 2012

    Thursday, August 6, 2015 9:28 PM
  • A lot of very subtle programming errors.  Here is a modernized and fixed version.  I think I got most of the errors.

    <#
    	Compare-GPO.ps1
    	ed wilson, msft, 7/13/2010
    
    	HSG-07-15-2010 
    	To test In current domain:
    	.\Compare-GPO.ps1 -Verbose
    #>
    #requires -version 2.0
    #requires -modules GroupPolicy
    
    Param(
    	[Parameter()]
    	[string]$domain=[System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain().Name,
    	[string]$server=$env:LOGONSERVER.Replace('\\',''),
    	[String[]]$gponame=@('Default Domain Policy','Default Domain Controllers Policy'),
    	[string]$folder=$pwd,
    	[switch]$user,
    	[switch]$computer
    )
    
    if(-not ($user -or $computer)){$computer=$true;Write-Warning 'Using Computer policy'}
    
    ForEach($gpo in $gpoName){
    	$path = Join-Path -Path $folder -ChildPath "$gpo.xml"
    	Write-Verbose $path
    	(Get-GPO -Name $gpo -Domain $domain -Server $server).GenerateReportToFile("xml",$path)
    	[array]$gpoReports+=$path
    }
    
    [xml]$xml1 = Get-Content -Path $gpoReports[0]
    [xml]$xml2 = Get-Content -Path $gpoReports[1]
    $regpolicyComputerNodes1 = $xml1.gpo.Computer.extensiondata.extension.ChildNodes | Select-Object name, state
    $regpolicyComputerNodes2 = $xml2.gpo.Computer.extensiondata.extension.ChildNodes | Select-Object name, state
    
    $regpolicyUserNodes1 = $xml1.gpo.User.extensiondata.extension.ChildNodes | Select-Object name, state
    $regpolicyUserNodes2 = $xml2.gpo.User.extensiondata.extension.ChildNodes | Select-Object name, state
    
    if($computer){
    	Try {
    		Write-Verbose "Comparing Computer GPO's $($gpoReports[0]) to $($gpoReports[1])"
      		Compare-Object -PassThru -ReferenceObject $regpolicyComputerNodes1 -DifferenceObject $regpolicyComputerNodes2 -IncludeEqual -property name
      	}
     	Catch{
       		if($regPolicyComputerNodes1){
          		Write-Error "Computer GPO $($gpoReports[0]) settings"
          		$regPolicyComputerNodes1
    		}else{
    			Write-Error "Computer GPO $($gpoReports[0]) not set" 
    		}
       
       		if($regPolicyComputerNodes2) {
          		"Computer GPO $($gpoReports[1]) settings `r`f"
          		$regPolicyComputerNodes2
         	}else{
         		"Computer GPO $($gpoReports[1]) not set"
         	}
      	}
    }
    
    
    
    if($user){
    
    	Try {
    		"Comparing User GPO's $($gpoReports[0]) to $($gpoReports[1])`r`n"
    		Compare-Object -PassThru -ReferenceObject $regpolicyUserNodes1 -DifferenceObject $regpolicyUserNodes2  -SyncWindow 5 -IncludeEqual -property name
    	}
    	Catch{
    	
    		if($regPolicyUserNodes1){
    	    	"User GPO $($gpoReports[0]) settings"
    	      	$regPolicyUserNodes1
    		}else{
    	     	"User GPO $($gpoReports[0]) not set"
    		}
    		
    	   	if($regPolicyUserNodes2) {
    	    	"User GPO $($gpoReports[1]) settings"
    	      	$regPolicyUserNodes2
    		}else{
    	    	"User GPO $($gpoReports[1]) not set"
    	    }
    	}
    }
    

    Use only this to test with all defaults.

    .\Compare-GPO.ps1 -Verbose


    \_(ツ)_/


    • Edited by jrv Thursday, August 6, 2015 10:07 PM
    Thursday, August 6, 2015 10:05 PM
  • I have an AHAH moment.

    I tested this on another domain and found that indeed it works correctly on the other domain. 

    The properties/Methods on the other domain contain a ".ChildNodes" for the object.  ($xml1.GPO.Computer.ExtensionData.ChildNodes)

    A tab-to-complete confirms this.  

    They do not exist in the production domain that I am trying to document.   Argh!!!


    Pat Spencer MCSE 2012

    It is not that they don't exist.  It is that the GPO does not have any entries in that section.  This is also not a reliable way to compare GPOs.  There are sections that are provider dependent and have to be  treated differently.

    Ed was really only trying to demonstrate how you can access GPO object's XML and compare it.  It is minimally useful.

    The GPO schema on WS2010R2 has newer namespaces and will not work exactly the same.  You can extend the script to compare other sections and select the data to compare in meaningful ways.  Use this as an example of how to build other comparators.


    \_(ツ)_/

    • Marked as answer by Pat Spencer Friday, August 7, 2015 4:53 AM
    Thursday, August 6, 2015 10:15 PM
  • I see.   As a followup, and to confirm what you are saying, I finally landed on the root cause of my differences between environments.  Turns out that it is the specific GPO's.  More accurately, the content of the GPO.

    In my comparison, I found that Ed's syntax ($xml1.GPO.Computer.ExtensionData.Extension.ChildNodes) only works if you only have one extension.  If the GPO has more content, and contains more than one extension, then it fails.

    What I am looking for is to have a script that programmatically adapts and prints off a grid of all of the settings and their content.  The purpose being to display (or print) the settings that are the same between two GPO's,and also display the settings that are different.

    There is a commercial app that does just that, but I though my needs could be served with PowerShell.

    The app I found is called GPO Compare from sdmsoftware.

    Thanks for your feedback and help.


    Pat Spencer MCSE 2012

    Friday, August 7, 2015 4:53 AM