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
    }
}