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 displayName parameter 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:

  1. Clients will not automatically pull the changes because they think they already have the latest configuration (unless you have code exec on a box and can issue a gpupdate /force)
  2. The changes will not be replicated across domain controllers

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.