- Published on
How to List All Users From a Specific OU in Active Directory (PowerShell Script)
Before applying a new GPO, running a bulk operation, or handing an OU off to a delegated admin, you want to know exactly who's in scope — not roughly, exactly. It's a simple query, but getting the sub-OU behavior right (included by default, or not) is the part that trips people up.
The quick answer
Get-ADUser -Filter * -SearchBase "OU=Sales,DC=contoso,DC=com" -SearchScope Subtree
A more useful reporting script
#requires -Modules ActiveDirectory
<#
.SYNOPSIS
Lists all users in a specific Active Directory OU.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$SearchBase,
[switch]$DirectOnly,
[string]$OutputCsv
)
Import-Module ActiveDirectory -ErrorAction Stop
$params = @{
Filter = '*'
SearchBase = $SearchBase
SearchScope = if ($DirectOnly) { 'OneLevel' } else { 'Subtree' }
Properties = @('Enabled', 'DistinguishedName')
}
$users = Get-ADUser @params |
Select-Object Name, SamAccountName, Enabled, DistinguishedName |
Sort-Object Name
if (-not $users) {
Write-Host "No users found under $SearchBase." -ForegroundColor Yellow
return
}
Write-Host "Found $(@($users).Count) user(s) under $SearchBase." -ForegroundColor Cyan
$users | Format-Table Name, SamAccountName, Enabled, DistinguishedName -AutoSize
if ($OutputCsv) {
$users | Export-Csv -Path $OutputCsv -NoTypeInformation
Write-Host "Exported results to $OutputCsv" -ForegroundColor Green
}
By default this includes every sub-OU under the one you point it at — pass -DirectOnly if you specifically want just the users sitting directly in that OU, not any nested underneath it.
Getting the OU's distinguished name right
The most common failure mode here is a copy-pasted or slightly wrong distinguished name, which fails with "Directory object not found" rather than quietly returning nothing. If you're not sure of the exact DN, list your OUs first:
Get-ADOrganizationalUnit -Filter * | Select-Object Name, DistinguishedName
Or use Get-ADOrganizationalUnitsReport.ps1 from this same repo, which gives you that list plus object counts per OU.
Where the manual approach runs out of road
A one-off script is fine for a single check. It starts to hurt once you actually need to run this regularly:
- No scheduling. Cron/Task Scheduler can run the script, but now you own the scheduling, the credentials it runs as, and what happens when it silently fails.
- No history. A CSV export is a snapshot. Was this the same five accounts as last month, or a growing list? A single export can't tell you.
- No distribution. Getting the report to the right people (security, IT ops, compliance) on a schedule means building that plumbing yourself.
- Multi-domain/multi-forest pain. Run it once per domain, reconcile the results yourself, and hope naming/OU conventions are consistent across all of them.
- No alerting. If something changes unexpectedly between runs — an account re-enabled, a privileged group gaining a member — nothing tells you until you happen to run the script again.
None of that is a PowerShell problem. It's what turns a script into a product.
What SysFlint AD does instead
Our SysFlint AD runs the same kind of discovery shown above automatically, on a schedule, entirely inside your own network. No agents on domain controllers, no data leaving your environment. It's free, forever.
- Scheduled reports by email — Daily, weekly, or monthly runs delivered to the right inbox automatically. No Task Scheduler job for you to babysit.
- Multi-domain and forest coverage — Enumerate every domain in the forest in one pass and get one consolidated report instead of one per domain.
If you're currently doing this with a script on a scheduled task, here's the honest comparison between the two, or go straight to the download page.
Get this script, and the rest of them
The script above is part of awesome-it-scripts, SysFlint's free, open-source library of PowerShell scripts for Active Directory and other IT-admin tasks — no signup, no catch, MIT licensed. Grab this one directly from active-directory/Get-ADUsersInOU.ps1, or browse the whole thing.
Find every disabled/locked-out/stale/privileged-account script we've published (plus the FAQ that goes with each one) in the repo's active-directory folder. Star it if it's useful — new scripts land there regularly.