PowerShell Onboarding Scripts in a Hybrid AD-Azure Environment
Title: PowerShell Onboarding Scripts in a Hybrid AD-Azure Environment
Date: 2024-10-27
Tags: IT Support, Automation, Active Directory, PowerShell, Azure AD, Onboarding
I. Introduction
1.1 Context & Purpose
- Manual onboarding for new hires (creating AD accounts, assigning licenses, setting up home drives) was error-prone and took ~45 minutes per user.
- Developed a PowerShell script to automate 90% of the process, ensuring consistency and freeing up L2/L3 time for more complex tasks.
1.2 What This Covers
- The logic and structure of the main automation script.
- Integration with on-prem Active Directory and Azure AD Connect.
- Error handling and logging for support team visibility.
II. Setup & Environment
2.1 Network & Tools Overview
- Domain Controller: Windows Server 2019 (On-prem)
- Sync Tool: Azure AD Connect (v2.x)
- Client: Administrative workstation with RSAT and AzureAD module.
- Script Location:
\\fileserver\IT\Scripts\Automation\Onboarding
2.2 Prerequisites / Preparations
- Pre-populated CSV template from HR (
newhires_YYYYMMDD.csv) in a secure share. - Pre-defined AD security groups (
Staff-Office,Staff-Remote,Department-*). - Available Microsoft 365 licenses in the tenant.
III. Execution & Findings
3.1 Steps Taken
- Script Trigger: Manual run from secure IT workstation after HR notification.
.\Start-NewHireOnboarding.ps1 -CsvPath "\\hrserver\secure\newhires_20241027.csv" - Core Script Logic (Abridged):
# 1. Import CSV and validate data $NewHires = Import-Csv $CsvPath foreach ($User in $NewHires) { # 2. Generate username (first.last) and check for duplicates $SamAccountName = "$($User.FirstName).$($User.LastName)".ToLower() # 3. Create AD User Account $Password = ConvertTo-SecureString -String (New-ComplexPassword) -AsPlainText -Force New-ADUser -Name "$($User.FirstName) $($User.LastName)" ` -SamAccountName $SamAccountName ` -UserPrincipalName "$SamAccountName@corp.example.com" ` -AccountPassword $Password ` -Enabled $true ` -Path "OU=Users,DC=corp,DC=example,DC=com" ` -OtherAttributes @{title=$User.JobTitle; department=$User.Department} # 4. Add to Security Groups based on Department/Location Add-ADGroupMember -Identity "Department-$($User.Department)" -Members $SamAccountName Add-ADGroupMember -Identity "Location-$($User.Location)" -Members $SamAccountName # 5. Create Home Drive and set permissions $HomeDrivePath = "\\fileserver\homes\$SamAccountName" New-Item -Path $HomeDrivePath -ItemType Directory icacls $HomeDrivePath /grant "$($env:USERDOMAIN)\$SamAccountName`:(OI)(CI)F" # 6. Wait for AD Connect sync, then assign M365 license Start-Sleep -Seconds 180 Connect-AzureAD $License = Get-AzureADSubscribedSku | Where-Object {$_.SkuPartNumber -eq "ENTERPRISEPACK"} Set-AzureADUserLicense -ObjectId "$SamAccountName@corp.example.com" ` -AssignedLicenses @{SkuId = $License.SkuId} # 7. Log all actions Write-Log -Message "Created user: $SamAccountName" -Level INFO }
3.2 Challenges & Fixes
- Challenge: Azure AD Connect sync delay caused "user not found" errors when trying to assign licenses immediately.
# ERROR: Set-AzureADUserLicense : Error occurred while executing SetUserLicenses # Code: Request_ResourceNotFound - Fix: Added a
Start-Sleep -Seconds 180wait and implemented a retry loop that checks Azure AD for user existence before proceeding.$RetryCount = 0 do { Start-Sleep -Seconds 30 $AzureUser = Get-AzureADUser -Filter "userPrincipalName eq '$UPN'" $RetryCount++ } while ($null -eq $AzureUser -and $RetryCount -lt 10) - Challenge: HR CSV sometimes had missing department data.
- Fix: Added validation logic that sends an alert to the IT ticket system and skips that user, rather than failing the entire batch.
if ([string]::IsNullOrWhiteSpace($User.Department)) { Write-Log -Message "Missing department for $($User.Email). Creating ticket." -Level WARN New-ServiceNowTicket -ShortDescription "Onboarding Data Issue" -Description "User missing department" continue }
IV. Observations & Insights
- Time Saved: Reduced manual work from 45 to ~5 minutes (just verification). Batch of 10 users now takes 20 minutes instead of 7.5 hours.
- Error Reduction: Zero typos in usernames or group assignments since implementation.
- Unexpected Benefit: The detailed log file (
Onboarding_20241027.log) became invaluable for auditing and proving compliance during internal audits.
V. Considerations & Next Steps
- Integrate with HR System: Next phase is to call the HRIS API directly instead of using CSV files.
- Self-Service Portal: Build a web front-end where managers can trigger onboarding for contractors with pre-approved templates.
- Offboarding Script: Build the counterpart script that disables accounts, archives data, and reclaims licenses with the same rigor.
VI. Conclusion
- Automation in IT support isn't about replacing people; it's about eliminating repetitive, low-value tasks that are prone to human error.
- This script paid for itself in time savings within the first month of use and significantly improved the new hire experience (everything was ready at 9 AM on day one).
- The key to success was robust error handling and comprehensive logging—the script needed to fail gracefully and tell us exactly why.
