PowerShell User Onboarding Script: Automate New Employee Setup

New employee IT onboarding involves creating an Active Directory account, assigning the right security groups, setting up a mailbox, generating a secure password, and emailing credentials — typically a 20-30 minute checklist per person. A PowerShell user onboarding automation script turns that into a 30-second operation that executes identically every time, catches nothing through the cracks, and gives the manager credentials before they finish their morning coffee. This post builds the complete onboarding script from CSV input to welcome email.
Input: Read New User Data from CSV
A simple CSV template lets HR or management submit new hire details without touching PowerShell. Define the expected columns and validate input before doing any AD operations:
#Requires -Modules ActiveDirectory
$ErrorActionPreference = 'Stop'
$csvPath = "C:\HR\NewHires.csv"
$users = Import-Csv -Path $csvPath
# Validate required columns
$required = @('FirstName','LastName','Department','Title','Manager','OU')
$missing = $required | Where-Object { $_ -notin $users[0].PSObject.Properties.Name }
if ($missing) { throw "CSV missing required columns: $($missing -join ', ')" }
Write-Host "Processing $($users.Count) new hire(s)..."
A minimal CSV looks like:
FirstName,LastName,Department,Title,Manager,OU
Jane,Smith,Finance,Analyst,jdoe,OU=Finance,OU=Users,DC=corp,DC=local
Create AD User Account
Build the user attributes from the CSV row and call New-ADUser. Generate the username from first initial + last name, checking for collisions:
foreach ($hire in $users) {
$baseUsername = ($hire.FirstName.Substring(0,1) + $hire.LastName).ToLower() -replace '[^a-z0-9]',''
$username = $baseUsername
$counter = 1
while (Get-ADUser -Filter "SamAccountName -eq '$username'" -ErrorAction SilentlyContinue) {
$username = "$baseUsername$counter"
$counter++
}
$upn = "[email protected]"
New-ADUser -Name "$($hire.FirstName) $($hire.LastName)" `
-GivenName $hire.FirstName `
-Surname $hire.LastName `
-SamAccountName $username `
-UserPrincipalName $upn `
-Department $hire.Department `
-Title $hire.Title `
-Manager $hire.Manager `
-Path $hire.OU `
-Enabled $true `
-ChangePasswordAtLogon $true
Write-Host "Created AD account: $username ($upn)"
Add to Security and Distribution Groups
Add the new user to standard groups based on their department. Maintain a department-to-groups mapping in the script for consistent provisioning:
# Department group mapping
$groupMap = @{
'Finance' = @('Finance-Staff', 'Finance-Drive', 'AllStaff-DL')
'IT' = @('IT-Staff', 'IT-Systems', 'AllStaff-DL')
'HR' = @('HR-Staff', 'HR-Confidential', 'AllStaff-DL')
}
$groups = $groupMap[$hire.Department]
if (-not $groups) { $groups = @('AllStaff-DL') }
foreach ($group in $groups) {
Add-ADGroupMember -Identity $group -Members $username -ErrorAction SilentlyContinue
Write-Host " Added to group: $group"
}
Generate Secure Random Password
Create a random password that meets typical AD complexity requirements (uppercase, lowercase, number, special character, minimum 12 characters):
function New-SecurePassword {
param([int]$Length = 14)
$upper = 'ABCDEFGHJKLMNPQRSTUVWXYZ'
$lower = 'abcdefghjkmnpqrstuvwxyz'
$digits = '23456789'
$special = '!@#$%^&*'
$all = $upper + $lower + $digits + $special
# Guarantee at least one of each required type
$pwd = (Get-Random -InputObject ($upper.ToCharArray())) `
+ (Get-Random -InputObject ($lower.ToCharArray())) `
+ (Get-Random -InputObject ($digits.ToCharArray())) `
+ (Get-Random -InputObject ($special.ToCharArray()))
# Fill remaining length from full set
$pwd += -join (1..($Length - 4) | ForEach-Object { Get-Random -InputObject ($all.ToCharArray()) })
# Shuffle the characters
-join ($pwd.ToCharArray() | Sort-Object { Get-Random })
}
$plainPassword = New-SecurePassword -Length 14
$securePassword = ConvertTo-SecureString $plainPassword -AsPlainText -Force
Set-ADAccountPassword -Identity $username -NewPassword $securePassword -Reset
Write-Host " Password set"
Create Exchange Mailbox
For Exchange Online, mailboxes are created automatically when the user is licensed in M365. For on-premises Exchange, call Enable-Mailbox:
# On-premises Exchange — run in Exchange Management Shell or via Invoke-Command
# Enable-Mailbox -Identity $username -Database "Mailbox Database 01"
# Exchange Online via Graph API — assign M365 license (simplified)
# (Requires Microsoft.Graph module or direct Graph REST calls)
Write-Host " Note: Assign M365 license in admin portal to provision mailbox"
Send Welcome Email with Credentials
Email the manager (not the new user — they cannot log in yet) with credentials and the first-day IT checklist:
$body = @"
New account created for $($hire.FirstName) $($hire.LastName)
Username: $username
Email: $upn
Temp Password: $plainPassword (must be changed at first login)
Groups: $($groups -join ', ')
Please share these credentials securely with the new employee.
"@
Send-MailMessage -From "[email protected]" -To "$($hire.Manager)@corp.com" `
-Subject "New Account: $($hire.FirstName) $($hire.LastName)" `
-Body $body -SmtpServer "smtp-relay.corp.com"
Write-Host " Welcome email sent to $($hire.Manager)"
} # end foreach
Common Errors and Fixes
-
Mailbox creation requires Exchange Online or on-prem Exchange access. Mailboxes in Exchange Online are provisioned by assigning an M365 license, not by a cmdlet. For on-premises Exchange, you must run
Enable-Mailboxin an Exchange Management Shell session, which is separate from the AD module session. -
Password generation must meet complexity requirements. The
New-SecurePasswordfunction guarantees at least one character from each required class before shuffling. If your domain has a Fine-Grained Password Policy with a longer minimum length, update the$Lengthparameter default accordingly.
Related Cmdlets / See Also
Wrapping Up
A complete onboarding script eliminates manual steps, ensures consistent group assignments, generates policy-compliant passwords, and delivers credentials securely. Build it against your real OU structure and group map, test with a pilot user account first, and hand the CSV template to HR so they can trigger onboarding with no IT manual effort.


