Tuesday, July 25, 2017

Mirroring AD OU trees including GPOs - the PoSh way

Hello all.

In your AD, there might be an OU tree for production purposes. There might be a second tree for testing purposes. Now you need a third tree for evaluation purposes. That means copying all OUs from one of the existing trees and re-linking all GPOs linked to the source.

I recently had this requirement for an OU structure 6 levels deep with more than 100 linked GPOs. Hard to believe I would do this manually, so I fired up my ISE and came out with this module:

CopyGPOLink

Since the description in the gallery is somewhat crispy, here's the full help:



.SYNOPSIS
Copies the GPLink attribute from a specified source OU to a target OU in the same domain. Optionally appends or prepends to existing GPO links and recurses through child OUs.
   
.DESCRIPTION
When staging environments in a single AD, it is common to create a new identical OU structure for testing purposes. This structure should match the original one, including all child OUs and their linked GPOs. Copy-GPOLinks copies all linked GPOs from a source OU to a target OU in a given domain. Optionally, it recurses through child OUs and copies their GPOs, too. It also can create missing target child OUs automatically.

Note: By default, Copy-GPOLinks will not produce any screen output. If you want on-screen information, run it -verbose. If you need logging, intercept output streams or pipe to a file.

.PARAMETER SourceOU
Distinguished name of the OU to copy the GPLink attribute from.
   
.PARAMETER TargetOU
Distinguished name of the OU to copy the GPLink attribute to. Regardless of the CreateMissingChild switch, this OU must already exist or the cmdlet will fail.
   
.PARAMETER CopyMode
The copy mode for GPLink: Replace (overwrite), append or prepend to existing, or None. If you append or prepend and you run the command multiple times, you will create multiple links of the same set of GPOs. Within GPMC this cannot be done (GPMC has builtin logic that prevents this), but technically it is possible and valid. The 'None' value is useful when combined with -CreateMissingChilds and -Whatif, see the samples section for more information.

.PARAMETER Recurse
Process child OUs, too. The target child OU names must match the names of the respective source child OUs. Child OUs that are found in source, but not in target, are ignored and will not raise an error.

.PARAMETER CreateMissingChilds
If the recurse switch is specified and for a given source child OU no matching target child OU is found, the target child OU is created automatically. ProtectFromAccidentalDeletion is not enabled, ACLs are not copied.

.PARAMETER ResolveGPONames
By default Copy-GPOLinks operates on the GPLink attribute. This attribute only contains GPO GUIDs, so if you want to know what was copied, you'll need to look either in GPMC or resolve those GUIDs. If you specify this switch, the source GPO names will be resolved and listed in the verbose output.

.PARAMETER TargetDomain
The Domain where the operation takes place. Can be a different domain or forest. Defaults to the callers domain.

.PARAMETER Credential
If the target domain requires different credentials, a credential object can be passed in.

.EXAMPLE
Copy-GPOLinks -SourceOU 'OU=Corp,DC=Corp,DC=Contoso,DC=Com' -TargetOU 'OU=Corp-Test,DC=Corp,DC=Contoso,DC=Com'
This command copies all linked GPOs from OU=Corp to OU=Corp-Test.

.EXAMPLE
$VerbosePreference = 'Continue'
$SourceOU = 'OU=Corp,DC=Corp,DC=Contoso,DC=Com'
$TargetOU = 'OU=Corp-Test,DC=Corp,DC=Contoso,DC=Com'
Copy-GPOLinks -SourceOU $SourceOU -TargetOU $TargetOU -CopyMode Replace -Recurse -CreateMissingChilds -Whatif

This command recursively travels down OU=Corp. It would copy all GPOs linked, and it would create all missing OUs. Due to -WhatIf, for missing OUs it will write out that it would create them. But it will not write out that it would copy their GPOs, because copying is a different step. Since the target OU was not really created, the copy function will exit silently.

.EXAMPLE
Copy-GPOLinks -SourceOU 'OU=Corp,DC=Corp,DC=Contoso,DC=Com' -TargetOU 'OU=Corp-Test,DC=Corp,DC=Contoso,DC=Com' -CreateMissingChilds -Recurse -CopyMode None
This Command works almost the same as above. But due to not trying to copy the GPLink attribute, it will only create some missing OUs. This can then be used with the next example.

.EXAMPLE
Copy-GPOLinks -SourceOU 'OU=Corp,DC=Corp,DC=Contoso,DC=Com' -TargetOU 'OU=Corp-Test,DC=Corp,DC=Contoso,DC=Com' -Recurse -WhatIf
This again works almost the same as example #2 above. But if you first ran example #3, now all OUs are present and -WhatIf will be able to fully show what GPLinks it would copy.


Comments and feedback welcome 😃

3 comments:

  1. Just found this, struggled with the recurse in my own scripting. Thanks for this, lifesaver.

    ReplyDelete
  2. The only problem with Copy-GPOLinks is that you can't copy links that are assigned to the root. I found this script that will let you copy a single OU to a single OU and you can have the source be "DC=your,DC=domain" https://www.open-a-socket.com/2010/12/02/powershell-script-to-copy-gpo-links/

    ReplyDelete
    Replies
    1. Paul, you are right. The domain root was not in scope for the task at hand, so I skipped it. Sites as well, because AFAIK almost nobody uses site links. But who knows, there's always more than one way to skin the cat :-)

      Delete