Use PowerShell to Decipher GPO Version Information
A Group Policy is made up of a GPC (Group Policy Container) and a GPT (Group Policy Template).
The GPC resides in Active Directory. The GPT lives on the file system of a Domain Controller in SYSVOL.
We have to ensure that these two components are synchronised: AD replication looks after the GPC; DFSR looks after the GPT. Both the GPC and the GPC contain version information. This version information should match for both the GPC and GPT.
Time for Pictures
Here's the version as it appears in AD* on a GPC:
*look in DomainName/System/Policies
Here's the version as it appears in SYSVOL from GPT.ini:
Notice both the GPC and GPT have a version of 7995578.
Now, here's how the Group Policy Management Console (GPMC) interprets that information:
And we can arrive at the same with Get-GPO:
Hey, There!
In the GPMC and with Get-GPO, we have versioning for both user and computer settings... but how? We only have one version number, shared by the GPC and GPT...
The version we see can be thought of as split into two. The left half arriving at the user settings version and the right half representing the computer settings. Let's use PowerShell to illustrate this.
I take the version for the Default Domain Policy GPO from the VersionNumber attribute on the GPC.
$VersionNumber = (Get-ADObject -SearchBase "CN=Policies,CN=System,DC=halo,DC=net" -Filter {Name -eq "{31b2f340-016d-11d2-945f-00c04fb984f9}"} -Properties VersionNumber).VersionNumber
Now, time to have some fun!
$Hex = '{0:x8}' -f $VersionNumber
$Hex
$UserVn = $Hex.substring(0,4)
$CompVn = $Hex.substring(4)
[Convert]::ToInt64($UserVn,16)
[Convert]::ToInt64($CompVn,16)
Let's see what that generates...
We convert $VersionNumber to hexadecimal by using the -f format operator, ensuring we have eight characters.
Next, assign the first four characters to $UserVn and the next four to $CompVn.
Now use the [CONVERT] type accelerator and the ToInt64 static method to arrive at values that match the GPMC and Get-GPO values.
Sweet!
Comments
- Anonymous
September 22, 2017
Or just let Powershell do the conversion for you: Get-GPO -All | Export-Csv .\GPOInfo.csv -NoTypeInformationHowever, if you need to read your Get-GPO into a Variable and merge it with other GPO data before writing your output, User and Computer Version info and WMIFilter will be Blank if you simply refer to $Var.UserVersion or $Var.ComputerVersion, so you need to do the following which actually provides more data per GPO and where its linked.NOTE: This was done with Windows 2012 R2 with Powershell 5.x$Obj = Get-GPO "Some GPO"Reference the following to retrieve the variables without all the conversion and calculation work in your script:$Obj.Computer.Enabled$Obj.Computer.DSVersion$Obj.Computer.SysvolVersion$Obj.User.Enabled$Obj.User.DSVersion$Obj.User.SysvolVersion$Obj.WMIFilter.Name$Obj.WMIFilter.Description$Obj.WMIFilter.Path You can then build out your table with ADD-MEMBER and expand on the data as I did below to retrieve both the base GPO information and LinkTo information from the Get-GPOReport. Here it is in generic form for general usage:Import-Module active*,group*$MasterBldObj = @()$BldObj = @()$GetGPOInfo = Get-GPO -All | sort Nameforeach ($Obj in $GetGPOInfo) { $ObjName = $BldObj = $GPReportXML = $null $ObjName = $Obj.DisplayName $GPReportXML = [xml] (Get-GPO -Name $ObjName | Get-GPOReport -ReportType xml) $BldObj = New-Object psobject $BldObj = $GPReportXML.GPO.LinksTo $BldObj | Add-Member -Type NoteProperty -Name "DisplayName" -Value $Obj.DisplayName -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "DomainName" -Value $Obj.DomainName -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "Owner" -Value $Obj.Owner -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "ID" -Value $Obj.ID -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "GPOStatus" -Value $Obj.GPOStatus -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "Description" -Value $Obj.Description -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "CreationTime" -Value $Obj.CreationTime -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "ModificationTime" -Value $Obj.ModificationTime -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "UserEnabled" -Value $Obj.User.Enabled -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "UserADVersion" -Value $Obj.User.DSVersion -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "UserSysVolVersion" -Value $Obj.User.SysvolVersion -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "ComputerEnabled" -Value $Obj.Computer.Enabled -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "ComputerADVersion" -Value $Obj.Computer.DSVersion -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "ComputerSysVolVersion" -Value $Obj.Computer.SysvolVersion -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "WMIFilterName" -Value $Obj.WMIFilter.Name -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "WMIFilterDescription" -Value $Obj.WMIFilter.Description -ErrorAction SilentlyContinue $BldObj | Add-Member -Type NoteProperty -Name "WMIFilterPath" -Value $Obj.WMIFilter.Path -ErrorAction SilentlyContinue $MasterBldObj += $BldObj }$MasterBldObj | Export-Csv ".\GPO-InfoWithLinkTo.csv" -NoTypeInformationEnjoy!