Discussing OU structures in an Active Directory can easily get into a religious matter. 🙂
Anyhow, the reality is that different organizations have different needs. Therefore, you sometimes end up with more or less complex OU structures. In order to make the creation of the ‘more complex structures’ as the one in the screenshot below easier, I’ve created a small function that lets you copy the structure from a template or from an existing, already properly configured site/structure.
function Copy-JDOrganizationalUnit { <# .SYNOPSIS The script copies an OU structure from one OU to another. The destination OU must already be created. .EXAMPLE Copy-JDOrganizationalUnit -SourcePath "OU=HAB,OU=SE,OU=Sites,DC=lucernepublishing,DC=local" -DestinationPath "OU=HEL,OU=FI,OU=Sites,DC=lucernepublishing,DC=local" -Verbose .PARAMETER SourceOU Plain name of the source OU to copy the structure from. .PARAMETER DestinationOU Plain name of the destination OU to replicate the structure to. .PARAMETER ProtectOU Sets the flag ProtectOUFromAccidentialDeletion .NOTES File Name: Copy-JDOrganizationalUnit Author : Johan Dahlbom, johan[at]dahlbom.eu Blog : 365lab.net The script are provided “AS IS” with no guarantees, no warranties, and they confer no rights. #> [CmdletBinding(SupportsShouldProcess=$true,HelpUri = 'http://www.365lab.net/')] param ( [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] [ValidateScript({Get-ADOrganizationalUnit -Identity $_})] [string]$SourcePath, [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] [ValidateScript({Get-ADOrganizationalUnit -Identity $_})] [string]$DestinationPath, [switch]$ProtectOU ) Write-Verbose "Copying structure from $SourcePath to $DestinationPath..." Get-ADOrganizationalUnit -SearchBase $SourcePath -Filter {Distinguishedname -ne $SourcePath} -Properties canonicalname| Select-Object DistinguishedName,canonicalname,Name | Sort-Object -Property CanonicalName | ForEach-Object { try { $NewOU = @{ Path = $_.DistinguishedName.replace("OU=$($Name),",'').Replace("$SourcePath","$DestinationPath") Name = $_.Name ProtectedFromAccidentalDeletion = $ProtectOU } New-ADOrganizationalUnit @NewOU -ErrorAction Stop Write-Verbose "Created OU OU=$Name,$DestPath" } catch { Write-Warning "Error with creating OU=$Name,$DestPath`r`n$_" } } }
Running the example as below, will copy the entire structure from OU=JKG to OU=BRU. It will not overwrite any existing OU’s.
$OUs = @{ SourcePath = 'OU=JKG,OU=SE,OU=Sites,DC=365lab,DC=internal' DestinationPath = 'OU=BRU,OU=BE,OU=Sites,DC=365lab,DC=internal' } Copy-JDOrganizationalUnit @OUs -Verbose -ProtectOU
As you can see above, the entire structure has now been copied according to the Source OU. Let me know if you have feedback or suggestions on improvements!
/Johan
Received the following error:
WARNING: Error with creating OU=,
Cannot convert ‘System.Management.Automation.SwitchParameter’ to the type ‘System.Nullable`1[System.Boolean]’ required by parameter ‘ProtectedFrom
AccidentalDeletion’.
By default when I create a OU the Protect from Accidental Deletion is defaulted ticked.
Here is what I ran:
$OUs = @{
SourcePath = ‘OU=Corporate Image,OU=Windows 7,OU=BatchBuilder,OU=Production,OU=DCT,OU=Computers,OU=MMS,OU=Delegated,DC=na,DC=corp,DC=maskeddomain,DC=com’
DestinationPath = ‘OU=Windows 10,OU=BatchBuilder,OU=Production,OU=DCT,OU=Computers,OU=MMS,OU=Delegated,DC=na,DC=corp,DC=maskeddomain,DC=com’
}
.\Copy-JDOrganizationalUnit.ps1 @OUs -Verbose -ProtectOU