#-------------------------------------------------------------------- # Copy GPO Registry Settings # Ashley McGlone, Microsoft PFE # http://blogs.technet.com/b/ashleymcglone # January 2011 # # Parameters: # dom FQDN of the domain where the GPOs reside # src string name of the GPO to copy settings from # dest string name of the GPO to copy settings to # newDest switch to create dest GPO if it does not exist # copymode part of GPO to copy: all, user, computer #-------------------------------------------------------------------- Param ( $dom, $src, $dest, [switch]$newDest, $copymode ) # We must continue on errors due to the way we enumerate GPO registry # paths and values in the function CopyValues. $ErrorActionPreference = "SilentlyContinue" $error.PSBase.Clear() Import-Module ActiveDirectory Import-Module GroupPolicy #-------------------------------------------------------------------- # Help #-------------------------------------------------------------------- if ($dom -eq $null -and ` $src -eq $null -and ` $dest -eq $null -and ` $copymode -eq $null) { "" "Copy-GPORegistryValue by Ashley McGlone, Microsoft PFE" "For more info: http://blogs.technet.com/b/ashleymcglone" "" "This script copies registry-based GPO settings from one GPO into another." "Use this script to copy and/or merge policy settings." "NOTE: This version does not copy GPO preferences." "" "Syntax:" ".\Copy-GPRegistryValue.ps1 [-dom DomainFQDN] -src `"Source GPO`"" " -dest `"Destination GPO`" [-newDest]" " [-copymode all/user/computer]" "" "The -dom switch will default to the current domain if blank." "The -copymode will default to all if blank." "The -newDest switch will create a new destination GPO of the specified" "name. If the GPO already exists, then the copy will proceed." "" Return } #-------------------------------------------------------------------- # Validate parameters #-------------------------------------------------------------------- if ($dom -eq $null) { $dom = (Get-ADDomain).DNSRoot } else { $dom = (Get-ADDomain -Identity $dom).DNSRoot If ($error.Count -ne 0) { "Domain name does not exist. Please specify a valid domain FQDN." $error Return } } if ($src -eq $null) { "Source GPO name cannot be blank." Return } else { $src = Get-GPO -Name $src If ($error.Count -ne 0) { "Source GPO does not exist. Be sure to use quotes around the name." Return } } if ($dest -eq $null) { "Destination GPO name cannot be blank." Return } else { if ($newDest -eq $true) { $desttemp = $dest $dest = New-GPO -Name $desttemp If ($error.Count -ne 0) { "The new destination GPO already exists." "Do you want to merge into this GPO (y/n)?" $choice = Read-Host if ($choice -eq "y") { $dest = Get-GPO -Name $desttemp } else { Return } } } else { $dest = Get-GPO -Name $dest If ($error.Count -ne 0) { "Destination GPO does not exist. Be sure to use quotes around the name." Return } } } if ($copymode -eq $null) { $copymode = "all" } else { if ($copymode -ne "all" -and ` $copymode -ne "user" -and ` $copymode -ne "computer") { "copymode must be one of the following values:" "all, user, computer" Return } } #-------------------------------------------------------------------- #-------------------------------------------------------------------- # Echo parameters for this run #-------------------------------------------------------------------- "" "Domain: $dom" "Source GPO: $($src.DisplayName)" "Destination GPO: $($dest.DisplayName)" "New Destination: $newDest" "CopyMode: $copymode" "" #-------------------------------------------------------------------- #-------------------------------------------------------------------- # Copy GPO registry values recursively beginning at a specified root. #-------------------------------------------------------------------- # THIS IS THE HEART OF THE SCRIPT. # Essentially this routine does a get from the source and a set on # the destination. Of course nothing is ever that simple, so we have # to account for the policystate "delete" which disables a setting; # this is like a "negative set". # We recurse down each registry path until we find a value to # get/set. # If we try to get a value from a path (non-leaf level), then we get # an error and continue to dig down the path. If we get a value and # no error, then we do the set. # User values have a single root: HKCU\Software. # Computer values have two roots: HKLM\System & HKLM\Software. # You can find these roots yourself by analyzing ADM and ADMX files. # It is normal to see an error in the output, because all of these # roots are not used in all policies. #-------------------------------------------------------------------- Function CopyValues ($Key) { $Key $error.PSBase.Clear() $path = Get-GPRegistryValue -GUID $src.ID -Key $Key $path If ($error.Count -eq 0) { ForEach ($keypath in $path) { $keypath $keypath | ForEach-Object {Write-Host $_} If ($keypath.HasValue) { $keypath.PolicyState $keypath.Valuename $keypath.Type $keypath.Value If ($keypath.PolicyState -eq "Delete") { # PolicyState = "Delete" Set-GPRegistryValue -Disable -Domain $dom -GUID $dest.ID ` -Key $keypath.FullKeyPath -ValueName $keypath.Valuename } Else { # PolicyState = "Set" $keypath | Set-GPRegistryValue -Domain $dom -GUID $dest.ID } } Else { CopyValues $keypath.FullKeyPath } } } Else { $error } } #-------------------------------------------------------------------- #-------------------------------------------------------------------- # Call the main copy routine for the specified scope of $copymode #-------------------------------------------------------------------- Function Copy-GPRegistryValue { # Copy user settings If (($copymode -eq "user") -or ($copymode -eq "all")) { CopyValues "HKCU\Software" } # Copy computer settings If (($copymode -eq "computer") -or ($copymode -eq "all")) { CopyValues "HKLM\System" CopyValues "HKLM\Software" } } #-------------------------------------------------------------------- # Start the copy Copy-GPRegistryValue # ><>