# ============================================================================ # 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' } # Short hostnames mapped to their canonical FQDN $ShortNames = @{ 'tsgwp00525' = 'tsgwp00525.wjs.geaerospace.net' 'avwesj-gwy01' = 'avwesj-gwy01.wjs.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 ""