Systems Admin

Create Active Directory Users from CSV with PowerShell

Introduction

You need to create new Active Directory users in your organization. For one or two accounts the user-creation wizard in Active Directory Users and Computers (ADUC) is fine; for ten it is annoying; for a thousand it is genuinely unworkable. If a single new user takes one minute in the wizard, a thousand new users is roughly 16 hours of clicking — an entire workday plus overtime spent on something a script could finish in seconds.

In this article you will learn how to create Active Directory users in bulk from a CSV file using PowerShell. You will design a CSV template, hand it to HR (or whoever owns the user data), generate strong passwords, fill in the destination OU, and run a single script that walks every row, splats the parameters, and calls New-ADUser with a duplicate-check and proper error handling.

Files Used in This Workflow

The walkthrough uses four files. They are not magic — they just keep the workflow auditable so you can hand any of them to a colleague and explain what each one is for:

File Purpose
NewUsersSent.csv The empty template you sent to the requester.
NewUsersReceived.csv The filled-in version they returned.
NewUsersFinal.csv The final version with passwords and OU added by IT, ready to import.
Add-NewUsers.ps1 The PowerShell script that reads the CSV and creates the accounts.

Step 1 — Create the CSV Template

Build a CSV with one column per AD attribute you want to populate. At minimum you need FirstName and Lastname — everything else is recoverable later, but those two are the basis of the username, the display name, and the email. A practical column set looks like:

FirstName,Initials,Lastname,Username,Email,StreetAddress,City,ZipCode,
State,Country,Department,JobTitle,Telephone,Password,OU,Company

Send this empty file (NewUsersSent.csv) to the requester — for a typical hiring batch this is HR. Tell them:

  • Fill in as much as possible — even the optional columns (Department, JobTitle, Telephone, Country) are useful for downstream filters and group memberships.
  • Leave the Password column empty. IT will generate strong passwords centrally; HR should never be choosing or transmitting passwords.
  • Leave the OU column empty. The Organizational Unit is an IT-side decision (it controls which GPOs and group memberships apply to the new users) and the value depends on your AD structure.
Microsoft Excel showing the empty NewUsersSent.csv template open with the header row containing the columns FirstName, Initials, Lastname, Username, Email, StreetAddress, City, ZipCode, State, Country, Department, JobTitle, Telephone, Password, OU, and Company - all data rows below are blank ready for HR to fill in
Step 1: create a CSV template with all the AD attributes you need (FirstName, Lastname, Username, Email, OU, etc.) and send it to the requester

Step 2 — Receive the Filled CSV

The requester returns NewUsersReceived.csv with the user data populated. Open it and sanity-check that the rows look right — the most common HR mistakes are typos in usernames, missing initials, and email addresses that conflict with existing accounts. Catch them now; fixing them after the import means deleting and recreating accounts.

Generate Passwords

Generate one strong password per user and paste them into the Password column. Any password generator with bulk output works; the article uses the free Manytools password generator, which can produce up to 9,999 passwords at a time. Pick a length and complexity that match your password policy — 16 characters with all four character classes is a sensible default.

The script flips ChangePasswordAtLogon to $True so the password you set is a one-time value: the user must change it the first time they sign in. That means you do not have to memorize or transmit each password securely — you generate them, store them in a password manager, and hand them to the user via the same secure channel you would use for any one-time secret.

Two screenshots: NewUsersReceived.csv open in Excel filled in by HR with ten user rows showing all attribute columns populated except Password and OU, and below it the Excel sheet again with the Password column being filled in from the Manytools.org password generator
After HR returns the CSV with all the user data filled in, generate strong passwords (Manytools allows up to 9999 at once) and paste them into the Password column

Step 3 — Fill in the Destination OU

Decide where the new accounts will live in AD. In this example HR is hiring for the IT department, so the target is OU=IT,OU=Users,OU=Company,DC=exoip,DC=local — the IT OU under Company > Users in the exoip.local domain.

Find the OU’s distinguishedName

To get the exact distinguishedName string the script needs:

  1. Open Active Directory Users and Computers.
  2. Click the View menu and enable Advanced Features. Without this, the Attribute Editor tab is hidden on Properties dialogs.
  3. Navigate to or create the target OU (here IT under Company > Users). To create it, right-click the parent OU and choose New > Organizational Unit.
  4. Right-click the OU and choose Properties.
  5. Click the Attribute Editor tab.
  6. Find the distinguishedName attribute, double-click it, and copy the full value.
Two screenshots from Active Directory Users and Computers (ADUC) on Windows Server: the View menu showing the Advanced Features option enabled, with the IT OU now visible inside Company > Users in the tree, and below it the Properties dialog of the IT OU with the Attribute Editor tab selected showing the distinguishedName attribute being copied (value: OU=IT,OU=Users,OU=Company,DC=exoip,DC=local)
Enable Advanced Features in ADUC, create the target OU (here OU=IT), then open its Properties > Attribute Editor and copy the distinguishedName for the OU column in the CSV

Paste the copied distinguishedName into the OU column for every row in the CSV. If different users go to different OUs (for example, sales hires into OU=Sales and IT hires into OU=IT), put each row’s correct OU in its own cell.

Save the Final CSV

Once both the Password and OU columns are filled in, save the workbook as NewUsersFinal.csv. Use File > Save As, name it NewUsersFinal, and choose CSV UTF-8 (Comma delimited) (*.csv) as the type. UTF-8 matters — without it, accented characters in names (e.g. José, Müller) round-trip as question marks.

Two screenshots: Excel showing NewUsersReceived.csv with the OU column now filled in for every row using the copied distinguishedName value highlighted in yellow, and below it the Excel Save As dialog showing the filename being changed to NewUsersFinal and the Save as type dropdown set to CSV UTF-8 (Comma delimited) (*.csv)
Paste the OU’s distinguishedName into the OU column for every row, then Save As NewUsersFinal.csv with the type CSV UTF-8 (Comma delimited)

Copy NewUsersFinal.csv to C:\Temp\ on the Domain Controller (or whichever management server has the AD PowerShell module installed and a network path to a DC).

Step 4 — Sanity-Check the CSV in PowerShell

Before running the import script, prove the CSV parses correctly. Open an elevated PowerShell window and run:

Import-Csv "C:\Temp\NewUsersFinal.csv" -Delimiter ";" | Format-Table

Comma vs Semicolon Delimiter

Excel on a system with European locale settings often saves CSVs with a semicolon separator instead of a comma, even when you choose “CSV (Comma delimited).” If Format-Table shows every row in a single column, the file is using a different delimiter than your -Delimiter argument expects. Try the other separator:

# If the file uses commas
Import-Csv "C:\Temp\NewUsersFinal.csv" | Format-Table

# If the file uses semicolons
Import-Csv "C:\Temp\NewUsersFinal.csv" -Delimiter ";" | Format-Table

Whichever one returns a clean table is the one the script needs to use as well. Note the choice now — you will set it in the script in the next step.

A correct table looks like this:

FirstName Initials Lastname Username   Email                  StreetAddress City   ZipCode State Country
--------- -------- -------- --------   -----                  ------------- ----   ------- ----- -------
Max       MF       Fraser   Max.Fraser Max.Fraser@exoip.com   21 Baker St   London NW1 6XE       GB
Piers     PB       Bower    Piers.Bower Piers.Bower@exoip.com 21 Baker St   London NW1 6XE       GB
...
PowerShell window running Import-Csv 'C:\Temp\NewUsersFinal.csv' -Delimiter ';' | Format-Table showing the imported CSV in tabular form with all the user attributes populated correctly for all ten users
Import the final CSV with Import-Csv | Format-Table to verify it parses correctly. If columns look squashed into one cell, try removing or adding the -Delimiter parameter

Step 5 — The Add-NewUsers.ps1 Script

The script reads the CSV row-by-row and creates an AD user from each row. It uses PowerShell splatting (a hashtable named @UserParams) so the long list of New-ADUser parameters stays readable, a duplicate check with Get-ADUser -Filter so a re-run does not error on accounts that already exist, and a try/catch wrapper so a single bad row does not abort the whole import.

<#
.SYNOPSIS
  Add-NewUsers.ps1
.DESCRIPTION
  Create Active Directory users from CSV file.
#>

# Import the AD module so New-ADUser is available
Import-Module ActiveDirectory

# Read the CSV (adjust -Delimiter to match your file)
$ADUsers = Import-Csv "C:\Temp\NewUsersFinal.csv" -Delimiter ";"

# UPN suffix that gets appended to every Username
$UPN = "exoip.com"

foreach ($User in $ADUsers) {
    try {
        $UserParams = @{
            SamAccountName        = $User.username
            UserPrincipalName     = "$($User.username)@$UPN"
            Name                  = "$($User.firstname) $($User.lastname)"
            GivenName             = $User.firstname
            Surname               = $User.lastname
            Initial               = $User.initials
            Enabled               = $True
            DisplayName           = "$($User.firstname) $($User.lastname)"
            Path                  = $User.ou
            City                  = $User.city
            PostalCode            = $User.zipcode
            Country               = $User.country
            Company               = $User.company
            State                 = $User.state
            StreetAddress         = $User.streetaddress
            OfficePhone           = $User.telephone
            EmailAddress          = $User.email
            Title                 = $User.jobtitle
            Department            = $User.department
            AccountPassword       = (ConvertTo-SecureString $User.password -AsPlainText -Force)
            ChangePasswordAtLogon = $True
        }

        if (Get-ADUser -Filter "SamAccountName -eq '$($User.username)'") {
            Write-Host "A user with username $($User.username) already exists in Active Directory." -ForegroundColor Yellow
        }
        else {
            New-ADUser @UserParams
            Write-Host "The user $($User.username) is created." -ForegroundColor Green
        }
    }
    catch {
        Write-Host "Failed to create user $($User.username) - $_" -ForegroundColor Red
    }
}
Top half of the Add-NewUsers.ps1 script source displayed in a dark-themed editor showing the comment-based help block, Import-Module ActiveDirectory, Import-Csv with -Delimiter, the UPN definition, and the start of the foreach loop with the splatting hashtable for UserParams
The Add-NewUsers.ps1 script (top half): import the CSV, define a UPN, and start a foreach loop that builds a UserParams hashtable for splatting into New-ADUser
Bottom half of the Add-NewUsers.ps1 script showing the rest of the UserParams hashtable, the Get-ADUser duplicate-check, the New-ADUser call, and a try/catch error handler. Below it a black PowerShell terminal showing the script running with green output 'The user Max.Fraser is created.', etc.
The script’s bottom half: complete the splat hashtable, check for an existing SamAccountName, call New-ADUser @UserParams, and a try/catch turns failures into a red one-liner

Three Lines You Must Adapt

  1. Import-Csv "C:\Temp\NewUsersFinal.csv" — change the path if the CSV lives somewhere else on your management server.
  2. -Delimiter ";" — remove this argument if your CSV uses commas (the default), or keep it if Excel saved it with semicolons.
  3. $UPN = "exoip.com" — change to your domain’s UPN suffix. This is what gets appended to username to form username@yourdomain.com.

Step 6 — Run the Script and Verify

Save the script to C:\Scripts\Add-NewUsers.ps1 on the Domain Controller or management server, open PowerShell as administrator, and run it:

C:\Scripts\.\Add-NewUsers.ps1

For a clean import, every row produces a green confirmation:

The user Max.Fraser is created.
The user Piers.Bower is created.
The user Kylie.Davidson is created.
The user Richard.Grant is created.
...

If you re-run the script (or accidentally hand it the same CSV twice), the duplicate check kicks in and you get yellow warnings instead of errors:

A user with username Max.Fraser already exists in Active Directory.
A user with username Piers.Bower already exists in Active Directory.
...

If a row has a bad value (for example, a malformed OU, a UPN collision, or a password that fails policy), the try/catch traps it and prints a red line for that user only:

Failed to create user Bad.User - The password does not meet the length, complexity, or history requirements of the domain.

The rest of the import continues normally. This is by design — you almost never want a 999-row CSV to halt because row 47 had a typo.

Open Active Directory Users and Computers and browse to the target OU. The new accounts should be visible there with the data you imported — first/last name, email, department, etc. Right-click any account and choose Properties > Account to confirm the User logon name (UPN), and Account > User must change password at next logon should be ticked.

Two screenshots: PowerShell terminal output showing all ten users being created (green) on the first run, then a yellow re-run showing 'A user with username Max.Fraser already exists in Active Directory.' for each row, and below it Active Directory Users and Computers showing the IT OU now contains the ten new user accounts
First run creates every user (green); re-running shows the duplicate-check guard (yellow). The new users now appear inside the target OU in ADUC

Operational Notes

  • Pre-flight in a lab. The first time you run this against a CSV in production, do a dry run in a test domain or against a single row first. CSV columns and OU paths are easy to mis-spell, and a clean test eliminates 99% of import failures before they happen.
  • Hand passwords over securely. Even though every account requires a change at first logon, the initial password is still a sensitive value. Use a password manager that supports per-recipient sharing (1Password, Bitwarden), not email or Slack.
  • License and group memberships. The script creates the AD object only. Microsoft 365 license assignment, security-group membership, distribution-list membership, and home-folder creation are usually separate follow-up steps. Add them to the script (or a companion script that runs after this one) once the basic import is reliable.
  • UPN must match a verified domain. If you use Microsoft Entra Connect to sync to Microsoft 365, make sure the UPN suffix you assign here is in your list of verified domains in Entra. Otherwise the user will sync but cannot sign in to cloud services.
  • Audit log. Every New-ADUser creation is logged on the DC under the Directory Service event log; for a real audit trail consider adding Start-Transcript/Stop-Transcript around the script so you have a written record of which CSV row mapped to which AD object on which date.

Conclusion

You learned how to bulk-create Active Directory users from a CSV with PowerShell. The complete recipe is:

  1. Design a CSV template with all the AD attributes you want populated.
  2. Hand it to the data owner (HR, hiring manager) with explicit instructions to leave Password and OU empty.
  3. Generate strong passwords centrally in IT and paste them into the Password column.
  4. Find the target OU’s distinguishedName via Advanced Features > Properties > Attribute Editor and paste it into the OU column.
  5. Save as NewUsersFinal.csv with UTF-8 encoding.
  6. Sanity-check the CSV with Import-Csv | Format-Table in PowerShell.
  7. Run Add-NewUsers.ps1 on a DC or management server.
  8. Verify the new accounts in ADUC.

Sixteen hours of clicking turns into about thirty seconds of script time, and the audit trail is a CSV in version control instead of a chain of help-desk tickets.

Leave a Reply