Moving and Deleting Active Directory OUs with PowerShell
In the last few articles I’ve been showing you how to use the Active Directory PowerShell module to create and manage Active Directory organizational units. To wrap this up, let’s look at moving and deleting OUs. Again, this isn’t something that I think you necessarily need to automate because you probably don’t do these tasks that often and Active Directory Users and Computers are fine for these tasks. But you may want a documentation trail or have other reasons for creating a script, so let’s see what you need to do.
- Read: Creating Active Directory OUs with PowerShell
- Read: Managing Active Directory OUs with PowerShell
Moving an OU
To move an OU, I’m assuming that if you are using Group Policy, then you understand the implications in your domain. Moving an OU will naturally move everything within it, including other OUs. But let’s assume you have analyzed the consequences and are ready to proceed. We’ll use some of the OUs I created in earlier articles for the demonstration. If you recall, I created a number of OUs based on office location. During a recent reorganization, the Columbus branch office will now fall under the Chicago office. Currently, the Columbus organizational unit is a separate unit.
I want to move this under ChicagoHQ.
Read the Best Personal and Business Tech without Ads
Staying updated on what is happening in the technology sector is important to your career and your personal life but ads can make reading news, distracting. With Thurrott Premium, you can enjoy the best coverage in tech without the annoying ads.
So I check the Active Directory module to see if there’s a command I can use:
There doesn’t appear to be anything specific to OUs. Let’s take a different approach and look for cmdlets based on a verb.
The Move-ADObject looks like the best candidate. Naturally we should read the help.
This seems pretty straightforward.
Get-ADOrganizationalUnit -filter "Name -eq 'Columbus'" | Move-ADObject -TargetPath "OU=ChicagoHQ,OU=Offices,DC=GLOBOMANTICS,DC=local" -WhatIf
That looks correct so I’ll re-run without –Whatif.
Well that didn’t go as planned. I’m logged on with a domain admin credential, so this should work. But I’ll cut to the chase and explain why this failed.
When you create an OU in Active Directory, Microsoft sets the security on it so that you can’t accidentally delete it. This was apparently a big problem in the early days of Active Directory because it was such an easy mistake to make. You can see this in Active Directory Users and Computers.
You could manually uncheck this box and proceed, but let’s set this with PowerShell. This is easily accomplished with Set-ADOrganizationalUnit.
Get-ADOrganizationalUnit -filter "Name -eq 'Columbus'" | Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $False
Now I can attempt to re-run the move command.
There were no errors, so I can only assume it worked. I’ll get the OU again and verify.
Based on the distinguishedname, I can see the move was successful. I should point out that the “protect from accidental deletion” feature also applies to objects like user accounts. Any protected objects in the OU are unaffected by the move. But, since the Columbus OU was protected to begin with, I should go ahead and re-enable it.
Get-ADOrganizationalUnit -filter "Name -eq 'Columbus'" | Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $True
Now that you understand the process, you can use a one-line PowerShell expression to get the OU, change the protection, move it, and change the protection back. This works because we can tell PowerShell to keep passing the object through the pipeline.
Get-ADOrganizationalUnit -filter "Name -like 'Petri*'" | Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $False -PassThru | Move-ADObject -TargetPath (Get-ADOrganizationalUnit -filter "Name -eq 'Testing'") -PassThru | Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $True -PassThru
I’m using a nested command to get the target OU, so that I don’t have to know in advance its distinguishedname.
On a side note, I know that looks like a long command to type, but I used tab completion for cmdlet and parameter names so it didn’t take long at all.
Deleting an OU
Deleting an OU is rather straightforward. If you recall when we looked at commands in the Active Directory module, there was one specifically for removing OUs.
Because OUs can have child objects, including nested OUs, you need to be careful and plan accordingly. In my domain, I have a test organizational unit that can be deleted. I know the full path, so I’ll use it:
Remove-ADOrganizationalUnit -Identity "OU=TestA,DC=globomantics,DC=local"
I get prompted for a confirmation:
I’m in the PowerShell ISE, which is why I get a popup. I answer “Yes.”
Oops. As you might have guessed, I have the same issue with protection from accidental deletion. Let’s use the pipeline to set it and then remove the OU.
Get-ADOrganizationalUnit -filter "Name -eq 'TestA'" | Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $False -PassThru | Remove-ADOrganizationalUnit
That still failed because TestA contains child objects, but I remember in help there is a parameter that might solve this.
So I’ll re-run the command and use this parameter. It doesn’t matter that I’m setting the protection again.
Get-ADOrganizationalUnit -filter "Name -eq 'TestA'" | Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $False -PassThru | Remove-ADOrganizationalUnit -recursive
This time there are no errors. I can recheck my domain for test organizational units and confirm that TestA, which included a TestB OU, are gone.
And even though TestB was also flagged for accidental deletion protection as well as some user accounts, I didn’t have to do anything to them. As long as the top level container can be deleted and you use –Recursive, everything will go away. All of this may seem like a lot of work, but that’s to protect you from potential “career-limiting” events.
With careful planning and plenty of testing in a non-production environment, you can easily manage Active Directory with PowerShell.