PowerShell User Onboarding Script: Automate New Employee Setup

PowerShell User Onboarding Script: Automate New Employee Setup

PowerShell Tips Editor 2 min read
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-Mailbox in an Exchange Management Shell session, which is separate from the AD module session.
  • Password generation must meet complexity requirements. The New-SecurePassword function 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 $Length parameter 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.

Send-Item -To