Public/Disable-UserAccount.ps1

function New-SecurePassword {
    <#
    .SYNOPSIS
        Generates a secure random password with complexity requirements.
     
    .DESCRIPTION
        Creates a cryptographically secure password with a mix of uppercase, lowercase,
        numbers, and special characters to meet modern security requirements.
     
    .PARAMETER Length
        Length of the password to generate (default: 20)
     
    .PARAMETER IncludeSymbols
        Include special characters in the password (default: $true)
     
    .EXAMPLE
        New-SecurePassword
        Generates a 20-character secure password
     
    .EXAMPLE
        New-SecurePassword -Length 16 -IncludeSymbols:$false
        Generates a 16-character password without special characters
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [ValidateRange(12, 128)]
        [int]$Length = 20,
        
        [Parameter()]
        [bool]$IncludeSymbols = $true
    )
    
    # Define character sets
    $lowercase = 'abcdefghijklmnopqrstuvwxyz'
    $uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    $numbers = '0123456789'
    $symbols = '!@#$%^&*()_+-=[]{}|;:,.<>?'
    
    # Build character set
    $characterSet = $lowercase + $uppercase + $numbers
    if ($IncludeSymbols) {
        $characterSet += $symbols
    }
    
    # Ensure at least one character from each required set
    $password = @()
    $password += Get-Random -InputObject $lowercase.ToCharArray()
    $password += Get-Random -InputObject $uppercase.ToCharArray()
    $password += Get-Random -InputObject $numbers.ToCharArray()
    
    if ($IncludeSymbols) {
        $password += Get-Random -InputObject $symbols.ToCharArray()
    }
    
    # Fill remaining length with random characters
    $remainingLength = $Length - $password.Count
    for ($i = 0; $i -lt $remainingLength; $i++) {
        $password += Get-Random -InputObject $characterSet.ToCharArray()
    }
    
    # Shuffle the password array and return as string
    $shuffledPassword = $password | Sort-Object {Get-Random}
    return -join $shuffledPassword
}

function Write-TerminationLog {
    <#
    .SYNOPSIS
        Writes messages to the termination log file with timestamps.
     
    .DESCRIPTION
        Centralized logging function for user termination activities.
        Automatically adds timestamps and ensures proper formatting.
     
    .PARAMETER Message
        The message to log
     
    .PARAMETER LogPath
        Path to the log file
     
    .PARAMETER Level
        Log level (INFO, WARNING, ERROR)
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Message,
        
        [Parameter(Mandatory)]
        [string]$LogPath,
        
        [Parameter()]
        [ValidateSet("INFO", "WARNING", "ERROR")]
        [string]$Level = "INFO"
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "[$timestamp] [$Level] $Message"
    
    try {
        Add-Content -Path $LogPath -Value $logEntry -ErrorAction Stop
    }
    catch {
        Write-Warning "Failed to write to log file: $($_.Exception.Message)"
    }
}

function Disable-O365UserAccess {
    <#
    .SYNOPSIS
        Disables various O365 access methods for a user.
     
    .DESCRIPTION
        Centralized function to disable multiple O365 access methods including
        ActiveSync, OWA, MAPI, POP3, IMAP, etc.
     
    .PARAMETER UserPrincipalName
        The user's UPN to disable access for
     
    .PARAMETER LogPath
        Path to the log file for recording actions
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$UserPrincipalName,
        
        [Parameter(Mandatory)]
        [string]$LogPath
    )
    
    $accessMethods = @{
        'ActiveSyncEnabled' = $false
        'OWAEnabled' = $false
        'PopEnabled' = $false
        'ImapEnabled' = $false
        'MAPIEnabled' = $false
        'EWSEnabled' = $false
    }
    
    foreach ($method in $accessMethods.GetEnumerator()) {
        try {
            Set-CASMailbox -Identity $UserPrincipalName -$($method.Key) $method.Value -ErrorAction Stop
            Write-Host "✓ Disabled $($method.Key) for $UserPrincipalName" -ForegroundColor Green
            Write-TerminationLog -Message "Disabled $($method.Key) for $UserPrincipalName" -LogPath $LogPath
        }
        catch {
            Write-Host "✗ Failed to disable $($method.Key): $($_.Exception.Message)" -ForegroundColor Red
            Write-TerminationLog -Message "Failed to disable $($method.Key): $($_.Exception.Message)" -LogPath $LogPath -Level "ERROR"
        }
    }
}

function Remove-UserLicenses {
    <#
    .SYNOPSIS
        Removes all Microsoft 365 licenses from a user using Microsoft Graph PowerShell.
     
    .DESCRIPTION
        Modern approach to license removal using the Microsoft Graph PowerShell module
        instead of the deprecated MSOnline module.
     
    .PARAMETER UserPrincipalName
        The user's UPN to remove licenses from
     
    .PARAMETER LogPath
        Path to the log file for recording actions
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$UserPrincipalName,
        
        [Parameter(Mandatory)]
        [string]$LogPath
    )
    
    try {
        # Get user's current licenses
        $user = Get-MgUser -UserId $UserPrincipalName -Property AssignedLicenses -ErrorAction Stop
        
        if ($user.AssignedLicenses.Count -gt 0) {
            Write-Host "Found $($user.AssignedLicenses.Count) licenses assigned to $UserPrincipalName" -ForegroundColor Yellow
            Write-TerminationLog -Message "Found $($user.AssignedLicenses.Count) licenses assigned to $UserPrincipalName" -LogPath $LogPath
            
            # Get all SKU details for logging
            $skuIds = $user.AssignedLicenses.SkuId
            foreach ($skuId in $skuIds) {
                try {
                    $sku = Get-MgSubscribedSku | Where-Object { $_.SkuId -eq $skuId }
                    Write-Host " - Removing license: $($sku.SkuPartNumber)" -ForegroundColor Yellow
                    Write-TerminationLog -Message "Removing license: $($sku.SkuPartNumber) (SKU ID: $skuId)" -LogPath $LogPath
                }
                catch {
                    Write-TerminationLog -Message "Removing license with SKU ID: $skuId" -LogPath $LogPath
                }
            }
            
            # Remove all licenses
            Set-MgUserLicense -UserId $UserPrincipalName -AddLicenses @() -RemoveLicenses $skuIds -ErrorAction Stop
            
            Write-Host "✓ Successfully removed all licenses from $UserPrincipalName" -ForegroundColor Green
            Write-TerminationLog -Message "Successfully removed all licenses from $UserPrincipalName" -LogPath $LogPath
        }
        else {
            Write-Host "✓ No licenses found for $UserPrincipalName" -ForegroundColor Green
            Write-TerminationLog -Message "No licenses found for $UserPrincipalName" -LogPath $LogPath
        }
    }
    catch {
        Write-Host "✗ Failed to remove licenses: $($_.Exception.Message)" -ForegroundColor Red
        Write-TerminationLog -Message "Failed to remove licenses: $($_.Exception.Message)" -LogPath $LogPath -Level "ERROR"
    }
}

function Disable-ADUserAccount {
    <#
    .SYNOPSIS
        Performs Active Directory account termination tasks.
     
    .DESCRIPTION
        Handles all AD-related termination tasks including password reset,
        account disable, group removal, and GAL hiding.
     
    .PARAMETER Username
        The AD username to terminate
     
    .PARAMETER Description
        New description for the terminated account
     
    .PARAMETER LogPath
        Path to the log file for recording actions
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$Username,
        
        [Parameter(Mandatory)]
        [string]$Description,
        
        [Parameter(Mandatory)]
        [string]$LogPath
    )
    
    # Reset password
    try {
        $newPassword = New-SecurePassword
        $securePassword = ConvertTo-SecureString -String $newPassword -AsPlainText -Force
        Set-ADAccountPassword -Identity $Username -NewPassword $securePassword -Reset -ErrorAction Stop
        Write-Host "✓ Password reset successfully" -ForegroundColor Green
        Write-TerminationLog -Message "Password reset successfully" -LogPath $LogPath
    }
    catch {
        Write-Host "✗ Failed to reset password: $($_.Exception.Message)" -ForegroundColor Red
        Write-TerminationLog -Message "Failed to reset password: $($_.Exception.Message)" -LogPath $LogPath -Level "ERROR"
    }
    
    # Disable account
    try {
        Disable-ADAccount -Identity $Username -ErrorAction Stop
        
        # Verify account is disabled
        $accountStatus = Get-ADUser -Identity $Username -Properties Enabled
        if (-not $accountStatus.Enabled) {
            Write-Host "✓ Account disabled successfully" -ForegroundColor Green
            Write-TerminationLog -Message "Account disabled successfully" -LogPath $LogPath
        }
        else {
            throw "Account disable verification failed"
        }
    }
    catch {
        Write-Host "✗ Failed to disable account: $($_.Exception.Message)" -ForegroundColor Red
        Write-TerminationLog -Message "Failed to disable account: $($_.Exception.Message)" -LogPath $LogPath -Level "ERROR"
    }
    
    # Remove from groups (except Domain Users)
    try {
        Write-TerminationLog -Message "Starting group removal process" -LogPath $LogPath
        $groups = Get-ADPrincipalGroupMembership -Identity $Username | Where-Object { $_.Name -ne "Domain Users" }
        
        if ($groups.Count -gt 0) {
            Write-Host "Removing user from $($groups.Count) groups:" -ForegroundColor Yellow
            Write-TerminationLog -Message "Found $($groups.Count) groups to remove user from" -LogPath $LogPath
            
            foreach ($group in $groups) {
                try {
                    Remove-ADGroupMember -Identity $group -Members $Username -Confirm:$false -ErrorAction Stop
                    Write-Host " ✓ Removed from: $($group.Name)" -ForegroundColor Green
                    Write-TerminationLog -Message "Removed from group: $($group.Name)" -LogPath $LogPath
                }
                catch {
                    Write-Host " ✗ Failed to remove from: $($group.Name)" -ForegroundColor Red
                    Write-TerminationLog -Message "Failed to remove from group $($group.Name): $($_.Exception.Message)" -LogPath $LogPath -Level "ERROR"
                }
            }
        }
        else {
            Write-Host "✓ No additional groups to remove user from" -ForegroundColor Green
            Write-TerminationLog -Message "No additional groups to remove user from" -LogPath $LogPath
        }
    }
    catch {
        Write-Host "✗ Failed to process group memberships: $($_.Exception.Message)" -ForegroundColor Red
        Write-TerminationLog -Message "Failed to process group memberships: $($_.Exception.Message)" -LogPath $LogPath -Level "ERROR"
    }
    
    # Hide from GAL
    try {
        Set-ADUser -Identity $Username -Replace @{msexchhidefromaddresslists=$true} -ErrorAction Stop
        Write-Host "✓ Hidden from Global Address List" -ForegroundColor Green
        Write-TerminationLog -Message "Hidden from Global Address List" -LogPath $LogPath
    }
    catch {
        Write-Host "✗ Failed to hide from GAL: $($_.Exception.Message)" -ForegroundColor Red
        Write-TerminationLog -Message "Failed to hide from GAL: $($_.Exception.Message)" -LogPath $LogPath -Level "ERROR"
    }
    
    # Update description
    try {
        Set-ADUser -Identity $Username -Description $Description -ErrorAction Stop
        Write-Host "✓ Description updated successfully" -ForegroundColor Green
        Write-TerminationLog -Message "Description updated to: $Description" -LogPath $LogPath
    }
    catch {
        Write-Host "✗ Failed to update description: $($_.Exception.Message)" -ForegroundColor Red
        Write-TerminationLog -Message "Failed to update description: $($_.Exception.Message)" -LogPath $LogPath -Level "ERROR"
    }
}

function Disable-UserAccount {
    <#
    .SYNOPSIS
        Modern user termination function for Active Directory and Microsoft 365.
     
    .DESCRIPTION
        Comprehensive user termination script that handles both on-premises Active Directory
        and Microsoft 365 cloud services using current PowerShell modules and best practices.
         
        Prerequisites:
        - ActiveDirectory PowerShell module
        - ExchangeOnlineManagement module
        - Microsoft.Graph PowerShell module
        - Appropriate permissions in AD and M365
     
    .PARAMETER Username
        Active Directory username to terminate
     
    .PARAMETER TicketNumber
        Service request or ticket number for audit trail
     
    .PARAMETER TechnicianName
        Name of the technician performing the termination
     
    .PARAMETER OutOfOfficeMessage
        Optional out-of-office message to set
     
    .PARAMETER ForwardEmailTo
        Optional email address to forward mail to
     
    .PARAMETER ConvertToSharedMailbox
        Convert the user's mailbox to a shared mailbox (default: $true)
     
    .PARAMETER RemoveLicenses
        Remove all Microsoft 365 licenses (default: $true)
     
    .PARAMETER LogDirectory
        Directory to store termination logs (default: C:\Temp\TerminatedUsers)
     
    .EXAMPLE
        Disable-UserAccount -Username "jdoe" -TicketNumber "SR12345" -TechnicianName "IT Admin"
     
    .EXAMPLE
        Disable-UserAccount -Username "jsmith" -TicketNumber "INC67890" -TechnicianName "Help Desk" -ForwardEmailTo "manager@company.com" -OutOfOfficeMessage "This employee is no longer with the company."
     
    .NOTES
        This function replaces the legacy Terminate-ADUser function with modern approaches:
        - Uses Microsoft Graph PowerShell instead of MSOnline
        - Uses modern Exchange Online PowerShell connection
        - Improved error handling and logging
        - Better security practices
        - Comprehensive parameter validation
    #>

    
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(
            Mandatory,
            HelpMessage = "Enter the Active Directory username to terminate"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$Username,
        
        [Parameter(
            Mandatory,
            HelpMessage = "Enter the ticket or service request number"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$TicketNumber,
        
        [Parameter(
            Mandatory,
            HelpMessage = "Enter the name of the technician performing the termination"
        )]
        [ValidateNotNullOrEmpty()]
        [string]$TechnicianName,
        
        [Parameter(HelpMessage = "Out of office message to set")]
        [string]$OutOfOfficeMessage,
        
        [Parameter(HelpMessage = "Email address to forward messages to")]
        [ValidatePattern("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")]
        [string]$ForwardEmailTo,
        
        [Parameter(HelpMessage = "Convert mailbox to shared mailbox")]
        [bool]$ConvertToSharedMailbox = $true,
        
        [Parameter(HelpMessage = "Remove all Microsoft 365 licenses")]
        [bool]$RemoveLicenses = $true,
        
        [Parameter(HelpMessage = "Directory to store termination logs")]
        [string]$LogDirectory = "C:\Temp\TerminatedUsers"
    )
    
    begin {
        # Initialize variables
        $startTime = Get-Date
        $description = "Terminated per $TicketNumber by $TechnicianName on $($startTime.ToString('yyyy-MM-dd'))"
        
        # Create log directory if it doesn't exist
        if (-not (Test-Path $LogDirectory)) {
            try {
                New-Item -Path $LogDirectory -ItemType Directory -Force | Out-Null
                Write-Host "✓ Created log directory: $LogDirectory" -ForegroundColor Green
            }
            catch {
                Write-Error "Failed to create log directory: $($_.Exception.Message)"
                return
            }
        }
        
        # Set up log file
        $logFile = Join-Path $LogDirectory "Termination-$Username-$(Get-Date -Format 'yyyyMMdd-HHmmss').log"
        Write-Host "Log file: $logFile" -ForegroundColor Cyan
        
        # Initialize log
        Write-TerminationLog -Message "=== USER TERMINATION PROCESS STARTED ===" -LogPath $logFile
        Write-TerminationLog -Message "Username: $Username" -LogPath $logFile
        Write-TerminationLog -Message "Ticket: $TicketNumber" -LogPath $logFile
        Write-TerminationLog -Message "Technician: $TechnicianName" -LogPath $logFile
        Write-TerminationLog -Message "Start Time: $startTime" -LogPath $logFile
        
        # Check required modules
        $requiredModules = @(
            @{Name = 'ActiveDirectory'; ImportName = 'ActiveDirectory'},
            @{Name = 'ExchangeOnlineManagement'; ImportName = 'ExchangeOnlineManagement'},
            @{Name = 'Microsoft.Graph.Authentication'; ImportName = 'Microsoft.Graph.Authentication'},
            @{Name = 'Microsoft.Graph.Users'; ImportName = 'Microsoft.Graph.Users'},
            @{Name = 'Microsoft.Graph.Identity.DirectoryManagement'; ImportName = 'Microsoft.Graph.Identity.DirectoryManagement'}
        )
        
        foreach ($module in $requiredModules) {
            if (-not (Get-Module -ListAvailable -Name $module.Name)) {
                Write-Error "Required module '$($module.Name)' is not installed. Please install it first."
                return
            }
            
            try {
                Import-Module $module.ImportName -Force -ErrorAction Stop
                Write-Host "✓ Imported module: $($module.ImportName)" -ForegroundColor Green
            }
            catch {
                Write-Error "Failed to import module '$($module.ImportName)': $($_.Exception.Message)"
                return
            }
        }
    }
    
    process {
        try {
            # Verify user exists in Active Directory
            Write-Host "`n=== VERIFYING USER ACCOUNT ===" -ForegroundColor Yellow
            Write-TerminationLog -Message "=== VERIFYING USER ACCOUNT ===" -LogPath $logFile
            
            try {
                $adUser = Get-ADUser -Identity $Username -Properties DisplayName, UserPrincipalName, Enabled, Description -ErrorAction Stop
                Write-Host "✓ Found user: $($adUser.DisplayName) ($($adUser.UserPrincipalName))" -ForegroundColor Green
                Write-Host "✓ Current status: $(if ($adUser.Enabled) { 'Enabled' } else { 'Disabled' })" -ForegroundColor $(if ($adUser.Enabled) { 'Yellow' } else { 'Red' })
                Write-TerminationLog -Message "Found user: $($adUser.DisplayName) ($($adUser.UserPrincipalName))" -LogPath $logFile
                Write-TerminationLog -Message "Current status: $(if ($adUser.Enabled) { 'Enabled' } else { 'Disabled' })" -LogPath $logFile
                
                if (-not $adUser.Enabled) {
                    Write-Warning "User account is already disabled!"
                    $continue = Read-Host "Continue with termination process? (y/N)"
                    if ($continue -notmatch '^[Yy]') {
                        Write-Host "Termination cancelled by user." -ForegroundColor Yellow
                        return
                    }
                }
            }
            catch {
                Write-Error "User '$Username' not found in Active Directory: $($_.Exception.Message)"
                Write-TerminationLog -Message "User '$Username' not found in Active Directory: $($_.Exception.Message)" -LogPath $logFile -Level "ERROR"
                return
            }
            
            # Confirmation prompt
            Write-Host "`nUser to terminate:" -ForegroundColor Red
            Write-Host " Name: $($adUser.DisplayName)" -ForegroundColor White
            Write-Host " Username: $Username" -ForegroundColor White
            Write-Host " UPN: $($adUser.UserPrincipalName)" -ForegroundColor White
            Write-Host " Ticket: $TicketNumber" -ForegroundColor White
            Write-Host " Technician: $TechnicianName" -ForegroundColor White
            
            if (-not $PSCmdlet.ShouldProcess($Username, "Terminate user account")) {
                $confirm = Read-Host "`nAre you sure you want to terminate this user? Type 'TERMINATE' to confirm"
                if ($confirm -ne 'TERMINATE') {
                    Write-Host "Termination cancelled." -ForegroundColor Yellow
                    return
                }
            }
            
            # Phase 1: Active Directory Tasks
            Write-Host "`n=== PHASE 1: ACTIVE DIRECTORY TASKS ===" -ForegroundColor Yellow
            Write-TerminationLog -Message "=== PHASE 1: ACTIVE DIRECTORY TASKS ===" -LogPath $logFile
            
            Disable-ADUserAccount -Username $Username -Description $description -LogPath $logFile
            
            # Phase 2: Exchange Online Tasks
            Write-Host "`n=== PHASE 2: EXCHANGE ONLINE TASKS ===" -ForegroundColor Yellow
            Write-TerminationLog -Message "=== PHASE 2: EXCHANGE ONLINE TASKS ===" -LogPath $logFile
            
            # Ensure Exchange Online connection
            if (-not (Test-O365ExchangeConnection -Quiet)) {
                Write-Host "Connecting to Exchange Online..." -ForegroundColor Cyan
                if (-not (Connect-O365Exchange -ShowProgress)) {
                    Write-Error "Failed to connect to Exchange Online"
                    Write-TerminationLog -Message "Failed to connect to Exchange Online" -LogPath $logFile -Level "ERROR"
                    return
                }
            }
            
            # Disable mailbox access methods
            Disable-O365UserAccess -UserPrincipalName $adUser.UserPrincipalName -LogPath $logFile
            
            # Set out of office message
            if ($OutOfOfficeMessage) {
                try {
                    Set-MailboxAutoReplyConfiguration -Identity $adUser.UserPrincipalName -AutoReplyState Enabled -InternalMessage $OutOfOfficeMessage -ExternalMessage $OutOfOfficeMessage -ErrorAction Stop
                    Write-Host "✓ Out of office message set" -ForegroundColor Green
                    Write-TerminationLog -Message "Out of office message set: $OutOfOfficeMessage" -LogPath $logFile
                }
                catch {
                    Write-Host "✗ Failed to set out of office message: $($_.Exception.Message)" -ForegroundColor Red
                    Write-TerminationLog -Message "Failed to set out of office message: $($_.Exception.Message)" -LogPath $logFile -Level "ERROR"
                }
            }
            
            # Set email forwarding
            if ($ForwardEmailTo) {
                try {
                    Set-Mailbox -Identity $adUser.UserPrincipalName -ForwardingAddress $ForwardEmailTo -DeliverToMailboxAndForward $false -ErrorAction Stop
                    Write-Host "✓ Email forwarding configured to: $ForwardEmailTo" -ForegroundColor Green
                    Write-TerminationLog -Message "Email forwarding configured to: $ForwardEmailTo" -LogPath $logFile
                }
                catch {
                    Write-Host "✗ Failed to configure email forwarding: $($_.Exception.Message)" -ForegroundColor Red
                    Write-TerminationLog -Message "Failed to configure email forwarding: $($_.Exception.Message)" -LogPath $logFile -Level "ERROR"
                }
            }
            
            # Convert to shared mailbox
            if ($ConvertToSharedMailbox) {
                try {
                    Set-Mailbox -Identity $adUser.UserPrincipalName -Type Shared -ErrorAction Stop
                    Write-Host "✓ Mailbox converted to shared mailbox" -ForegroundColor Green
                    Write-TerminationLog -Message "Mailbox converted to shared mailbox" -LogPath $logFile
                    
                    # Verify conversion
                    Start-Sleep -Seconds 5
                    $mailbox = Get-Mailbox -Identity $adUser.UserPrincipalName
                    if ($mailbox.RecipientTypeDetails -eq 'SharedMailbox') {
                        Write-Host "✓ Shared mailbox conversion verified" -ForegroundColor Green
                        Write-TerminationLog -Message "Shared mailbox conversion verified" -LogPath $logFile
                    }
                }
                catch {
                    Write-Host "✗ Failed to convert to shared mailbox: $($_.Exception.Message)" -ForegroundColor Red
                    Write-TerminationLog -Message "Failed to convert to shared mailbox: $($_.Exception.Message)" -LogPath $logFile -Level "ERROR"
                }
            }
            
            # Phase 3: Microsoft Graph Tasks (License Removal)
            if ($RemoveLicenses) {
                Write-Host "`n=== PHASE 3: MICROSOFT 365 LICENSE REMOVAL ===" -ForegroundColor Yellow
                Write-TerminationLog -Message "=== PHASE 3: MICROSOFT 365 LICENSE REMOVAL ===" -LogPath $logFile
                
                # Connect to Microsoft Graph
                try {
                    $graphContext = Get-MgContext
                    if (-not $graphContext) {
                        Write-Host "Connecting to Microsoft Graph..." -ForegroundColor Cyan
                        Connect-MgGraph -Scopes "User.ReadWrite.All", "Directory.ReadWrite.All" -NoWelcome
                    }
                    
                    Remove-UserLicenses -UserPrincipalName $adUser.UserPrincipalName -LogPath $logFile
                }
                catch {
                    Write-Host "✗ Failed to connect to Microsoft Graph: $($_.Exception.Message)" -ForegroundColor Red
                    Write-TerminationLog -Message "Failed to connect to Microsoft Graph: $($_.Exception.Message)" -LogPath $logFile -Level "ERROR"
                }
            }
            
            # Summary
            $endTime = Get-Date
            $duration = $endTime - $startTime
            
            Write-Host "`n=== TERMINATION SUMMARY ===" -ForegroundColor Green
            Write-Host "✓ User termination process completed" -ForegroundColor Green
            Write-Host "✓ Duration: $($duration.TotalMinutes.ToString('F1')) minutes" -ForegroundColor Green
            Write-Host "✓ Log file: $logFile" -ForegroundColor Green
            
            Write-TerminationLog -Message "=== TERMINATION PROCESS COMPLETED ===" -LogPath $logFile
            Write-TerminationLog -Message "End Time: $endTime" -LogPath $logFile
            Write-TerminationLog -Message "Duration: $($duration.TotalMinutes.ToString('F1')) minutes" -LogPath $logFile
            Write-TerminationLog -Message "Process completed successfully" -LogPath $logFile
            
            # Open log file
            try {
                Start-Process $logFile
            }
            catch {
                Write-Host "Log file location: $logFile" -ForegroundColor Cyan
            }
        }
        catch {
            Write-Error "Termination process failed: $($_.Exception.Message)"
            Write-TerminationLog -Message "Termination process failed: $($_.Exception.Message)" -LogPath $logFile -Level "ERROR"
        }
    }
}