# Update-StaffAD.ps1 # Reads Staff_Extract.csv and updates AD email addresses and account status. # Matches users by sAMAccountName (PAYROLL_REC_NO column). # If duplicate entries exist, ACTV takes priority over INAC/LEFT. # Creates new AD accounts for ACTV users not found in AD. # Moves users to active/inactive OUs based on status. # Applies changes automatically and appends results to a log file. # # Usage: # .\Update-StaffAD.ps1 - Run normally, apply all changes # .\Update-StaffAD.ps1 -DryRun - Preview only, no changes made param( [switch]$DryRun ) # --- Configuration --- $CsvPath = "C:\Scripts\Staff_Extract.csv" $LogFile = "C:\Scripts\Logs\StaffAD_Changes.log" $NewUserOU = "OU=Teachers,OU=Staff,OU=Users,OU=5362-NiddrieAutistic,DC=curric,DC=niddrieautistic,DC=wan" $ActiveOU = "OU=Teachers,OU=Staff,OU=Users,OU=5362-NiddrieAutistic,DC=curric,DC=niddrieautistic,DC=wan" $InactiveOU = "OU=InactiveStaff,OU=5362-NiddrieAutistic,DC=curric,DC=niddrieautistic,DC=wan" $DefaultPassword = ConvertTo-SecureString "P@ssword123!" -AsPlainText -Force # Update this # --- Setup --- if (-not (Test-Path $CsvPath)) { Write-Error "CSV not found: $CsvPath" exit 1 } $LogDir = Split-Path $LogFile if (-not (Test-Path $LogDir)) { New-Item -ItemType Directory -Path $LogDir | Out-Null } $Staff = Import-Csv -Path $CsvPath $DisableStatuses = @("INAC", "LEFT") $RunHeader = "=" * 60 $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" function Write-Log { param([string]$Message, [string]$Color = "White") Write-Host $Message -ForegroundColor $Color if (-not $DryRun) { Add-Content -Path $LogFile -Value $Message } } # --- Deduplicate: ACTV wins over INAC/LEFT --- $Deduped = @{} foreach ($entry in $Staff) { $key = $entry.PAYROLL_REC_NO.Trim() if (-not $Deduped.ContainsKey($key)) { $Deduped[$key] = $entry } elseif ($entry.STAFF_STATUS.Trim() -eq "ACTV") { $Deduped[$key] = $entry } } # --- Run Header --- if ($DryRun) { Write-Host "" Write-Host $RunHeader -ForegroundColor Magenta Write-Host " DRY RUN - NO CHANGES WILL BE MADE" -ForegroundColor Magenta Write-Host " $Timestamp" -ForegroundColor Magenta Write-Host $RunHeader -ForegroundColor Magenta } else { Write-Log "" Write-Log $RunHeader Write-Log " RUN: $Timestamp" Write-Log $RunHeader } $emailUpdates = 0 $disables = 0 $noChanges = 0 $notFound = 0 $created = 0 $moved = 0 $notFoundList = @() foreach ($entry in $Deduped.Values) { $samAccount = $entry.PAYROLL_REC_NO.Trim() $status = $entry.STAFF_STATUS.Trim() $email = $entry.E_MAIL.Trim() # Parse name from email $firstName = "Unknown" $lastName = "Unknown" if ($email -match "^([^.]+)\.([^@]+)@") { $firstName = $Matches[1] $lastName = $Matches[2] } $displayName = "$firstName $lastName" # Find user in AD by sAMAccountName try { $adUser = Get-ADUser -Identity $samAccount ` -Properties EmailAddress, Enabled, DisplayName, DistinguishedName ` -ErrorAction Stop } catch { # Not found in AD - create if ACTV, otherwise log and skip if ($status -ne "ACTV") { $notFound++ $notFoundList += "$samAccount, $displayName (skipped - status: $status)" continue } Write-Log "" Write-Log " User : $displayName ($samAccount)" Write-Log " Status : $status" if ($DryRun) { Write-Log " Account : WOULD BE CREATED in $NewUserOU" "Magenta" Write-Log " Email : $email [WOULD BE SET]" "Magenta" } else { try { New-ADUser ` -SamAccountName $samAccount ` -UserPrincipalName $email ` -GivenName $firstName ` -Surname $lastName ` -DisplayName $displayName ` -Name $displayName ` -EmailAddress $email ` -AccountPassword $DefaultPassword ` -Enabled $true ` -Path $NewUserOU Write-Log " Account : CREATED in $NewUserOU [CREATED]" "Green" Write-Log " Email : $email [SET]" "Green" } catch { Write-Log " Account : FAILED to create - $_" "Red" } } $created++ continue } $willDisable = ($status -in $DisableStatuses) -and $adUser.Enabled $willUpdateEmail = ($adUser.EmailAddress -ne $email) # Determine OU move $currentOU = ($adUser.DistinguishedName -replace '^CN=[^,]+,', '') $targetOU = if ($status -in $DisableStatuses) { $InactiveOU } else { $ActiveOU } $willMove = ($currentOU -ne $targetOU) if (-not $willDisable -and -not $willUpdateEmail -and -not $willMove) { $noChanges++ continue } Write-Log "" Write-Log " User : $($adUser.DisplayName) ($samAccount)" Write-Log " Status : $status" # Update email if ($willUpdateEmail) { if ($DryRun) { Write-Log " Email : $($adUser.EmailAddress) --> $email [WOULD UPDATE]" "Magenta" } else { try { Set-ADUser -Identity $samAccount -EmailAddress $email Write-Log " Email : $($adUser.EmailAddress) --> $email [UPDATED]" "Green" $emailUpdates++ } catch { Write-Log " Email : FAILED to update - $_" "Red" } } if ($DryRun) { $emailUpdates++ } } # Disable account if ($willDisable) { if ($DryRun) { Write-Log " Account : WOULD BE DISABLED (status: $status)" "Magenta" } else { try { Disable-ADAccount -Identity $samAccount Write-Log " Account : DISABLED (status: $status) [UPDATED]" "Green" $disables++ } catch { Write-Log " Account : FAILED to disable - $_" "Red" } } if ($DryRun) { $disables++ } } # Move user to correct OU if ($willMove) { if ($DryRun) { Write-Log " OU Move : WOULD MOVE to $targetOU" "Magenta" } else { try { Move-ADObject -Identity $adUser.DistinguishedName -TargetPath $targetOU Write-Log " OU Move : MOVED to $targetOU [MOVED]" "Green" $moved++ } catch { Write-Log " OU Move : FAILED to move - $_" "Red" } } if ($DryRun) { $moved++ } } } # --- Summary --- Write-Log "" Write-Log " --- Summary $(if ($DryRun) { '(DRY RUN)' }) ---" if ($emailUpdates -eq 0 -and $disables -eq 0 -and $created -eq 0 -and $moved -eq 0) { Write-Log " No changes $(if ($DryRun) { 'would be' } else { 'were' }) made on this run." "Cyan" } Write-Log " Accounts $(if ($DryRun) { 'to create ' } else { 'created ' }): $created" Write-Log " Email updates : $emailUpdates" Write-Log " Accounts disabled : $disables" Write-Log " OU moves : $moved" Write-Log " No changes needed : $noChanges" Write-Log " Not found in AD : $notFound" if ($notFoundList.Count -gt 0) { foreach ($missing in $notFoundList) { Write-Log " - $missing" "Yellow" } } Write-Log $RunHeader Write-Log ""