UPDATED: Copy and Merge Group Policies (GPOs) with PowerShell
GPO Consolidation Redux
Do you have Group Policies gone wild? Did you realize too late that it might not be such a good idea to delegate GPO creation to half the IT department? Have you wanted to combine multiple policies into one for simplicity? This blog post is for you.
One of my most popular posts over the years has been a vintage script from 2011: Finally! Copy and merge GPOs! PowerShell saves the day! As I have said before, it is embarrassing to go back and look at old code from when you just started learning PowerShell. I would do things so differently now; so I did.
Recently a customer contacted me for help with Group Policy consolidation. They had 35 workstation policies linked to a single OU structure, and I suggested they reduce them to 3 to 5 policies. This was the perfect opportunity to dust off the old script and rewrite it using better PowerShell practices.
Fixes and Features
Thanks to your comments on the previous script I was able to fix some issues and add enhancements. The new, improved version of this script includes the following fixes and features:
- All functions compatible on PowerShell v2.0 for Windows Server 2008 R2.
- Recursive infinite loop identified and fixed.
- Specify multiple source GPOs.
- Dynamically create the destination GPO if it does not exist.
- Verbose logging for every setting copied.
- Warnings for settings that get over-written, showing both old and new values.
- Warnings for settings that fail copying (usually the Disable/Delete type).
- Warnings for non-registry settings that need manual copy.
- Warning if source policy is not found.
- Helper functions for identifying linked and unlinked GPOs.
- Progress bar.
Nice list.
What about Group Policy Preferences?
Some folks have asked how to copy preferences as well. Here again we are limited by the features in the GroupPolicy PowerShell module. There is a cmdlet to copy preference registry settings, but that is all. When you look at the scope of how many different kinds of settings there are in preferences, this is only a very small percentage of the scope. I decided it was not worth the development time to pursue this.
Free Advice: Group Policy Optimization
You can improve group policy processing performance on client machines by reducing the total number of policies applied. This eliminates multiple per-policy processing steps. However, this does not mean to simply combine all 35 policies into one single policy. Here are some guidelines to follow for policy consolidation:
- Using the Get-GPLink report below look at which policies change the most frequently. This is indicated in the versioning statistics and modification date for each policy. Leave these frequently-updated policies as they are or consider rolling them into one frequently-updated policy.
- Take the remaining policies that are infrequently updated and consolidate them into a single policy. Separating the policies by update frequency will keep the bulk of the settings from triggering a refresh, keeping policy processing time to a minimum.
- For any future policy additions that will be relatively static, add them to the consolidated policy. For settings that will change frequently, consider adding them to one of the existing policies with frequent updates.
See the great article Group Policy Processing Performance Considerations for a deeper discussion of group policy performance optimization.
When creating new group policies, consider the following points to justify if a new policy object is required:
- Will the policy be linked to multiple OUs?
- Will the policy require unique security group filtering scenarios?
- Will the policy require frequent updates?
If the answer is “yes” for any of these questions, then a new group policy object may be required. Otherwise add the settings to an existing group policy object.
Group Policy Consolidation Process
Use the updated script below for combining the group policies. This script will likely meet 80% or more of your requirements. Due to scripting limitations, only the group policy registry settings can be copied into a consolidated policy. Other setting that require manual migration are noted in the output from the script.
When analyzing the policies for consolidation, take into account the following factors for the suitability of each policy to be consolidated:
- Is the policy still relevant for the latest workstation standards?
- Is the policy linked to multiple OUs?
- Is the policy filtered by either security groups or WMI filters?
Once policies are identified for consolidation, use the script below to do the work. The script will create a new policy containing the merged settings, and it is not linked to any OU. Create a test OU, link the new policy, move a sample of test machines into the OU, and then validate that the policy applies all setting correctly. Pay close attention to any settings where a warning was noted in the script output. Recreate these settings manually as needed.
Note that the consolidated GPO will not include any of the following features of the other GPOs:
- WMI filter
- Permission filtering
- User or computer settings disabled
These settings may need to be manually applied to the new policy where appropriate.
When the time comes for production implementation, link the new consolidated GPO to the production OU. Allow two hours for replication and workstations to refresh their settings. Next disable the consolidated individual former GPOs (see script sample below). Do this activity during a non-peak time as a precaution. Allow another two hours for policy refresh on workstations. After reboot and verification of the settings on a sample of target workstations it will be safe to delete the disabled OU links (not the policies) . Finally, backup and delete the policies themselves once all other dependencies have been eliminated and verified.
Note: When consolidating multiple GPOs linked to a single OU the sample code below consolidates the policies in the order of their group policy precedence (from bottom to top of the list). This ensures that any potentially duplicated or conflicted settings will retain the values from the highest-ranking policies in the same way these settings would be applied in the formerly separate policies.
Show me some ‘Shell
This script file contains three functions:
- Get-GPLink – Detailed link report for GPOs, including enabled/disabled, enforced, block inheritance, WMIFilter, date created, date modified, version numbers, and more. This is based off of another GPO report that I did, but I removed the PowerShell v3 cmdlets for Windows Server 2008 R2 compatibility. This report only includes GPOs that are linked in the environment.
- Get-GPUnlinked – This is similar to the Get-GPLink report, but it includes unlinked GPOs and a simplified Linked property for reporting.
- Copy-GPRegistryValue – This function is the heart of the script, and it is a 99% rewrite of the previous version. See the bullet list above for the features list.
After you download the script, unblock the file, open it in the PowerShell ISE, and review the code. Press F5 to run it. Notice that there is a BREAK statement following the functions, and this prevents the sample code at the bottom from executing. This will load the functions for your use. Tweak the sample code and use F8 to run selections of it in your lab before production.
Here is the included sample code for using the functions. Read through the comments below to understand the scenarios enabled by these functions:
# Help
Help Get-GPLink -Full
Help Get-GPUnlinked -Full
Help Copy-GPRegistryValue -Full
# Copy one GPO registry settings into another
Copy-GPRegistryValue -Mode All -SourceGPO 'Client Settings' `
-DestinationGPO 'New Merged GPO' -Verbose
# Copy one GPO registry settings into another, just user settings
Copy-GPRegistryValue -Mode User -SourceGPO 'Client Settings' `
-DestinationGPO 'New Merged GPO' -Verbose
# Copy one GPO registry settings into another, just computer settings
Copy-GPRegistryValue -Mode Computer -SourceGPO 'Client Settings' `
-DestinationGPO 'New Merged GPO' -Verbose
# Copy multiple GPO registry settings into another
Copy-GPRegistryValue -Mode All -DestinationGPO "NewMergedGPO" `
-SourceGPO "Firewall Policy", "Starter User", "Starter Computer" -Verbose
# Copy all GPOs linked to one OU registry settings into another
# Sort in reverse precedence order so that the highest precedence settings overwrite
# any potential settings conflicts in lower precedence policies.
$SourceGPOs = Get-GPLink -Path 'OU=PHB,OU=HR,DC=CohoVineyard,DC=com' |
Sort-Object Precedence -Descending |
Select-Object -ExpandProperty DisplayName
Copy-GPRegistryValue -Mode All -SourceGPO $SourceGPOs `
-DestinationGPO "NewMergedGPO" -Verbose
# Log all GPO copy output (including verbose and warning)
# Requires PowerShell v3.0+
Copy-GPRegistryValue -Mode All -SourceGPO 'IE Test' `
-DestinationGPO 'New Merged GPO' -Verbose *> GPOCopyLog.txt
# Disable all GPOs linked to an OU
Get-GPLink -Path 'OU=PHB,OU=HR,DC=CohoVineyard,DC=com' |
ForEach-Object {
Set-GPLink -Target $_.OUDN -GUID $_.GUID -LinkEnabled No -Confirm
}
# Enable all GPOs linked to an OU
Get-GPLink -Path 'OU=PHB,OU=HR,DC=CohoVineyard,DC=com' |
ForEach-Object {
Set-GPLink -Target $_.OUDN -GUID $_.GUID -LinkEnabled Yes -Confirm
}
# Quick link status of all GPOs
Get-GPUnlinked | Out-Gridview
# Just the unlinked GPOs
Get-GPUnlinked | Where-Object {!$_.Linked} | Out-GridView
# Detailed GP link status for all GPOs with links
Get-GPLink | Out-GridView
# List of GPOs linked to a specific OU (or domain root)
Get-GPLink -Path 'OU=PHB,OU=HR,DC=CohoVineyard,DC=com' |
Select-Object -ExpandProperty DisplayName
# List of OUs (or domain root) where a specific GPO is linked
Get-GPLink |
Where-Object {$_.DisplayName -eq 'Script And Delegation Test'} |
Select-Object -ExpandProperty OUDN
Important Notes
ALWAYS use –Verbose when running these functions. Here are some warnings you may notice in your output while consolidating GPOs:
- Registry path not found. This is normal. Safely ignore it. The function attempts to explore every possible registry setting root path based on the consolidation mode (user, computer, all). These will not be present in every policy.
- Empty value, potential setting failure. Observe the detailed output and manually verify that these settings were copied into the destination policy. These are usually policies that disable a setting.
- Source GPO contains non-registry settings for manual copy. This script can only migrate registry-based settings. Look at the warning details to see what other types of settings are included in the policy. These settings require manual copying.
- Overwriting previous value. The destination policy already contained the setting, and it is being overwritten. Notice that the old value appears in the warning text, and the new value appears in the following verbose text.
- Source GPO does not exist. Check your spelling of the SourceGPO parameter value(s). Use quotes around policy names that include spaces.
That may sound like a lot of warnings, but hey, it is better than the alternative (no warnings). Now you know where you might have potential issues in the copy. Manually compare and edit the destination policy as necessary to make a good copy. Then test, test, test the policy as described above.
This process should save you 80% or more manual effort on the process of consolidating GPOs. That is a lot of clickety-click avoided.
How Do I Get The Script?
Download the full script at the TechNet Script Center.
BONUS LINK: The Group Policy team blog has some great sample PowerShell for other GPO scripting tasks.
Comments
- Anonymous
June 20, 2015
wow - Anonymous
June 26, 2015
Great script. I have multiple OUs with GPOs applied. Currently 130 GPOs and i've been tasked with the job of consolidation. Will this script work if GPOs are applied to multiple OUs ? - Anonymous
July 07, 2015
Hello NetworkAngel,
The consolidation will likely work, but you will need to plan out more carefully which policies to consolidate based on where they are linked. Be careful not to join policies that would begin applying new settings to other OUs.
Hope this helps,
Ashley - Anonymous
July 15, 2015
Does the script still only work on registry-based policy settings or does it now include auditing? My goal is to create a local group policy (I don't work in domains) which complies to a specific policy, but would do this several times. The result would be one LGPO which complies with policy A, one for B, etc. When the need for a system to comply with Policies A, D, and F, I'd like to just combine LGPOs made for A, D, and F. Would this script support such a concept? - Anonymous
July 16, 2015
The comment has been removed - Anonymous
August 04, 2015
Awesome job, this literally was written right after I was tasked with a consolidation project - Anonymous
December 16, 2015
This script sounds great in theory, especially with the advertised comment that the process should save 80% of the manual labor in consolidating GPO's. Shame it's a lie. I tried to merge two GPO's using this script and got a whopping 12 settings out of over 100 copied to the new GPO. And I'm not even talking about Group Policy Preferences settings. All this did was cause me to waste time finding out that I still have to merge my GPO's manually. - Anonymous
January 04, 2016
Hello John,
Sorry to hear that. Sounds like your policies use more non-registry based settings. The 80% is an estimate of average policy settings that would be registry-based.
GoateePFE - Anonymous
January 27, 2016
I'm getting this error message "Select-String : Cannot find path 'C:Windowssystem32report_Default Domain Policy.xml' because it does not exist. $nonRegistry = Select-String <<<< -Path "C:WindowsSystem32report_$($SourceGPOSingle).xml" -Pattern " + CategoryInfo : ObjectNotFound: (C:WindowsSyst...main Policy.xml:String) [Select-String], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SelectStringCommand - Anonymous
March 23, 2016
Hi Ashley, Love your work! I am looking for some way to take multiple GPO's and consolidate them in to a GPO that contains the settings that are identical and then separate GPO's for the unique settings. So, if I were to export GPO’s from MSCM for the W2008, W2012 and W2012R2 for member servers, I would like to be able to consolidate them as follows, - Default Member Server GPO settings that would be repeated in the following GPO’s- Unique W2008 - Containing settings only for W2008 Member Servers- Unique W2012 - Containing settings only for W2012 Member Servers- Unique W2012 - Containing settings only for W2012R2 Member ServersThank you in advance - Anonymous
October 03, 2016
If i do 'get-command -module grouppolicy' i don't see Get-GPLink or Copy-GPRegistryValue listed, what cmdlet are you loading to get this to work?- Anonymous
October 28, 2016
Hi there,Those are in the functions you can download. See the link in the article.GoateePFE
- Anonymous
- Anonymous
April 04, 2017
cool! now I can go wild and create as many GPOs as I want for any settings knowing that I could merge them later :) seriously that's awesome thanks a lot!- Anonymous
November 08, 2017
Doesn't seem to work like that - for me this has only merged registry settings. So won't cover things like "Account Policy" or "Local Policy" settings
- Anonymous
- Anonymous
June 26, 2017
Great Stuff! Recently I saw some Access Denied errors while coping GPOs. Any Idea what is causing this? Most settings have been copied successfully but some not with the 80..5 error. I used domain Admin and local Admin but it did not help. Env: Windows 10 1703, Server2016 DCs. - Anonymous
October 11, 2017
Modifying this script to allow merging Group Policy backups and not overwriting conflicts, while importing to a live GPO would make this a great tool for managing Security Compliance baselines. Especially considering the deprecation of Security Compliance Manager.Could adding these features be considered? See SecGuide blog for more information regarding deprecation of SCM.