Public/Disable-DepartedUser.ps1
|
function Disable-DepartedUser { <# .SYNOPSIS Offboards a departed employee by disabling and archiving their AD account. .DESCRIPTION Performs a complete employee offboarding workflow: 1. Disables the AD account 2. Resets the password to a random complex value 3. Removes all group memberships (logging them first) 4. Moves the account to a designated Disabled Users OU 5. Archives the user's home folder (compress to zip) 6. Updates the account description with termination date and operator 7. Hides from the Global Address List (if Exchange attributes present) All actions are logged to a transcript file for audit purposes. .PARAMETER Identity The SAMAccountName of the user to offboard. .PARAMETER DisabledOU The Distinguished Name of the OU to move disabled accounts to. Example: "OU=Disabled Users,DC=contoso,DC=com" .PARAMETER ArchivePath The UNC or local path to archive the user's home folder to. A subfolder named LastName-FirstName-Date will be created. .PARAMETER SkipHomeFolder Skip the home folder archival step. .PARAMETER LogPath Directory for transcript logs. Defaults to .\Logs. .EXAMPLE Disable-DepartedUser -Identity "jsmith" -DisabledOU "OU=Disabled Users,DC=contoso,DC=com" -ArchivePath "\\fileserver\archives" Fully offboards jsmith with home folder archival. .EXAMPLE Disable-DepartedUser -Identity "jsmith" -DisabledOU "OU=Disabled Users,DC=contoso,DC=com" -SkipHomeFolder -WhatIf Shows what the offboarding would do without making changes. .EXAMPLE Import-Csv ".\Terminations.csv" | ForEach-Object { Disable-DepartedUser -Identity $_.SAMAccountName -DisabledOU "OU=Disabled,DC=contoso,DC=com" -ArchivePath "\\server\archive" } Bulk offboard from a CSV. .NOTES Requires: ActiveDirectory module, write access to the Disabled OU and archive path. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('SAMAccountName')] [ValidateNotNullOrEmpty()] [string]$Identity, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$DisabledOU, [Parameter()] [string]$ArchivePath, [switch]$SkipHomeFolder, [string]$LogPath = ".\Logs" ) begin { Import-Module ActiveDirectory -ErrorAction Stop if (-not (Test-Path $LogPath)) { New-Item -Path $LogPath -ItemType Directory -Force | Out-Null } $timestamp = Get-Date -Format 'yyyyMMdd-HHmmss' $logFile = Join-Path $LogPath "Offboard-$timestamp.log" Start-Transcript -Path $logFile -Append } process { try { # Get full user object $user = Get-ADUser -Identity $Identity -Properties MemberOf, HomeDirectory, GivenName, Surname, Description -ErrorAction Stop $displayName = "$($user.GivenName) $($user.Surname) ($Identity)" Write-Verbose "Starting offboard for: $displayName" if ($PSCmdlet.ShouldProcess($displayName, 'Disable and offboard user')) { # 1. Record current group memberships before removal $groups = $user.MemberOf | ForEach-Object { (Get-ADGroup $_).Name } Write-Verbose "Current group memberships: $($groups -join ', ')" # 2. Disable the account Disable-ADAccount -Identity $Identity Write-Verbose "Account disabled" # 3. Reset password to random value $newPassword = _New-RandomPassword Set-ADAccountPassword -Identity $Identity -NewPassword $newPassword -Reset Write-Verbose "Password reset" # 4. Remove all group memberships (except Domain Users) $user.MemberOf | ForEach-Object { Remove-ADGroupMember -Identity $_ -Members $Identity -Confirm:$false } Write-Verbose "Removed from $($groups.Count) groups" # 5. Update description with offboard info $offboardNote = "Disabled $(Get-Date -Format 'yyyy-MM-dd') by $env:USERNAME | Previous groups: $($groups -join '; ')" Set-ADUser -Identity $Identity -Description $offboardNote Write-Verbose "Description updated" # 6. Hide from GAL (if Exchange attributes exist) try { Set-ADUser -Identity $Identity -Replace @{msExchHideFromAddressLists = $true} Write-Verbose "Hidden from GAL" } catch { Write-Verbose "No Exchange attributes found, skipping GAL hide" } # 7. Move to Disabled OU Move-ADObject -Identity $user.DistinguishedName -TargetPath $DisabledOU Write-Verbose "Moved to $DisabledOU" # 8. Archive home folder if (-not $SkipHomeFolder -and $ArchivePath -and $user.HomeDirectory) { if (Test-Path $user.HomeDirectory) { $archiveDate = Get-Date -Format 'MM-dd-yyyy' $archiveName = "$($user.Surname)-$($user.GivenName)-$archiveDate" $archiveTarget = Join-Path $ArchivePath "$archiveName.zip" Write-Verbose "Archiving home folder: $($user.HomeDirectory) -> $archiveTarget" Compress-Archive -Path $user.HomeDirectory -DestinationPath $archiveTarget -Force Write-Verbose "Home folder archived" } else { Write-Warning "Home folder path not found: $($user.HomeDirectory)" } } # Output summary [PSCustomObject]@{ SAMAccountName = $Identity DisplayName = $displayName PreviousGroups = $groups -join '; ' PreviousOU = ($user.DistinguishedName -replace '^CN=.+?(?<!\\),', '') MovedTo = $DisabledOU HomeFolderArchived = (-not $SkipHomeFolder -and $user.HomeDirectory -and (Test-Path $user.HomeDirectory)) Status = 'Offboarded' Date = Get-Date -Format 'yyyy-MM-dd HH:mm' } } } catch { Write-Error "Failed to offboard $Identity : $_" [PSCustomObject]@{ SAMAccountName = $Identity Status = "FAILED: $_" Date = Get-Date -Format 'yyyy-MM-dd HH:mm' } } } end { Stop-Transcript } } |