Export Active Directory Users from an OU to CSV
Export all user accounts in a specific Active Directory OU to CSV (name, UPN, distinguished name and mail) with Get-ADUser, scoped to one search base for fast, targeted inventories.
by Emanuel De Almeida
TL;DR
- Exports all users in a given Active Directory OU to a CSV under C:\Temp\Export.
- Returns name, UPN, distinguished name and primary mail per user.
- Uses Get-ADUser with a search base scoped to one OU, so it is fast and targeted.
- Needs the ActiveDirectory module (RSAT) and read access to the OU.
- Handy for audits, migrations and building mailing lists.
What does this script do?
It queries one organizational unit with Get-ADUser, selects a small set of useful attributes, and writes them to a CSV, one row per user. Logging and folder creation are handled for you, so it is safe to schedule or hand to a junior admin.
When is this useful?
- Pre-migration inventories before a tenant or domain move.
- Access reviews and audits scoped to a department's OU.
- Generating distribution or contact lists from a known OU.
What do you need before running it?
- PowerShell 5.1 or later.
- The ActiveDirectory module (part of RSAT) on the machine running the script.
- Read access to the target OU and its user objects.
Install the AD module on a workstation if needed:
Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0How do you find the OU distinguished name?
List your OUs and copy the distinguished name of the one you want to export:
Get-ADOrganizationalUnit -Filter * | Select-Object Name, DistinguishedNameHow do you run the script?
Set $Organization_Unit to your OU's distinguished name, then run it:
.\Export-ADUsers.ps1The export is written to C:\Temp\Export\Export_Users.csv with a log under C:\Temp\Log.
How do you customise the exported fields?
Add any AD attribute to the $Properties array at the top of the script. For example, to include the department and creation date, add 'Department' and 'whenCreated'. The same names drive both the query and the CSV columns, so one edit changes both.
FAQ
Does this modify Active Directory?
No. It is read-only: it queries users and writes a CSV. It never edits, disables or deletes accounts.
Why scope to an OU instead of the whole domain?
Scoping to a search base keeps the query fast and the output relevant. To export the whole directory, point the search base at the domain root, though large directories are better paged or filtered.
The script returns no users. Why?
Check that the distinguished name is exact (including the DC components) and that your account can read that OU. An empty or mistyped search base returns nothing rather than an error.
The script
#Requires -Version 5.1
#Requires -Modules ActiveDirectory
<#
.SYNOPSIS
Exports every user account in a specific Active Directory OU to a CSV file.
.DESCRIPTION
Reads all user objects under the given organizational unit with Get-ADUser
and writes their name, user principal name, distinguished name and primary
mail address to a CSV. Logs and the export are written under C:\Temp.
Set $Organization_Unit to the distinguished name of the OU you want to
export. Add or remove fields in $Properties to change the columns.
.NOTES
Author : Emanuel De Almeida - https://www.navanem.com
Version: 1.0
#>
$Global:ErrorActionPreference = 'Stop'
# Organizational unit to export (set to your OU's distinguished name)
$Organization_Unit = 'OU=Staff,DC=contoso,DC=com'
# Properties to read and export
$Properties = @(
'Name',
'UserPrincipalName',
'distinguishedName',
'mail'
)
# Log helper
Function Write-Log {
Param(
[Parameter(Mandatory = $true)][String]$Message,
[Parameter(Mandatory = $true)][String]$Type
)
$Date = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
"$Date - $Type - $Message" |
Out-File -FilePath "C:\Temp\Log\$(Get-Date -Format 'yyyy-MM-dd').log" -Append -Encoding UTF8
}
# Make sure the output folders exist
Function CheckFilePath {
If (-not (Test-Path -Path 'C:\Temp\Log')) { New-Item 'C:\Temp\Log' -ItemType Directory | Out-Null }
If (-not (Test-Path -Path 'C:\Temp\Export')) { New-Item 'C:\Temp\Export' -ItemType Directory | Out-Null }
}
CheckFilePath
Try {
Write-Log -Message 'Collecting all users' -Type 'Information'
$Users = Get-ADUser -SearchBase $Organization_Unit -Filter * -Properties $Properties |
Select-Object $Properties
Write-Log -Message "Collected $($Users.Count) users" -Type 'Success'
} Catch {
Write-Host "`n`t$($_.InvocationInfo.InvocationName) [Line:$($_.InvocationInfo.ScriptLineNumber)]: $($_.Exception.Message)" -ForegroundColor Yellow
Write-Log -Message "$($_.InvocationInfo.InvocationName) [Line:$($_.InvocationInfo.ScriptLineNumber)]: $($_.Exception.Message)" -Type 'Error'
Write-Log -Message 'Unable to collect users' -Type 'Error'
Break
}
Try {
Write-Log -Message 'Exporting user information' -Type 'Information'
Foreach ($User in $Users) {
[PSCustomObject][Ordered]@{
'Name' = $User.Name
'UserPrincipalName' = $User.UserPrincipalName
'distinguishedName' = $User.distinguishedName
'mail' = $User.mail
} | Export-Csv -Path 'C:\Temp\Export\Export_Users.csv' -Delimiter ',' -Encoding UTF8 -NoTypeInformation -Append -Force
}
Write-Log -Message 'User information exported' -Type 'Success'
} Catch {
Write-Host "`n`t$($_.InvocationInfo.InvocationName) [Line:$($_.InvocationInfo.ScriptLineNumber)]: $($_.Exception.Message)" -ForegroundColor Yellow
Write-Log -Message "$($_.InvocationInfo.InvocationName) [Line:$($_.InvocationInfo.ScriptLineNumber)]: $($_.Exception.Message)" -Type 'Error'
Write-Log -Message 'Unable to export users' -Type 'Error'
}
Review before running. Test in a non-production environment first.