Files
inno-installers/FQDNUpdate/FQDNUpdate.ps1
cproudlock f9a8b2dff4 Add FQDNUpdate drive remapping tool and standardize log paths
Add FQDNUpdate project for SSO drive remapping — scans for drives mapped
to legacy server names (tsgwp00525, avwesj-gwy01), backs them up, clears
stale credentials (cmdkey, IPC$, Kerberos), and remaps using canonical
FQDNs with Windows SSO (no password). Includes .iss (pure Pascal Script),
.ps1, and .bat launcher.

Standardize all project log/backup paths to Documents\wjdt\logs\ with
auto-creation of the directory.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 07:32:30 -05:00

256 lines
8.1 KiB
PowerShell

# ============================================================================
# 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 ""