Before we can really dive into modifying GPOs, we need to try and understand some of the intricacies of how they’re updated normally in GPMC and AD. Because believe me, it aint as simple as it appears.
When you first create and name a GPO and then look at it the Details tab, you’ll see it has these User and Computer version fields, with # (AD), # (SYSVOL).
For every GPO, there is also a corresponding path on disk (which I believe is called the Group Policy Template) at C:\Windows\SYSVOL\domain\Policies\<guid>. For this GPO, it would be C:\Windows\SYSVOL\domain\Policies\{F3003ADC-17E3-4FBE-A11E-6A41779ADD6E}. From a domain member, you can also access SYSVOL over its network share e.g. \\testlab.local\SYSVOL\testlab.local\Policies\{F3003ADC-17E3-4FBE-A11E-6A41779ADD6E}.
Inside the GPT, you have a Machine and User directory and a GPT.INI file.
PS > ls "\\testlab.local\SYSVOL\testlab.local\Policies\{F3003ADC-17E3-4FBE-A11E-6A41779ADD6E}"
Directory: \\testlab.local\SYSVOL\testlab.local\Policies\{F3003ADC-17E3-4FBE-A11E-6A41779ADD6E}
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 13/01/2019 11:13 Machine
d----- 13/01/2019 11:13 User
-a---- 13/01/2019 11:13 59 GPT.INI
No points for guessing that Computer policies are dropped into Machine and User policies into User.
GPT.INI is a really simple file that contains:
PS > cat "\\testlab.local\SYSVOL\testlab.local\Policies\{F3003ADC-17E3-4FBE-A11E-6A41779ADD6E}\GPT.INI"
[General]
Version=0
displayName=New Group Policy Object
Note that the
displayNameparameter never changes¯\_(ツ)_/¯.
If we make some changes to the GPO and refresh GPMC, we can see that the AD and SYSVOL numbers for Computer have been pushed up.
They seem to increase for every individual change that happens, but since GPMC does all sorts in the background that you can’t see unless you’re monitoring with something like Process Monitor, seemingly small changes can result in a large increase.
The AD and SYSVOL values are stored in different places, but are pretty important to understand.
SYSVOL is stored in that GPT.INI file. If we read it again, we’ll see that the version has changed.
PS > cat "\\testlab.local\SYSVOL\testlab.local\Policies\{F3003ADC-17E3-4FBE-A11E-6A41779ADD6E}\GPT.INI"
[General]
Version=12
displayName=New Group Policy Object
It gets a bit more complicated if you have a GPO that applies both Computer and User policies, since the number format of GPT.INI changes.
PS > cat "\\testlab.local\SYSVOL\testlab.local\Policies\{F3003ADC-17E3-4FBE-A11E-6A41779ADD6E}\GPT.INI"
[General]
Version=65548
displayName=New Group Policy Object
version = [user verion][computer version] where each value is 16 bits.
To “translate”, we first convert the decimal to hex. With a calculator in scientific mode, this comes out to be 1000C. But to make up for the fact these are 16 bit, it’s actually 0001000C, because a calculator won’t display the leading zeros.
So 0001 is 1 and 000C is 12.
The AD number is stored as an attribute on the Group Policy object in AD. You can query it with PowerView like:
PS > Get-DomainGPO -Identity "Test GPO" -Properties VersionNumber
versionnumber
-------------
65548
And it uses exactly the same format.
When you modify a GPO in GPMC it will update the corresponding files in SYSVOL, update the value in GPT.INI and then update its versionnumber attribute in AD.
To modify the GPO without GPMC, you have to go into SYSVOL and modify the files manually. E.g. if we wanted to deploy some new local admins using Restricted Groups, we’d have to modify C:\Windows\SYSVOL\domain\Policies\{F3003ADC-17E3-4FBE-A11E-6A41779ADD6E}\Machine\Microsoft\Windows NT\SecEdit\GptTmpl.inf.
The limitation of updating the file without incrementing the AD or SYSVOL version numbers is that:
gpupdate /force)To enable all clients to pull the changes as part of their regular group policy update schedule, you must increment both AD and SYSVOL version numbers manually.
GPT.INI is straight forward as it’s just a text file. The versionnumber attribute can be updated with PowerView:
PS > Get-DomainGPO -Identity "Test GPO" | Set-DomainObject -Set @{'versionnumber'='1337'}
PS > Get-DomainGPO -Identity "Test GPO" -Properties VersionNumber
versionnumber
-------------
1337
You must always keep the two values identical, otherwise you will cause AD / SYSVOL Version Mismatch errors.