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.

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.

Getting the Columbus OU
Getting the Columbus OU (Image Credit: Jeff Hicks)

I want to move this under ChicagoHQ.

Getting the Chicago OU
Getting the Chicago OU (Image Credit: Jeff Hicks)

So I check the Active Directory module to see if there’s a command I can use:

Listing OU commands
Listing OU commands (Image Credit: Jeff Hicks)

There doesn’t appear to be anything specific to OUs. Let’s take a different approach and look for cmdlets based on a verb.

Listing Active Directory Move commands
Listing Active Directory Move commands (Image Credit: Jeff Hicks)

The Move-ADObject looks like the best candidate. Naturally we should read the help.

Help for Move-ADObject
Help for Move-ADObject (Image Credit: Jeff Hicks)

This seems pretty straightforward.

Get-ADOrganizationalUnit -filter "Name -eq 'Columbus'" | Move-ADObject -TargetPath "OU=ChicagoHQ,OU=Offices,DC=GLOBOMANTICS,DC=local" -WhatIf
Testing a move command
Testing a move command (Image Credit: Jeff Hicks)

That looks correct so I’ll re-run without –Whatif.

Re-running the move command
Re-running the move command (Image Credit: Jeff Hicks)

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.

Protect from accidental deletion
Protect from accidental deletion (Image Credit: Jeff Hicks)

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.

Moving the OU
Moving the OU (Image Credti: Jeff Hicks)

There were no errors, so I can only assume it worked. I’ll get the OU again and verify.

Verifying the new location
Verifying the new location (Image Credit: Jeff Hicks)

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.

A move OU one-liner
A move OU one-liner (Image Credit: Jeff Hicks)

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.

Remove-ADOrganizationalUnit Help
Remove-ADOrganizationalUnit Help (Image Credit: Jeff Hicks)

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:

Removal confirmation
Removal confirmation (Image Credit: Jeff Hicks)

I’m in the PowerShell ISE, which is why I get a popup. I answer “Yes.”

Access Denied
Access Denied (Image Credit: Jeff Hicks)

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 |
Child object error
Child object error (Image Credit: Jeff Hicks)

That still failed because TestA contains child objects, but I remember in help there is a parameter that might solve this.

The Recursive parameter
The Recursive parameter (Image Credit: Jeff Hicks)

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.

Verifying test OUs
Verifying test OUs (Image Credit: Jeff Hicks)

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.

Related Article: