<#
.SYNOPSIS
    Network Drive Manager - Backup, validate credentials, and reconnect SMB shares
.DESCRIPTION
    This script helps users manage network drives connected to legacy domain servers.
    It backs up current mappings, validates credentials, and reconnects drives after
    password changes.
.NOTES
    Author: Cameron Proudlock / GE Aerospace
    Version: 1.0
    Requires: PowerShell 5.1+
#>

#Requires -Version 5.1

# ============================================================================
# CONFIGURATION - Modify these variables as needed
# ============================================================================

# Legacy domain servers to manage (add/remove as needed)
$LegacyServers = @(
    "tsgwp00525.rd.ds.ge.com"
    # Add additional servers here:
    # "server2.rd.ds.ge.com"
    # "server3.rd.ds.ge.com"
)

# Legacy domain suffix
$LegacyDomain = "logon.ds.ge.com"

# Password reset URL
$PasswordResetURL = "https://mypassword.ge.com"

# Backup file location
$LogDir = Join-Path $env:USERPROFILE 'Documents\wjdt\logs'
if (-not (Test-Path $LogDir)) { New-Item -Path $LogDir -ItemType Directory -Force | Out-Null }
$BackupFileName = "NetworkDriveMappings.json"
$BackupFilePath = Join-Path -Path $LogDir -ChildPath $BackupFileName

# ============================================================================
# FUNCTIONS
# ============================================================================

function Get-LegacyUsername {
    <#
    .SYNOPSIS
        Derives the legacy username from the current Windows profile
    #>
    $currentUser = $env:USERNAME
    return "$currentUser@$LegacyDomain"
}

function Invoke-PasswordResetFlow {
    <#
    .SYNOPSIS
        Guides user through password reset and re-prompts for new credentials
    .OUTPUTS
        Returns new SecureString password if successful, $null if cancelled
    #>
    
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Yellow
    Write-Host "              Password Reset Required" -ForegroundColor Yellow
    Write-Host "============================================================" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "  Your legacy domain password needs to be reset." -ForegroundColor White
    Write-Host ""
    Write-Host "  Steps to complete:" -ForegroundColor Cyan
    Write-Host "    1. Click 'Y' below to open the password reset portal"
    Write-Host "    2. Reset your password at $PasswordResetURL"
    Write-Host "    3. Return here and type 'DONE'"
    Write-Host "    4. Wait for the 10-minute sync timer"
    Write-Host "    5. Enter your NEW password to continue"
    Write-Host ""
    Write-Host "  NOTE: Password changes can take up to 10 minutes to sync" -ForegroundColor Gray
    Write-Host "  from Azure AD to the legacy domain. The script will wait" -ForegroundColor Gray
    Write-Host "  automatically after you confirm the reset." -ForegroundColor Gray
    Write-Host ""
    
    $openPortal = Read-Host "Open password reset portal now? (Y/n)"
    if ($openPortal.ToLower() -ne 'n') {
        Start-Process $PasswordResetURL
        Write-Host ""
        Write-Host "  Browser opened to password reset portal..." -ForegroundColor Gray
    }
    
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "  [ ] I have reset my password at $PasswordResetURL" -ForegroundColor White
    Write-Host ""
    
    $confirmed = $false
    while (-not $confirmed) {
        $confirmation = Read-Host "Type 'DONE' when you have reset your password (or 'CANCEL' to abort)"
        
        switch ($confirmation.ToUpper()) {
            "DONE" {
                $confirmed = $true
            }
            "CANCEL" {
                Write-Host ""
                Write-Host "  Password reset cancelled." -ForegroundColor Yellow
                return $null
            }
            default {
                Write-Host "  Please type 'DONE' or 'CANCEL'" -ForegroundColor Yellow
            }
        }
    }
    
    Write-Host ""
    Write-Host "  [X] Password reset confirmed!" -ForegroundColor Green
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Cyan
    Write-Host "           Waiting for AD Sync (~10 minutes)" -ForegroundColor Cyan
    Write-Host "============================================================" -ForegroundColor Cyan
    Write-Host ""
    Write-Host "  Your new password needs time to sync to the legacy domain." -ForegroundColor White
    Write-Host "  Please wait for the timer to complete, or press 'S' to skip" -ForegroundColor White
    Write-Host "  if you've already waited." -ForegroundColor White
    Write-Host ""
    
    # 10 minute countdown timer
    $totalSeconds = 600  # 10 minutes
    $startTime = Get-Date
    $endTime = $startTime.AddSeconds($totalSeconds)
    $skipped = $false
    
    # Check if a key is available to read (non-blocking)
    $host.UI.RawUI.FlushInputBuffer()
    
    while ((Get-Date) -lt $endTime -and -not $skipped) {
        $remaining = $endTime - (Get-Date)
        $minutes = [math]::Floor($remaining.TotalMinutes)
        $seconds = $remaining.Seconds
        
        # Create progress bar
        $elapsed = ((Get-Date) - $startTime).TotalSeconds
        $percentComplete = [math]::Min(100, [math]::Floor(($elapsed / $totalSeconds) * 100))
        $barLength = 40
        $filledLength = [math]::Floor($barLength * $percentComplete / 100)
        $bar = ("█" * $filledLength) + ("░" * ($barLength - $filledLength))
        
        # Write progress on same line
        Write-Host "`r  [$bar] $($minutes.ToString('00')):$($seconds.ToString('00')) remaining   (Press 'S' to skip)   " -NoNewline -ForegroundColor Cyan
        
        # Check for keypress (non-blocking)
        if ([Console]::KeyAvailable) {
            $key = [Console]::ReadKey($true)
            if ($key.Key -eq 'S') {
                $skipped = $true
                Write-Host ""
                Write-Host ""
                Write-Host "  Timer skipped by user." -ForegroundColor Yellow
            }
        }
        
        Start-Sleep -Milliseconds 500
    }
    
    if (-not $skipped) {
        Write-Host ""
        Write-Host ""
        Write-Host "  [OK] Sync wait complete!" -ForegroundColor Green
    }
    
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Cyan
    Write-Host ""
    Write-Host "  Please enter your NEW password below." -ForegroundColor White
    Write-Host ""
    
    $newPassword = Read-Host "  Enter your NEW legacy password" -AsSecureString
    
    if ($newPassword.Length -eq 0) {
        Write-Host ""
        Write-Host "  [ERROR] Password cannot be empty." -ForegroundColor Red
        return $null
    }
    
    # Confirm password
    Write-Host ""
    $confirmPassword = Read-Host "  Confirm your NEW legacy password" -AsSecureString
    
    # Compare the two passwords
    $BSTR1 = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($newPassword)
    $BSTR2 = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($confirmPassword)
    $plain1 = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR1)
    $plain2 = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR2)
    [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR1)
    [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR2)
    
    if ($plain1 -ne $plain2) {
        Write-Host ""
        Write-Host "  [ERROR] Passwords do not match. Please try again." -ForegroundColor Red
        $plain1 = $null
        $plain2 = $null
        return $null
    }
    
    $plain1 = $null
    $plain2 = $null
    
    Write-Host ""
    Write-Host "  [OK] Password confirmed!" -ForegroundColor Green
    
    return $newPassword
}

function Invoke-ZscalerReauthPrompt {
    <#
    .SYNOPSIS
        Prompts user to re-authenticate to Zscaler and retry
    .OUTPUTS
        Returns $true if user wants to retry, $false to cancel
    #>
    
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Yellow
    Write-Host "              Zscaler Re-Authentication Required" -ForegroundColor Yellow
    Write-Host "============================================================" -ForegroundColor Yellow
    Write-Host ""
    Write-Host "  The network path could not be found. This typically means" -ForegroundColor White
    Write-Host "  your Zscaler connection needs to be re-authenticated." -ForegroundColor White
    Write-Host ""
    Write-Host "  Steps to fix:" -ForegroundColor Cyan
    Write-Host "    1. Look for the Zscaler icon in your system tray"
    Write-Host "    2. Right-click and select 'Sign In' or 'Authenticate'"
    Write-Host "    3. Complete the authentication process"
    Write-Host "    4. Return here and select 'Retry'"
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Yellow
    Write-Host ""
    
    $retry = Read-Host "Type 'RETRY' after re-authenticating to Zscaler (or 'CANCEL' to abort)"
    
    return ($retry.ToUpper() -eq "RETRY")
}

function Invoke-ErrorActionHandler {
    <#
    .SYNOPSIS
        Handles specific error actions and returns whether to retry
    .OUTPUTS
        Hashtable with:
          - Retry: $true if operation should be retried
          - NewPassword: SecureString if password was reset, $null otherwise
          - Cancel: $true if user wants to cancel entirely
    #>
    param(
        [Parameter(Mandatory)]
        [string]$Action,
        
        [Parameter(Mandatory)]
        [int]$ErrorCode,
        
        [string]$AdditionalInfo = ""
    )
    
    $result = @{
        Retry       = $false
        NewPassword = $null
        Cancel      = $false
    }
    
    switch ($Action) {
        "contact_manager" {
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Red
            Write-Host "                   Access Denied (Error 5)" -ForegroundColor Red
            Write-Host "============================================================" -ForegroundColor Red
            Write-Host ""
            Write-Host "  You do not have permission to access this share." -ForegroundColor White
            Write-Host ""
            Write-Host "  ACTION REQUIRED:" -ForegroundColor Yellow
            Write-Host "    Contact your manager to request access to this resource."
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Red
            Write-Host ""
            Read-Host "Press Enter to continue..."
            $result.Cancel = $true
        }
        
        "zscaler_reauth" {
            $retry = Invoke-ZscalerReauthPrompt
            $result.Retry = $retry
            $result.Cancel = (-not $retry)
        }
        
        "retry_or_zscaler" {
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Yellow
            Write-Host "              Connection Dropped (Error 64)" -ForegroundColor Yellow
            Write-Host "============================================================" -ForegroundColor Yellow
            Write-Host ""
            Write-Host "  The network connection was unexpectedly terminated." -ForegroundColor White
            Write-Host ""
            Write-Host "  This could be caused by:" -ForegroundColor Cyan
            Write-Host "    - Zscaler connection timeout (most common)"
            Write-Host "    - Network instability"
            Write-Host "    - Server-side connection reset"
            Write-Host ""
            Write-Host "  Try re-authenticating to Zscaler first." -ForegroundColor Yellow
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Yellow
            Write-Host ""
            
            $retry = Invoke-ZscalerReauthPrompt
            $result.Retry = $retry
            $result.Cancel = (-not $retry)
        }
        
        "verify_path" {
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Yellow
            Write-Host "              Invalid Share Path (Error 67)" -ForegroundColor Yellow
            Write-Host "============================================================" -ForegroundColor Yellow
            Write-Host ""
            Write-Host "  The share path appears to be invalid or malformed." -ForegroundColor White
            if ($AdditionalInfo) {
                Write-Host "  Path: $AdditionalInfo" -ForegroundColor Gray
            }
            Write-Host ""
            Write-Host "  Possible causes:" -ForegroundColor Cyan
            Write-Host "    - The share may have been renamed or removed"
            Write-Host "    - The path may be incorrectly formatted"
            Write-Host "    - Typo in the server or share name"
            Write-Host ""
            Write-Host "  ACTION REQUIRED:" -ForegroundColor Yellow
            Write-Host "    Verify the share path is correct, or contact IT support"
            Write-Host "    if you believe this share should exist."
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Yellow
            Write-Host ""
            Read-Host "Press Enter to continue..."
            # Don't retry automatically - path needs manual verification
            $result.Cancel = $true
        }
        
        "reassign_drive_letter" {
            # This is handled automatically - we'll disconnect and reconnect
            Write-Host ""
            Write-Host "  [INFO] Drive letter conflict detected - will reassign automatically" -ForegroundColor Cyan
            $result.Retry = $true
        }
        
        "reset_password_flow" {
            $newPassword = Invoke-PasswordResetFlow
            if ($null -ne $newPassword) {
                $result.Retry = $true
                $result.NewPassword = $newPassword
            }
            else {
                $result.Cancel = $true
            }
        }
        
        "clear_connections" {
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Yellow
            Write-Host "        Multiple Connections Detected (Error 1219)" -ForegroundColor Yellow
            Write-Host "============================================================" -ForegroundColor Yellow
            Write-Host ""
            Write-Host "  You have existing connections to this server with different" -ForegroundColor White
            Write-Host "  credentials. This often happens when:" -ForegroundColor White
            Write-Host "    - You have mapped drives from a previous session" -ForegroundColor Gray
            Write-Host "    - Windows cached old credentials" -ForegroundColor Gray
            Write-Host "    - Another application connected to the server" -ForegroundColor Gray
            Write-Host ""
            Write-Host "  Clearing all connections to legacy servers..." -ForegroundColor Cyan

            # Clear all connections to legacy servers
            foreach ($server in $LegacyServers) {
                # Clear IPC$ connection
                $null = net use "\\$server\IPC$" /delete /y 2>&1
                # Clear server root
                $null = net use "\\$server" /delete /y 2>&1
            }

            # Clear any mapped drives to legacy servers
            $netUseList = net use 2>&1
            foreach ($server in $LegacyServers) {
                $serverConnections = $netUseList | Select-String -Pattern $server
                foreach ($conn in $serverConnections) {
                    $connString = $conn.ToString()
                    if ($connString -match '^(OK|Disconnected|Unavailable)?\s*([A-Z]:)') {
                        $driveLetter = $Matches[2]
                        Write-Host "    Disconnecting $driveLetter..." -NoNewline
                        $null = net use $driveLetter /delete /y 2>&1
                        Write-Host " Done" -ForegroundColor Green
                    }
                }
            }

            # Also clear cached credentials
            foreach ($server in $LegacyServers) {
                $null = cmdkey /delete:$server 2>&1
                $null = cmdkey /delete:"Domain:target=$server" 2>&1
            }

            Write-Host ""
            Write-Host "  [OK] Connections cleared. Will retry..." -ForegroundColor Green
            Write-Host ""
            Start-Sleep -Seconds 2
            $result.Retry = $true
        }
        
        "contact_helpdesk" {
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Red
            Write-Host "                Account Issue Detected" -ForegroundColor Red
            Write-Host "============================================================" -ForegroundColor Red
            Write-Host ""
            Write-Host "  Your account has a restriction that prevents connection." -ForegroundColor White
            Write-Host "  Error Code: $ErrorCode" -ForegroundColor Gray
            Write-Host ""
            Write-Host "  ACTION REQUIRED:" -ForegroundColor Yellow
            Write-Host "    Please contact the IT Helpdesk for assistance."
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Red
            Write-Host ""
            Read-Host "Press Enter to continue..."
            $result.Cancel = $true
        }
        
        "unknown_error" {
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Red
            Write-Host "                Unknown Error (Code: $ErrorCode)" -ForegroundColor Red
            Write-Host "============================================================" -ForegroundColor Red
            Write-Host ""
            Write-Host "  An unexpected error occurred." -ForegroundColor White
            if ($AdditionalInfo) {
                Write-Host "  Details: $AdditionalInfo" -ForegroundColor Gray
            }
            Write-Host ""
            Write-Host "  Options:" -ForegroundColor Cyan
            Write-Host "    - Try re-authenticating to Zscaler"
            Write-Host "    - Check your network connection"
            Write-Host "    - Contact IT Helpdesk if the issue persists"
            Write-Host ""
            Write-Host "============================================================" -ForegroundColor Red
            Write-Host ""
            
            $choice = Read-Host "Type 'RETRY' to try again, or press Enter to cancel"
            $result.Retry = ($choice.ToUpper() -eq "RETRY")
            $result.Cancel = (-not $result.Retry)
        }
        
        default {
            $result.Cancel = $true
        }
    }
    
    return $result
}

function Get-CurrentDriveMappings {
    <#
    .SYNOPSIS
        Gets all current network drive mappings and filters for legacy servers
    #>
    param(
        [switch]$AllDrives,
        [string[]]$ServerFilter = $LegacyServers
    )
    
    $mappings = @()
    
    # Get all network drives
    $netDrives = Get-WmiObject -Class Win32_MappedLogicalDisk -ErrorAction SilentlyContinue
    
    foreach ($drive in $netDrives) {
        $mapping = [PSCustomObject]@{
            DriveLetter = $drive.DeviceID
            RemotePath  = $drive.ProviderName
            ServerName  = if ($drive.ProviderName -match '\\\\([^\\]+)\\') { $Matches[1] } else { $null }
            ShareName   = if ($drive.ProviderName -match '\\\\[^\\]+\\(.+)$') { $Matches[1] } else { $null }
            IsLegacy    = $false
        }
        
        # Check if this is a legacy server drive
        foreach ($server in $ServerFilter) {
            if ($mapping.ServerName -like "*$server*" -or $mapping.RemotePath -like "*$server*") {
                $mapping.IsLegacy = $true
                break
            }
        }
        
        if ($AllDrives -or $mapping.IsLegacy) {
            $mappings += $mapping
        }
    }
    
    return $mappings
}

function Backup-DriveMappings {
    <#
    .SYNOPSIS
        Saves current drive mappings to a JSON file in OneDrive
    #>
    param(
        [string]$FilePath = $BackupFilePath
    )
    
    $mappings = Get-CurrentDriveMappings -AllDrives
    
    $backupData = [PSCustomObject]@{
        BackupDate    = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
        ComputerName  = $env:COMPUTERNAME
        Username      = $env:USERNAME
        Mappings      = $mappings
    }
    
    try {
        $backupData | ConvertTo-Json -Depth 3 | Out-File -FilePath $FilePath -Encoding UTF8 -Force
        Write-Host "[OK] " -ForegroundColor Green -NoNewline
        Write-Host "Backup saved to: $FilePath"
        return $true
    }
    catch {
        Write-Host "[ERROR] " -ForegroundColor Red -NoNewline
        Write-Host "Failed to save backup: $_"
        return $false
    }
}

function Get-SavedMappings {
    <#
    .SYNOPSIS
        Loads previously saved drive mappings from backup file
    #>
    param(
        [string]$FilePath = $BackupFilePath
    )
    
    if (-not (Test-Path $FilePath)) {
        Write-Host "[WARN] " -ForegroundColor Yellow -NoNewline
        Write-Host "No backup file found at: $FilePath"
        return $null
    }
    
    try {
        $backupData = Get-Content -Path $FilePath -Raw | ConvertFrom-Json
        Write-Host "[OK] " -ForegroundColor Green -NoNewline
        Write-Host "Loaded backup from: $($backupData.BackupDate)"
        return $backupData
    }
    catch {
        Write-Host "[ERROR] " -ForegroundColor Red -NoNewline
        Write-Host "Failed to read backup: $_"
        return $null
    }
}

function Test-SMBCredentials {
    <#
    .SYNOPSIS
        Tests credentials against a legacy SMB server
    .OUTPUTS
        Returns a hashtable with Success, ErrorCode, and Message
    #>
    param(
        [Parameter(Mandatory)]
        [string]$Server,
        
        [Parameter(Mandatory)]
        [string]$Username,
        
        [Parameter(Mandatory)]
        [SecureString]$Password
    )
    
    $result = @{
        Success   = $false
        ErrorCode = 0
        Message   = ""
        Action    = ""
    }
    
    # Convert SecureString to plain text for net use (unfortunately required)
    $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
    $PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
    [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
    
    # Try to connect to the server's IPC$ share (doesn't require a specific share to exist)
    $testPath = "\\$Server\IPC$"

    # First, remove ALL existing connections to this server (not just IPC$)
    $null = net use $testPath /delete /y 2>&1
    $null = net use "\\$Server" /delete /y 2>&1
    # Also try to clear any other connections to this server
    $existingConnections = net use 2>&1 | Select-String -Pattern $Server
    foreach ($conn in $existingConnections) {
        if ($conn -match '([A-Z]:)\s+\\\\') {
            $null = net use $Matches[1] /delete /y 2>&1
        }
    }

    # Attempt connection
    $netUseOutput = net use $testPath /user:$Username $PlainPassword 2>&1
    $exitCode = $LASTEXITCODE

    # Parse the actual system error code from the output message
    # net use often returns exit code 2 but the real error is in the message
    $parsedErrorCode = $exitCode
    $outputString = $netUseOutput | Out-String
    if ($outputString -match 'System error (\d+)') {
        $parsedErrorCode = [int]$Matches[1]
    }
    elseif ($outputString -match 'error (\d+)') {
        $parsedErrorCode = [int]$Matches[1]
    }

    # Clean up the test connection
    $null = net use $testPath /delete /y 2>&1

    # Clear password from memory
    $PlainPassword = $null

    # Interpret the result using parsed error code
    switch ($parsedErrorCode) {
        0 {
            $result.Success = $true
            $result.Message = "Credentials validated successfully"
            $result.Action = "none"
        }
        5 {
            $result.ErrorCode = 5
            $result.Message = "Access denied - you may not have permission to this share"
            $result.Action = "contact_manager"
        }
        53 {
            $result.ErrorCode = 53
            $result.Message = "Network path not found - Zscaler may need re-authentication"
            $result.Action = "zscaler_reauth"
        }
        64 {
            $result.ErrorCode = 64
            $result.Message = "Network connection was dropped unexpectedly"
            $result.Action = "retry_or_zscaler"
        }
        67 {
            $result.ErrorCode = 67
            $result.Message = "Network name cannot be found - invalid share path"
            $result.Action = "verify_path"
        }
        85 {
            $result.ErrorCode = 85
            $result.Message = "Drive letter is already in use"
            $result.Action = "reassign_drive_letter"
        }
        86 {
            $result.ErrorCode = 86
            $result.Message = "Invalid password"
            $result.Action = "reset_password_flow"
        }
        1219 {
            $result.ErrorCode = 1219
            $result.Message = "Multiple connections to server exist with different credentials"
            $result.Action = "clear_connections"
        }
        1326 {
            $result.ErrorCode = 1326
            $result.Message = "Logon failure - unknown username or bad password"
            $result.Action = "reset_password_flow"
        }
        1327 {
            $result.ErrorCode = 1327
            $result.Message = "Account restriction - policy is preventing logon"
            $result.Action = "contact_helpdesk"
        }
        1330 {
            $result.ErrorCode = 1330
            $result.Message = "Password has expired"
            $result.Action = "reset_password_flow"
        }
        1331 {
            $result.ErrorCode = 1331
            $result.Message = "Account is disabled"
            $result.Action = "contact_helpdesk"
        }
        1909 {
            $result.ErrorCode = 1909
            $result.Message = "Account is locked out"
            $result.Action = "reset_password_flow"
        }
        default {
            $result.ErrorCode = $parsedErrorCode
            $result.Message = "Unknown error (code: $parsedErrorCode) - $outputString"
            $result.Action = "unknown_error"
        }
    }

    return $result
}

function Remove-LegacyDriveMappings {
    <#
    .SYNOPSIS
        Removes all network drive mappings for legacy servers
    #>
    param(
        [string[]]$Servers = $LegacyServers
    )
    
    $currentMappings = Get-CurrentDriveMappings
    $removed = @()
    
    foreach ($mapping in $currentMappings) {
        if ($mapping.IsLegacy) {
            Write-Host "  Removing $($mapping.DriveLetter) ($($mapping.RemotePath))... " -NoNewline
            
            $result = net use $mapping.DriveLetter /delete /y 2>&1
            
            if ($LASTEXITCODE -eq 0) {
                Write-Host "OK" -ForegroundColor Green
                $removed += $mapping
            }
            else {
                Write-Host "Failed" -ForegroundColor Red
            }
        }
    }
    
    # Also clear any cached connections to these servers
    foreach ($server in $Servers) {
        $null = net use "\\$server\IPC$" /delete /y 2>&1
    }
    
    return $removed
}

function Remove-WindowsCredentials {
    <#
    .SYNOPSIS
        Removes stored Windows credentials for legacy servers
    #>
    param(
        [string[]]$Servers = $LegacyServers
    )
    
    foreach ($server in $Servers) {
        Write-Host "  Clearing credentials for $server... " -NoNewline
        
        # Try different credential target formats
        $targets = @(
            $server,
            "Domain:target=$server",
            "LegacyGeneric:target=$server",
            "*$server*"
        )
        
        $cleared = $false
        foreach ($target in $targets) {
            $result = cmdkey /delete:$target 2>&1
            if ($LASTEXITCODE -eq 0) {
                $cleared = $true
            }
        }
        
        if ($cleared) {
            Write-Host "OK" -ForegroundColor Green
        }
        else {
            Write-Host "Not found/Already cleared" -ForegroundColor Yellow
        }
    }
}

function Add-DriveMappings {
    <#
    .SYNOPSIS
        Reconnects drive mappings with new credentials
        Handles error 85 (drive letter in use) automatically
    #>
    param(
        [Parameter(Mandatory)]
        [PSCustomObject[]]$Mappings,
        
        [Parameter(Mandatory)]
        [string]$Username,
        
        [Parameter(Mandatory)]
        [SecureString]$Password
    )
    
    # Convert SecureString to plain text
    $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
    $PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
    [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
    
    $results = @()
    
    foreach ($mapping in $Mappings) {
        if (-not $mapping.IsLegacy) { continue }
        
        Write-Host "  Mapping $($mapping.DriveLetter) to $($mapping.RemotePath)... " -NoNewline
        
        # First attempt
        $netUseOutput = net use $mapping.DriveLetter $mapping.RemotePath /user:$Username $PlainPassword /persistent:yes 2>&1
        $exitCode = $LASTEXITCODE
        
        # Handle error 85 - drive letter already in use
        if ($exitCode -eq 85) {
            Write-Host "in use, reassigning... " -NoNewline -ForegroundColor Yellow
            
            # Try to disconnect the existing mapping
            $null = net use $mapping.DriveLetter /delete /y 2>&1
            Start-Sleep -Milliseconds 500
            
            # Retry the mapping
            $netUseOutput = net use $mapping.DriveLetter $mapping.RemotePath /user:$Username $PlainPassword /persistent:yes 2>&1
            $exitCode = $LASTEXITCODE
        }
        
        $mapResult = [PSCustomObject]@{
            DriveLetter = $mapping.DriveLetter
            RemotePath  = $mapping.RemotePath
            Success     = ($exitCode -eq 0)
            ErrorCode   = $exitCode
            Message     = $netUseOutput
        }
        
        if ($exitCode -eq 0) {
            Write-Host "OK" -ForegroundColor Green
        }
        else {
            Write-Host "Failed (Error: $exitCode)" -ForegroundColor Red
        }
        
        $results += $mapResult
    }
    
    # Clear password from memory
    $PlainPassword = $null
    
    return $results
}

function Show-Menu {
    <#
    .SYNOPSIS
        Displays the main menu
    #>
    Clear-Host
    Write-Host "============================================================" -ForegroundColor Cyan
    Write-Host "       GE Aerospace - Network Drive Manager" -ForegroundColor Cyan
    Write-Host "============================================================" -ForegroundColor Cyan
    Write-Host ""
    Write-Host "  Current User: $env:USERNAME" -ForegroundColor Gray
    Write-Host "  Legacy User:  $(Get-LegacyUsername)" -ForegroundColor Gray
    Write-Host "  Backup File:  $BackupFilePath" -ForegroundColor Gray
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Cyan
    Write-Host ""
    Write-Host "  1. " -NoNewline -ForegroundColor Yellow
    Write-Host "View current network drive mappings"
    Write-Host "  2. " -NoNewline -ForegroundColor Yellow
    Write-Host "Backup current mappings to OneDrive"
    Write-Host "  3. " -NoNewline -ForegroundColor Yellow
    Write-Host "Test legacy credentials"
    Write-Host "  4. " -NoNewline -ForegroundColor Yellow
    Write-Host "Full reset - Disconnect, clear creds, and reconnect drives"
    Write-Host "  5. " -NoNewline -ForegroundColor Yellow
    Write-Host "Restore drives from backup"
    Write-Host "  6. " -NoNewline -ForegroundColor Yellow
    Write-Host "Open password reset portal"
    Write-Host ""
    Write-Host "  Q. " -NoNewline -ForegroundColor Red
    Write-Host "Quit"
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Cyan
}

function Invoke-FullReset {
    <#
    .SYNOPSIS
        Performs full credential reset and drive reconnection
        With intelligent error handling and retry logic
    #>
    
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Cyan
    Write-Host "       Full Credential Reset & Drive Reconnection" -ForegroundColor Cyan
    Write-Host "============================================================" -ForegroundColor Cyan
    Write-Host ""
    
    # Step 1: Backup current mappings
    Write-Host "[Step 1/5] Backing up current drive mappings..." -ForegroundColor Yellow
    $backupSuccess = Backup-DriveMappings
    if (-not $backupSuccess) {
        Write-Host ""
        $continue = Read-Host "Backup failed. Continue anyway? (y/N)"
        if ($continue -ne 'y') { return }
    }
    
    # Load the backup we just made (or existing one)
    $savedMappings = Get-SavedMappings
    $legacyMappings = $savedMappings.Mappings | Where-Object { $_.IsLegacy -eq $true }
    
    if (-not $legacyMappings -or $legacyMappings.Count -eq 0) {
        Write-Host ""
        Write-Host "[WARN] " -ForegroundColor Yellow -NoNewline
        Write-Host "No legacy drive mappings found to restore."
        Write-Host "       Press Enter to return to menu..."
        Read-Host
        return
    }
    
    Write-Host ""
    Write-Host "Found $($legacyMappings.Count) legacy drive(s) to manage:" -ForegroundColor Cyan
    foreach ($map in $legacyMappings) {
        Write-Host "  $($map.DriveLetter) -> $($map.RemotePath)" -ForegroundColor Gray
    }
    Write-Host ""
    
    # Step 2: Get credentials from user
    Write-Host "[Step 2/5] Enter your legacy domain credentials" -ForegroundColor Yellow
    $legacyUser = Get-LegacyUsername
    Write-Host "  Username: $legacyUser" -ForegroundColor Gray
    Write-Host ""
    $password = Read-Host "  Enter your legacy password" -AsSecureString
    
    if ($password.Length -eq 0) {
        Write-Host "[ERROR] " -ForegroundColor Red -NoNewline
        Write-Host "Password cannot be empty."
        Read-Host "Press Enter to return to menu..."
        return
    }
    
    # Step 3: Test credentials first (with retry loop for errors)
    $credentialsValid = $false
    $maxRetries = 3
    $retryCount = 0
    
    while (-not $credentialsValid -and $retryCount -lt $maxRetries) {
        Write-Host ""
        Write-Host "[Step 3/5] Testing credentials against $($LegacyServers[0])..." -ForegroundColor Yellow
        $testResult = Test-SMBCredentials -Server $LegacyServers[0] -Username $legacyUser -Password $password
        
        if ($testResult.Success) {
            $credentialsValid = $true
            Write-Host "[OK] " -ForegroundColor Green -NoNewline
            Write-Host "Credentials validated successfully!"
        }
        else {
            Write-Host ""
            Write-Host "[FAILED] " -ForegroundColor Red -NoNewline
            Write-Host $testResult.Message
            
            # Handle the specific error
            $errorHandler = Invoke-ErrorActionHandler -Action $testResult.Action -ErrorCode $testResult.ErrorCode
            
            if ($errorHandler.Cancel) {
                Write-Host ""
                Write-Host "Operation cancelled." -ForegroundColor Yellow
                Read-Host "Press Enter to return to menu..."
                return
            }
            
            if ($errorHandler.NewPassword) {
                # User reset their password - use the new one
                $password = $errorHandler.NewPassword
                Write-Host ""
                Write-Host "  Retrying with new password..." -ForegroundColor Cyan
            }
            elseif ($errorHandler.Retry) {
                # Retry with same credentials (e.g., after Zscaler reauth)
                Write-Host ""
                Write-Host "  Retrying..." -ForegroundColor Cyan
            }
            
            $retryCount++
        }
    }
    
    if (-not $credentialsValid) {
        Write-Host ""
        Write-Host "[ERROR] " -ForegroundColor Red -NoNewline
        Write-Host "Maximum retry attempts reached. Please try again later."
        Read-Host "Press Enter to return to menu..."
        return
    }
    
    Write-Host ""
    
    # Step 4: Remove existing mappings and credentials
    Write-Host "[Step 4/5] Removing existing mappings and credentials..." -ForegroundColor Yellow
    Remove-LegacyDriveMappings
    Remove-WindowsCredentials
    
    Write-Host ""
    
    # Step 5: Reconnect drives (with individual error handling)
    Write-Host "[Step 5/5] Reconnecting drives with new credentials..." -ForegroundColor Yellow
    $mapResults = Add-DriveMappings -Mappings $legacyMappings -Username $legacyUser -Password $password
    
    # Check for failures that need individual handling
    $failedMappings = $mapResults | Where-Object { -not $_.Success }
    
    foreach ($failed in $failedMappings) {
        Write-Host ""
        Write-Host "  Handling failed mapping: $($failed.DriveLetter)" -ForegroundColor Yellow
        
        # Determine the action based on error code
        $action = switch ($failed.ErrorCode) {
            5   { "contact_manager" }
            53  { "zscaler_reauth" }
            64  { "retry_or_zscaler" }
            67  { "verify_path" }
            86  { "reset_password_flow" }
            1326 { "reset_password_flow" }
            1330 { "reset_password_flow" }
            1909 { "reset_password_flow" }
            default { "unknown_error" }
        }
        
        $errorHandler = Invoke-ErrorActionHandler -Action $action -ErrorCode $failed.ErrorCode -AdditionalInfo $failed.RemotePath
        
        if ($errorHandler.Retry -and -not $errorHandler.Cancel) {
            if ($errorHandler.NewPassword) {
                $password = $errorHandler.NewPassword
            }
            
            # Retry just this one mapping
            Write-Host "  Retrying $($failed.DriveLetter)... " -NoNewline
            
            $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
            $PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
            [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
            
            $retryOutput = net use $failed.DriveLetter $failed.RemotePath /user:$legacyUser $PlainPassword /persistent:yes 2>&1
            $PlainPassword = $null
            
            if ($LASTEXITCODE -eq 0) {
                Write-Host "OK" -ForegroundColor Green
                # Update the result
                $failed.Success = $true
                $failed.ErrorCode = 0
            }
            else {
                Write-Host "Still failed (Error: $LASTEXITCODE)" -ForegroundColor Red
            }
        }
    }
    
    Write-Host ""
    Write-Host "============================================================" -ForegroundColor Cyan
    Write-Host "                        Summary" -ForegroundColor Cyan
    Write-Host "============================================================" -ForegroundColor Cyan
    
    $successCount = ($mapResults | Where-Object { $_.Success }).Count
    $failCount = ($mapResults | Where-Object { -not $_.Success }).Count
    
    Write-Host ""
    Write-Host "  Successful: " -NoNewline
    Write-Host $successCount -ForegroundColor Green
    Write-Host "  Failed:     " -NoNewline
    Write-Host $failCount -ForegroundColor $(if ($failCount -gt 0) { "Red" } else { "Green" })
    Write-Host ""
    
    if ($failCount -gt 0) {
        Write-Host "Failed mappings:" -ForegroundColor Red
        foreach ($result in ($mapResults | Where-Object { -not $_.Success })) {
            Write-Host "  $($result.DriveLetter) - Error $($result.ErrorCode)" -ForegroundColor Red
        }
        Write-Host ""
        Write-Host "  You may need to map these drives manually or contact IT support." -ForegroundColor Yellow
    }
    
    Write-Host ""
    Read-Host "Press Enter to return to menu..."
}

# ============================================================================
# MAIN SCRIPT
# ============================================================================

# Check if running interactively or with parameters
param(
    [switch]$Silent,
    [switch]$BackupOnly,
    [switch]$Reset
)

if ($BackupOnly) {
    Backup-DriveMappings
    exit 0
}

if ($Reset) {
    # Non-interactive reset - would need credentials passed in or prompted
    Write-Host "Non-interactive reset not yet implemented. Please run without -Reset for interactive mode."
    exit 1
}

# ============================================================================
# AUTO-BACKUP ON STARTUP
# ============================================================================

Write-Host ""
Write-Host "============================================================" -ForegroundColor Cyan
Write-Host "       GE Aerospace - Network Drive Manager" -ForegroundColor Cyan
Write-Host "============================================================" -ForegroundColor Cyan
Write-Host ""

# Check for existing backup and auto-backup
$doBackup = $true
if (Test-Path $BackupFilePath) {
    # Backup exists - ask if user wants to overwrite
    try {
        $existingBackup = Get-Content -Path $BackupFilePath -Raw | ConvertFrom-Json
        $backupDate = $existingBackup.BackupDate
        Write-Host "  Existing backup found from: $backupDate" -ForegroundColor Yellow
        Write-Host ""
        $overwrite = Read-Host "  Overwrite existing backup with current mappings? (y/N)"
        $doBackup = ($overwrite.ToLower() -eq 'y')
    }
    catch {
        Write-Host "  Existing backup file is corrupted. Creating new backup..." -ForegroundColor Yellow
        $doBackup = $true
    }
}
else {
    Write-Host "  No existing backup found. Creating automatic backup..." -ForegroundColor Cyan
}

if ($doBackup) {
    $currentMappings = Get-CurrentDriveMappings -AllDrives
    $legacyCount = ($currentMappings | Where-Object { $_.IsLegacy }).Count

    if ($currentMappings.Count -gt 0) {
        Backup-DriveMappings | Out-Null
        Write-Host "  [OK] Backed up $($currentMappings.Count) drive(s) ($legacyCount legacy)" -ForegroundColor Green
    }
    else {
        Write-Host "  [INFO] No network drives to backup" -ForegroundColor Yellow
    }
}
else {
    Write-Host "  [SKIP] Keeping existing backup" -ForegroundColor Gray
}

Write-Host ""
Start-Sleep -Seconds 1

# Interactive menu loop
do {
    Show-Menu
    $choice = Read-Host "Select an option"
    
    switch ($choice.ToLower()) {
        "1" {
            # View current mappings
            Write-Host ""
            Write-Host "Current Network Drive Mappings:" -ForegroundColor Cyan
            Write-Host "================================" -ForegroundColor Cyan
            $mappings = Get-CurrentDriveMappings -AllDrives
            
            if ($mappings.Count -eq 0) {
                Write-Host "  No network drives mapped." -ForegroundColor Yellow
            }
            else {
                foreach ($map in $mappings) {
                    $legacyTag = if ($map.IsLegacy) { " [LEGACY]" } else { "" }
                    $color = if ($map.IsLegacy) { "Yellow" } else { "Gray" }
                    Write-Host "  $($map.DriveLetter) -> $($map.RemotePath)$legacyTag" -ForegroundColor $color
                }
            }
            Write-Host ""
            Read-Host "Press Enter to continue..."
        }
        "2" {
            # Backup mappings
            Write-Host ""
            Backup-DriveMappings
            Write-Host ""
            Read-Host "Press Enter to continue..."
        }
        "3" {
            # Test credentials
            Write-Host ""
            Write-Host "Testing Legacy Credentials" -ForegroundColor Cyan
            Write-Host "==========================" -ForegroundColor Cyan
            $legacyUser = Get-LegacyUsername
            Write-Host "Username: $legacyUser" -ForegroundColor Gray
            Write-Host ""
            $password = Read-Host "Enter your legacy password" -AsSecureString
            
            Write-Host ""
            Write-Host "Testing against servers..." -ForegroundColor Yellow
            
            foreach ($server in $LegacyServers) {
                Write-Host "  $server... " -NoNewline
                $result = Test-SMBCredentials -Server $server -Username $legacyUser -Password $password
                
                if ($result.Success) {
                    Write-Host "OK" -ForegroundColor Green
                }
                else {
                    Write-Host "FAILED - $($result.Message)" -ForegroundColor Red
                }
            }
            
            Write-Host ""
            Read-Host "Press Enter to continue..."
        }
        "4" {
            # Full reset
            Invoke-FullReset
        }
        "5" {
            # Restore from backup
            Write-Host ""
            $savedMappings = Get-SavedMappings
            
            if ($savedMappings) {
                Write-Host ""
                Write-Host "Saved mappings from $($savedMappings.BackupDate):" -ForegroundColor Cyan
                foreach ($map in $savedMappings.Mappings) {
                    $legacyTag = if ($map.IsLegacy) { " [LEGACY]" } else { "" }
                    Write-Host "  $($map.DriveLetter) -> $($map.RemotePath)$legacyTag"
                }
                
                Write-Host ""
                $restore = Read-Host "Restore legacy drives from this backup? (y/N)"
                
                if ($restore -eq 'y') {
                    $legacyUser = Get-LegacyUsername
                    Write-Host ""
                    Write-Host "Username: $legacyUser" -ForegroundColor Gray
                    $password = Read-Host "Enter your legacy password" -AsSecureString
                    
                    $legacyMappings = $savedMappings.Mappings | Where-Object { $_.IsLegacy }
                    Add-DriveMappings -Mappings $legacyMappings -Username $legacyUser -Password $password
                }
            }
            
            Write-Host ""
            Read-Host "Press Enter to continue..."
        }
        "6" {
            # Open password portal
            Write-Host ""
            Write-Host "Opening $PasswordResetURL ..." -ForegroundColor Cyan
            Start-Process $PasswordResetURL
            Start-Sleep -Seconds 2
        }
        "q" {
            Write-Host ""
            Write-Host "Goodbye!" -ForegroundColor Cyan
        }
        default {
            Write-Host ""
            Write-Host "Invalid option. Please try again." -ForegroundColor Red
            Start-Sleep -Seconds 1
        }
    }
} while ($choice.ToLower() -ne 'q')
