Ah, Group Policy objects. Ever since their introduction in Windows 2000, most companies have been gradually building a larger and larger library of GPOs, each applying a larger and larger number of settings to users and computers. Today, we rely on them to configure security-sensitive settings, to mapping drives and printers, to configuring how software applications look and behave.
Unfortunately, the native tools for GPO administration aren’t full-featured, meaning that a robust GPO-using environment can sometimes have its work cut out for it.
Who Changed That GPO?!?!?!
Probably one of the toughest things to accomplish with the native tools is a comparison of a GPO. There are a variety of situations in which you might need to do so:
- If you’re troubleshooting a problem, you might want to compare a current version of a GPO with a backup copy of that same GPO, so that you can see what settings changed.
- In a merger or acquisition scenario, you might want to compare different GPOs – perhaps even across domains or forests – so that you can start consolidating them.
- In a purely internal consolidation effort, you might want to compare different GPOs to see where they differ, so that you can start building fewer GPOs that implement all the functionality of the existing set.
The native graphical management console – the Group Policy Management Console, or GPMC, to be specific – doesn’t include comparison capabilities. This is where I’d normally turn to PowerShell, and Windows Server 2008 R2 (and Windows 7) offer a GroupPolicy module. In it, the Get-GPRegistryValue cmdlet would seem to offer a technique. If it was capable of getting every value (setting) from a GPO, then I could use it to load two different GPOs and compare them using PowerShell’s Compare-Object cmdlet. Sadly, Get-GPRegistryValue can’t recursively read every setting out of a GPO. For example, it could do this:
Get-GPRegistryValue –Name 'CorpGPO' –Key HKCU\Software
That should get every setting configured under HKEY_CURRENT_USER\SOFTWARE, but in fact won’t work. Time to dig a little deeper.
The GroupPolicy module also includes a Get-GPOReport cmdlet, which looks promising. It can generate results in both XML and HTML; while HTML is easier to read, it won’t be so useful for making an automated comparison possible. We’ll focus on XML instead.
Get-GPOReport –name 'CorpGPO' –ReportType XML
That certainly displays the information we’re after – a whole bunch of it, in fact. Let’s try using it to compare two GPOs:
PS C:\> Diff (Get-GPOReport -Name 'CorpGPO' -ReportType XML) (Get-GPOReport -Name 'Default Domain Policy' -ReportType XML)
Figure 2 the Compare-GPO PowerShell Script
Unfortunately, the output consists of the entire XML document – the report XML just isn’t designed for a straightforward comparison like this. Fortunately, Microsoft’s Scripting Guys offer a Compare-GPO script at https://gallery.technet.microsoft.com/ScriptCenter/18dea308-4faf-44bf-9e1c-e83d47edb866/. It does the work of comparing that complex XML produced by Get-GPOReport. The output looks something like Figure 3.
This is indicating that both compared GPOs set a particular setting – in this case, AuditLogRetentionPeriod and RetentionDays. This still isn’t ideal output. For example, while both GPOs configured both of those settings, they each set them to different values, which isn’t shown here. Also, the report doesn’t indicate which audit log’s retention period was set. Browsing through the GPO, I can see that it’s the Security log, but it’s a lot of manual effort to discover that fact.
There’s also the problem of getting to the GPOs in the first place. The script I used above assumes that both GPOs you want to compare live in the same domain; that won’t always be the case. The GPOs also have to be loaded into a domain controller, although they needn’t be linked to anything (meaning they could just be sitting there, in active). If you want to compare a backed-up GPO to an active version of the same one, it might be tricky to get them both loaded into a domain controller at the same time. Now, you could manually run the XML-generation command for each GPO:
(Get-GPO -Name $gpo -Domain $domain -Server $server).GenerateReportToFile("xml",$path)
And then use the script’s Compare-GPOAsXML function manually. That would let you pull XML reports from any GPO in any domain, and then bring the two XML files together to compare them directly. Again… it starts to add complexity to the situation.
Other Comparison Options
Comparing GPOs is actually a pretty common need, one that – as you’ve seen – isn’t well-met by the native Windows tools. Anytime you see “common need” compared with “not done well by the native tools,” you can bet that someone outside Microsoft has taken a stab at solving the problem. That’s certainly the case for GPO comparison: Punch “compare GPO tool” into your favorite search engine and you should generate a few useful hits.
As you’re looking at such tools, there are a few things you’ll want to keep in mind. After all, if you’re going to be bringing in outside software, you might as well choose a tool that is most likely to meet all of your needs. Here’s my “wish list:”
- Offline editing. The GPMC changes GPOs instantly, which is why it doesn’t have a “save” button. That makes me kind of nervous, and so I like to have a tool that lets me load a GPO, edit it, and then save it when I’m ready to have the whole thing go into production.
- Comparison reports. These should ideally include some kind of color-coding to highlight differences, and should go down to the value level. In other words, you don’t want to just know which settings are different, you also want to know how they differ.
- Automated backup. The GPMC can run a backup of a GPO, but you really want the ability to automatically do so each time you make an edit. That way, you have a versioned history of each GPO. You should then be able to compare older versions with current ones so that you can quickly spot differences – an invaluable troubleshooting tool.
You may have some other capabilities that you’d like in a GPO management or comparison tool; add those to your own personal wish list and see if you can find a tool that handles it all.
Wait, Isn’t This Change Auditing?
Well, sort of. If you have a change auditing solution that’s capturing changes to GPOs as they’re made, that can definitely be useful for troubleshooting, but those audit reports don’t necessarily eliminate the need to have a good comparison tool. After all, GPOs change over time, right? You don’t want to have to dig through months of audit reports to find all of the changes to a GPO! It’d be much more efficient to just store a “baseline” copy of a GPO, and then compare it to the “current version” anytime you want to see a complete list of differences.
In fact, that’s a good recommendation to end with: Make a backup of all of your GPO objects, as they currently exist, and treat those as a baseline. That backup can be the entire GPO file, or maybe an XML representation generated by a PowerShell cmdlet. The idea is to have a baseline file that can be quickly and easily compared to the GPO’s current version, so that you can quickly spot changes. Whenever an authorized change is made to a GPO, update your baseline to reflect the most up-to-date settings.