# ============================================================================
# FQDNUpdate - Drive Remapping Tool
# Scans for drives mapped to legacy server names, backs them up,
# clears stale credentials, and remaps using canonical FQDNs with SSO.
# ============================================================================

#Requires -Version 5.1

# Server mapping configuration (old FQDN -> new canonical FQDN)
# To add a new server, add one entry to $ServerMapping and one to $ShortNames.
$ServerMapping = @{
    'tsgwp00525.rd.ds.ge.com'              = 'tsgwp00525.wjs.geaerospace.net'
    'avwesj-gwy01.av.ge.com'               = 'avwesj-gwy01.wjs.geaerospace.net'
    'win.cighpeifep036.logon.ds.ge.com'     = 'win-cigh-pscl-0178-nec.compute.geaerospace.net'
}

# Short hostnames mapped to their canonical FQDN
$ShortNames = @{
    'tsgwp00525'       = 'tsgwp00525.wjs.geaerospace.net'
    'avwesj-gwy01'     = 'avwesj-gwy01.wjs.geaerospace.net'
    'win.cighpeifep036' = 'win-cigh-pscl-0178-nec.compute.geaerospace.net'
}

# Build the full list of all server name variants to scan for
$AllVariants = @()
$AllVariants += $ServerMapping.Keys
$AllVariants += $ServerMapping.Values
$AllVariants += $ShortNames.Keys

$Timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$LogDir = Join-Path $env:USERPROFILE 'Documents\wjdt\logs'
if (-not (Test-Path $LogDir)) { New-Item -Path $LogDir -ItemType Directory -Force | Out-Null }
$BackupFile = Join-Path $LogDir "fqdnupdate_$Timestamp.txt"
$LogFile = Join-Path $LogDir "fqdnupdate_$Timestamp.log"

# Log helper — writes to both console and log file
function Write-Log {
    param([string]$Message, [string]$Color)
    if ($Color) {
        Write-Host $Message -ForegroundColor $Color
    } else {
        Write-Host $Message
    }
    Add-Content -Path $LogFile -Value $Message
}

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

function Get-CanonicalFQDN {
    param([string]$ServerName)

    $lower = $ServerName.ToLower()

    # Check old FQDN -> new FQDN mapping
    foreach ($old in $ServerMapping.Keys) {
        if ($lower -eq $old.ToLower()) { return $ServerMapping[$old] }
    }

    # Check if it's already a canonical FQDN
    foreach ($new in $ServerMapping.Values) {
        if ($lower -eq $new.ToLower()) { return $new }
    }

    # Check short hostname
    foreach ($short in $ShortNames.Keys) {
        if ($lower -eq $short.ToLower()) { return $ShortNames[$short] }
    }

    return $null
}

function Find-MatchingDrives {
    $netUse = net use 2>&1 | Out-String
    $lines = $netUse -split "`r?`n"
    $drives = @()

    foreach ($line in $lines) {
        # Match lines with drive letters mapped to any of our target servers
        if ($line -match '^\s*(OK|Disconnected|Unavailable)?\s*([A-Z]:)\s+(\\\\[^\s]+)') {
            $driveLetter = $Matches[2]
            $remotePath  = $Matches[3]

            # Check if this path contains any of our server variants
            $matched = $false
            foreach ($variant in $AllVariants) {
                if ($remotePath -like "*$variant*") {
                    $matched = $true
                    break
                }
            }

            if ($matched) {
                # Extract server name and share from the remote path
                if ($remotePath -match '^\\\\([^\\]+)\\(.+)$') {
                    $serverName = $Matches[1]
                    $shareName  = $Matches[2]
                    $canonical  = Get-CanonicalFQDN $serverName

                    $drives += [PSCustomObject]@{
                        DriveLetter   = $driveLetter
                        RemotePath    = $remotePath
                        ServerName    = $serverName
                        ShareName     = $shareName
                        CanonicalFQDN = $canonical
                    }
                }
            }
        }
    }

    return $drives
}

function Save-DriveBackup {
    param([array]$Drives)

    $lines = @()
    foreach ($d in $Drives) {
        $lines += "$($d.DriveLetter)|$($d.RemotePath)"
    }

    $lines | Set-Content -Path $BackupFile -Encoding UTF8
    return $BackupFile
}

function Clear-ServerCredentials {
    $results = @()
    foreach ($variant in $AllVariants) {
        $null = cmdkey /delete:$variant 2>&1
        $null = cmdkey /delete:"Domain:target=$variant" 2>&1
        $results += "  Cleared credentials for $variant"
    }
    return $results
}

function Remove-AllTargetConnections {
    param([array]$Drives)

    $results = @()

    # Disconnect matched drives
    foreach ($d in $Drives) {
        $output = net use $d.DriveLetter /delete /y 2>&1 | Out-String
        if ($LASTEXITCODE -eq 0) {
            $results += "  Disconnected $($d.DriveLetter) ($($d.RemotePath))"
        } else {
            $results += "  Warning: Could not disconnect $($d.DriveLetter): $($output.Trim())"
        }
    }

    # Clear IPC$ connections for all server variants
    foreach ($variant in $AllVariants) {
        $null = net use "\\$variant\IPC$" /delete /y 2>&1
        $null = net use "\\$variant" /delete /y 2>&1
    }
    $results += "  Cleared IPC$/server connections for all variants"

    # Clear cached credentials
    $results += Clear-ServerCredentials

    # Purge Kerberos tickets to force re-authentication with current domain login
    $null = & "$env:SystemRoot\System32\klist.exe" purge 2>&1
    $results += "  Purged Kerberos ticket cache"

    # Let Windows release connections
    Start-Sleep -Seconds 2
    $results += "  Waited 2 seconds for Windows to release connections"

    return $results
}

function Add-RemappedDrives {
    param([array]$Drives)

    $results = @()
    foreach ($d in $Drives) {
        $newPath = "\\$($d.CanonicalFQDN)\$($d.ShareName)"
        $output = net use $d.DriveLetter $newPath /persistent:yes 2>&1 | Out-String

        if ($LASTEXITCODE -eq 0) {
            $results += "  OK:     $($d.DriveLetter) -> $newPath"
        } else {
            $errCode = $LASTEXITCODE
            if ($output -match 'System error (\d+)') { $errCode = [int]$Matches[1] }
            $results += "  FAILED: $($d.DriveLetter) -> $newPath (Error $errCode)"
        }
    }
    return $results
}

# ============================================================================
# MAIN
# ============================================================================

# Move to a local directory so disconnecting mapped drives doesn't break CWD
Set-Location $env:SystemRoot

Write-Log ""
Write-Log "============================================" Cyan
Write-Log "  FQDNUpdate - Drive Remapping Tool" Cyan
Write-Log "============================================" Cyan
Write-Log "  $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Log "  User: $env:USERNAME  Computer: $env:COMPUTERNAME"
Write-Log ""

# --- Phase 1: Scan & Backup ---
Write-Log "[Phase 1] Scanning for target drives..." Yellow
$drives = Find-MatchingDrives

if ($drives.Count -eq 0) {
    Write-Log ""
    Write-Log "  No drives found mapped to target servers." Green
    Write-Log "  Servers scanned: $($AllVariants -join ', ')"
    Write-Log ""
    Write-Log "Nothing to do. Exiting." Cyan
    exit 0
}

Write-Log "  Found $($drives.Count) drive(s):" Green
foreach ($d in $drives) {
    Write-Log "    $($d.DriveLetter) -> $($d.RemotePath)  [remap to $($d.CanonicalFQDN)]"
}

Write-Log ""
Write-Log "  Saving backup to $BackupFile..."
$backupPath = Save-DriveBackup -Drives $drives
Write-Log "  Backup saved." Green

# --- Phase 2: Disconnect & Clear ---
Write-Log ""
Write-Log "[Phase 2] Disconnecting drives and clearing credentials..." Yellow
$phase2Results = Remove-AllTargetConnections -Drives $drives
foreach ($line in $phase2Results) { Write-Log $line }

# --- Phase 3: Remap with SSO ---
Write-Log ""
Write-Log "[Phase 3] Remapping drives with SSO (no password prompt)..." Yellow
$phase3Results = Add-RemappedDrives -Drives $drives
foreach ($line in $phase3Results) {
    if ($line -like "*OK:*") {
        Write-Log $line Green
    } elseif ($line -like "*FAILED:*") {
        Write-Log $line Red
    } else {
        Write-Log $line
    }
}

Write-Log ""
Write-Log "============================================" Cyan
Write-Log "  Complete!" Cyan
Write-Log "  Backup: $BackupFile" White
Write-Log "  Log:    $LogFile" White
Write-Log "============================================" Cyan
Write-Log ""
