Recently I needed to build out some test Active Directory Forests that resemble production in order to complete some testing. One of the forests contained a significant amount of OU’s that I had no intention of manually recreating.
To run the New-ADOrganizationalUnit cmdlet, you need to provide the OU name and the Path where you want to create it. However, Get-ADOrganizationalUnit doesn’t provide the path, so you need to determine it from the DistinguishedName.
After a number of google searches, I couldn’t find exactly what I needed, so I began piecing together various bits of Powershell that I found. I ended up learning a bit of Regex in the process! Powerful tool if you know how to use it.
I came up with two versions in the end, you can see both below with the differences highlighted.
1$OUs=Get-ADOrganizationalUnit -Filter * | select name,DistinguishedName,@{n=’OUPath’;e={$_.distinguishedName -replace **_'^.+?,',_**''}},@{n=’OUNum’;e={([regex]::Matches($_.distinguishedName, “OU=” )).count}} | Sort OUNum | export-csv C:<Path_to_CSV>OUTree.csv -NoTypeInformation
1$OUs=Get-ADOrganizationalUnit -Filter * | select name,DistinguishedName,@{n=’OUPath’;e={$_.distinguishedName -replace **_'^.+?,(CN|OU|DC.+)','$1'_**}},@{n=’OUNum’;e={([regex]::Matches($_.distinguishedName, “OU=” )).count}} | Sort OUNum | export-csv C:<Path_to_CSV>OUTree.csv -NoTypeInformation
The first one effectively takes everything up to the first ‘,’ and replaces it with nothing, effectively removing the OU Name. The second one captures everything after the first ‘,’ and replaces the whole string with what was captured. Both have produced the same result in my scenario, but it was useful to understand both methods for future use of Regex.
Both also have a property called ‘OUNum’, this property counts how many time ‘OU=’ appears in the original DistigushedName string. OU’s need to be created in order, so that the parent OU exists before the child. This orders the OU’s in ’tiers’ before exporting them to CSV. All OU’s in the root of the directory will get a value of 1, OU’s within these will get a value of 2 and so on. Credit to ‘David Z’ for this bit!
Once you have your data, you may or may not need to modify the domain. If you are importing it into a different domain, you’ll need to. In my case it was simple enough to do a find and replace in a text editor (eg. DC=lab,DC=local to DC=lab2,DC=local
). You could look at using concepts from above to achieve this before exporting the data if you so wish.
Now you have your data, you need to import it. You can run the following in the target domain.
1$OUs = import-csv C:<Path_to_CSV>OUTree.csv
2ForEach ($OU in $OUs)
3 {New-ADOrganizationalUnit -Name $OU.Name -Path $OU.OUPath}
Hope this has been useful. Thanks for reading!