Get-EmptyOUs.ps1
19 Sep 2025Description
Purpose
Retrieves and optionally removes empty Active Directory Organizational Units (OUs).
Detailed Description
The Get-EmptyOUs function retrieves all organizational units (OUs) in Active Directory and checks if they are empty. It can optionally remove the empty OUs if specified.
Usage
Example 1
Get-EmptyOUs -RemoveOUs $false
Retrieves and lists the distinguished names (DNs) of the empty OUs without removing them.
Example 2
Get-EmptyOUs -RemoveOUs $true -OUsToKeep "OU=TestOU,DC=example,DC=com"
Retrieves and removes the empty OUs, excluding the OU with the specified distinguished name.
Notes
This function requires the Active Directory module to be installed. It should be run with appropriate permissions to manage OUs in Active Directory.
Script
<#
.SYNOPSIS
Retrieves and optionally removes empty Active Directory Organizational Units (OUs).
.DESCRIPTION
The Get-EmptyOUs function retrieves all organizational units (OUs) in Active Directory and checks if they are empty. It can optionally remove the empty OUs if specified.
.PARAMETER RemoveOUs
Indicates whether to remove the empty OUs. If $true, empty OUs will be removed. If $false, only a list of empty OUs will be returned.
.PARAMETER OUsToKeep
An array of distinguished names (DNs) of OUs to exclude from removal, even if they are empty.
.EXAMPLE
Get-EmptyOUs -RemoveOUs $false
Retrieves and lists the distinguished names (DNs) of the empty OUs without removing them.
.EXAMPLE
Get-EmptyOUs -RemoveOUs $true -OUsToKeep "OU=TestOU,DC=example,DC=com"
Retrieves and removes the empty OUs, excluding the OU with the specified distinguished name.
.NOTES
This function requires the Active Directory module to be installed. It should be run with appropriate permissions to manage OUs in Active Directory.
#>
function Get-EmptyOUs {
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[bool]$RemoveOUs = $false,
[Parameter(Mandatory = $false)]
[string[]]$OUsToKeep = @()
)
function Get-AdOrganizationalUnits {
Get-ADObject -Filter "ObjectClass -eq 'organizationalUnit'" | Where-Object { $_.DistinguishedName -notlike '*LostAndFound*' }
}
function Get-EmptyAdOrganizationalUnits($ad_ous) {
$aOuDns = @()
foreach ($o in $ad_ous) {
$sDn = $o.DistinguishedName
if ($sDn -like '*OU=*') {
$sOuDn = $sDn.Substring($sDn.IndexOf('OU='))
$aOuDns += $sOuDn
}
}
$a0CountOus = $aOuDns | Group-Object | Where-Object { $_.Count -eq 1 } | ForEach-Object { $_.Name }
return $a0CountOus
}
function IsAdOrganizationalUnitEmpty($ou_dn) {
$child_objects = Get-ADObject -Filter "ObjectClass -ne 'organizationalUnit'" -SearchBase $ou_dn -SearchScope OneLevel -Properties ObjectClass
$child_ous = Get-ADObject -Filter "ObjectClass -eq 'organizationalUnit'" -SearchBase $ou_dn -SearchScope OneLevel -Properties ObjectClass
return ($child_objects.Count -eq 0 -and $child_ous.Count -eq 0)
}
function RemoveAdOrganizationalUnit($ou_dn) {
Set-ADOrganizationalUnit -Identity $ou_dn -ProtectedFromAccidentalDeletion $false -confirm:$false
Remove-AdOrganizationalUnit -Identity $ou_dn -confirm:$false
}
$ad_ous = Get-AdOrganizationalUnits
$a0CountOus = Get-EmptyAdOrganizationalUnits $ad_ous
$empty_ous = 0
$ous_removed = 0
foreach ($sOu in $a0CountOus) {
if (IsAdOrganizationalUnitEmpty $sOu) {
$ou_dn = (Get-AdObject -Filter { DistinguishedName -eq $sOu }).DistinguishedName
if ($OUsToKeep -notcontains $ou_dn) {
if ($RemoveOUs) {
RemoveAdOrganizationalUnit $ou_dn
$ous_removed++
}
else {
Write-Output $ou_dn
}
$empty_ous++
}
}
}
if ($empty_ous -gt 0) {
Write-Output '-------------------'
Write-Output "Total Empty OUs Removed: $ous_removed"
Write-Output "Total Empty OUs: $empty_ous"
}
else {
Write-Output 'No empty OUs found.'
}
}
Download
Please feel free to copy parts of the script or if you would like to download the entire script, simply click the download button. You can download the complete repository in a zip file by clicking the Download link in the menu bar on the left hand side of the page.
Report Issues
You can report an issue or contribute to this site on GitHub. Simply click the button below and add any relevant notes. I will attempt to respond to all issues as soon as possible.