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>
This commit is contained in:
255
FQDNUpdate/FQDNUpdate.ps1
Normal file
255
FQDNUpdate/FQDNUpdate.ps1
Normal file
@@ -0,0 +1,255 @@
|
||||
# ============================================================================
|
||||
# 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 ""
|
||||
Reference in New Issue
Block a user