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:
17
FQDNUpdate/FQDNUpdate.bat
Normal file
17
FQDNUpdate/FQDNUpdate.bat
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
@echo off
|
||||||
|
cd /d %SystemRoot%
|
||||||
|
|
||||||
|
if not exist "%~dp0FQDNUpdate.ps1" (
|
||||||
|
echo ERROR: FQDNUpdate.ps1 not found in %~dp0
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0FQDNUpdate.ps1"
|
||||||
|
|
||||||
|
if %ERRORLEVEL% NEQ 0 (
|
||||||
|
echo.
|
||||||
|
echo ERROR: PowerShell exited with code %ERRORLEVEL%
|
||||||
|
)
|
||||||
|
|
||||||
|
pause
|
||||||
441
FQDNUpdate/FQDNUpdate.iss
Normal file
441
FQDNUpdate/FQDNUpdate.iss
Normal file
@@ -0,0 +1,441 @@
|
|||||||
|
; ============================================================================
|
||||||
|
; 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.
|
||||||
|
; Pure Pascal Script — no PowerShell dependency.
|
||||||
|
; ============================================================================
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
AppId={{B1A2C3D4-E5F6-7890-ABCD-EF1234567890}}
|
||||||
|
AppName=FQDNUpdate
|
||||||
|
AppVersion=1.0
|
||||||
|
AppPublisher=WJDT
|
||||||
|
DefaultDirName={tmp}\FQDNUpdate
|
||||||
|
CreateAppDir=no
|
||||||
|
PrivilegesRequired=lowest
|
||||||
|
OutputDir=Output
|
||||||
|
OutputBaseFilename=FQDNUpdate
|
||||||
|
SolidCompression=yes
|
||||||
|
WizardStyle=modern
|
||||||
|
SetupIconFile=gea-logo.ico
|
||||||
|
WizardImageFile=patrick.bmp
|
||||||
|
WizardSmallImageFile=patrick-sm.bmp
|
||||||
|
DisableWelcomePage=no
|
||||||
|
DisableDirPage=yes
|
||||||
|
DisableProgramGroupPage=yes
|
||||||
|
DisableReadyPage=yes
|
||||||
|
Uninstallable=no
|
||||||
|
|
||||||
|
[Languages]
|
||||||
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
|
[Messages]
|
||||||
|
WelcomeLabel1=FQDNUpdate - Drive Remapping Tool
|
||||||
|
WelcomeLabel2=This tool will scan your mapped network drives and remap any that point to legacy server names so they use Windows SSO (no password prompt).%n%nWhat it does:%n 1. Scans for drives mapped to tsgwp00525 or avwesj-gwy01%n 2. Backs up your current mappings%n 3. Disconnects and clears stale credentials%n 4. Remaps drives using the canonical server name%n%nNo password will be required — your Windows login is used automatically.%n%nClick Next to begin.
|
||||||
|
FinishedHeadingLabel=Remapping Complete
|
||||||
|
|
||||||
|
[Code]
|
||||||
|
// ============================================================================
|
||||||
|
// CONSTANTS AND CONFIGURATION
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
const
|
||||||
|
NL = #13#10;
|
||||||
|
|
||||||
|
// Server group 1
|
||||||
|
OLD_SERVER_1 = 'tsgwp00525.rd.ds.ge.com';
|
||||||
|
NEW_SERVER_1 = 'tsgwp00525.wjs.geaerospace.net';
|
||||||
|
SHORT_NAME_1 = 'tsgwp00525';
|
||||||
|
|
||||||
|
// Server group 2
|
||||||
|
OLD_SERVER_2 = 'avwesj-gwy01.av.ge.com';
|
||||||
|
NEW_SERVER_2 = 'avwesj-gwy01.wjs.geaerospace.net';
|
||||||
|
SHORT_NAME_2 = 'avwesj-gwy01';
|
||||||
|
|
||||||
|
SERVER_VARIANT_COUNT = 6;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// GLOBAL VARIABLES
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
var
|
||||||
|
ProgressPage: TOutputProgressWizardPage;
|
||||||
|
LogContent: String;
|
||||||
|
FailureCount: Integer;
|
||||||
|
BackupPath: String;
|
||||||
|
LogPath: String;
|
||||||
|
|
||||||
|
// Parallel arrays for matched drives
|
||||||
|
DriveLetters: TArrayOfString;
|
||||||
|
RemotePaths: TArrayOfString;
|
||||||
|
ShareNames: TArrayOfString;
|
||||||
|
CanonicalFQDNs: TArrayOfString;
|
||||||
|
DriveCount: Integer;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// UTILITY FUNCTIONS
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function ExecWithOutput(const Cmd, Params: String; var Output: String): Integer;
|
||||||
|
var
|
||||||
|
TempFile: String;
|
||||||
|
ResultCode: Integer;
|
||||||
|
OutputAnsi: AnsiString;
|
||||||
|
begin
|
||||||
|
TempFile := ExpandConstant('{tmp}\cmd_output_') + IntToStr(Random(99999)) + '.txt';
|
||||||
|
|
||||||
|
Exec('cmd.exe', '/c ' + Cmd + ' ' + Params + ' > "' + TempFile + '" 2>&1',
|
||||||
|
ExpandConstant('{sys}'), SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||||
|
|
||||||
|
if FileExists(TempFile) then
|
||||||
|
begin
|
||||||
|
if LoadStringFromFile(TempFile, OutputAnsi) then
|
||||||
|
Output := String(OutputAnsi)
|
||||||
|
else
|
||||||
|
Output := '';
|
||||||
|
DeleteFile(TempFile);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Output := '';
|
||||||
|
|
||||||
|
Result := ResultCode;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Log(const Msg: String);
|
||||||
|
begin
|
||||||
|
LogContent := LogContent + Msg + NL;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetServerVariants: TArrayOfString;
|
||||||
|
begin
|
||||||
|
SetArrayLength(Result, SERVER_VARIANT_COUNT);
|
||||||
|
Result[0] := OLD_SERVER_1;
|
||||||
|
Result[1] := NEW_SERVER_1;
|
||||||
|
Result[2] := SHORT_NAME_1;
|
||||||
|
Result[3] := OLD_SERVER_2;
|
||||||
|
Result[4] := NEW_SERVER_2;
|
||||||
|
Result[5] := SHORT_NAME_2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetCanonicalFQDN(const ServerName: String): String;
|
||||||
|
var
|
||||||
|
Lower: String;
|
||||||
|
begin
|
||||||
|
Lower := Lowercase(ServerName);
|
||||||
|
if (Lower = Lowercase(OLD_SERVER_1)) or (Lower = Lowercase(NEW_SERVER_1)) or (Lower = Lowercase(SHORT_NAME_1)) then
|
||||||
|
Result := NEW_SERVER_1
|
||||||
|
else if (Lower = Lowercase(OLD_SERVER_2)) or (Lower = Lowercase(NEW_SERVER_2)) or (Lower = Lowercase(SHORT_NAME_2)) then
|
||||||
|
Result := NEW_SERVER_2
|
||||||
|
else
|
||||||
|
Result := '';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ContainsServerVariant(const S: String): Boolean;
|
||||||
|
var
|
||||||
|
Lower: String;
|
||||||
|
begin
|
||||||
|
Lower := Lowercase(S);
|
||||||
|
Result := (Pos(Lowercase(OLD_SERVER_1), Lower) > 0) or
|
||||||
|
(Pos(Lowercase(NEW_SERVER_1), Lower) > 0) or
|
||||||
|
(Pos(Lowercase(SHORT_NAME_1), Lower) > 0) or
|
||||||
|
(Pos(Lowercase(OLD_SERVER_2), Lower) > 0) or
|
||||||
|
(Pos(Lowercase(NEW_SERVER_2), Lower) > 0) or
|
||||||
|
(Pos(Lowercase(SHORT_NAME_2), Lower) > 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ExtractServerFromUNC(const UNCPath: String): String;
|
||||||
|
var
|
||||||
|
S: String;
|
||||||
|
SlashPos: Integer;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
if (Length(UNCPath) > 2) and (UNCPath[1] = '\') and (UNCPath[2] = '\') then
|
||||||
|
begin
|
||||||
|
S := Copy(UNCPath, 3, Length(UNCPath) - 2);
|
||||||
|
SlashPos := Pos('\', S);
|
||||||
|
if SlashPos > 0 then
|
||||||
|
Result := Copy(S, 1, SlashPos - 1)
|
||||||
|
else
|
||||||
|
Result := S;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ExtractShareFromUNC(const UNCPath: String): String;
|
||||||
|
var
|
||||||
|
S: String;
|
||||||
|
SlashPos: Integer;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
if (Length(UNCPath) > 2) and (UNCPath[1] = '\') and (UNCPath[2] = '\') then
|
||||||
|
begin
|
||||||
|
S := Copy(UNCPath, 3, Length(UNCPath) - 2);
|
||||||
|
SlashPos := Pos('\', S);
|
||||||
|
if SlashPos > 0 then
|
||||||
|
Result := Copy(S, SlashPos + 1, Length(S) - SlashPos);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimestamp: String;
|
||||||
|
begin
|
||||||
|
Result := GetDateTimeString('yyyymmdd_hhnnss', '-', '-');
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetLogDir: String;
|
||||||
|
begin
|
||||||
|
Result := ExpandConstant('{userdocs}\wjdt\logs');
|
||||||
|
ForceDirectories(Result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// PHASE 1: SCAN & BACKUP
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
procedure ScanAndBackup;
|
||||||
|
var
|
||||||
|
NetOutput, Line, DriveLetter, RemotePath, ServerName, ShareName, Canonical: String;
|
||||||
|
I, SpacePos, SecondSpace: Integer;
|
||||||
|
BackupContent: String;
|
||||||
|
begin
|
||||||
|
Log('=== Phase 1: Scan & Backup ===');
|
||||||
|
Log('');
|
||||||
|
DriveCount := 0;
|
||||||
|
SetArrayLength(DriveLetters, 26);
|
||||||
|
SetArrayLength(RemotePaths, 26);
|
||||||
|
SetArrayLength(ShareNames, 26);
|
||||||
|
SetArrayLength(CanonicalFQDNs, 26);
|
||||||
|
|
||||||
|
ExecWithOutput('net', 'use', NetOutput);
|
||||||
|
|
||||||
|
NetOutput := NetOutput + NL;
|
||||||
|
while Length(NetOutput) > 0 do
|
||||||
|
begin
|
||||||
|
I := Pos(#13#10, NetOutput);
|
||||||
|
if I = 0 then I := Pos(#10, NetOutput);
|
||||||
|
if I = 0 then
|
||||||
|
begin
|
||||||
|
Line := NetOutput;
|
||||||
|
NetOutput := '';
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Line := Copy(NetOutput, 1, I - 1);
|
||||||
|
if (I < Length(NetOutput)) and (NetOutput[I] = #13) then
|
||||||
|
NetOutput := Copy(NetOutput, I + 2, Length(NetOutput))
|
||||||
|
else
|
||||||
|
NetOutput := Copy(NetOutput, I + 1, Length(NetOutput));
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not ContainsServerVariant(Line) then
|
||||||
|
Continue;
|
||||||
|
|
||||||
|
DriveLetter := '';
|
||||||
|
RemotePath := '';
|
||||||
|
for I := 1 to Length(Line) - 1 do
|
||||||
|
begin
|
||||||
|
if (Line[I] >= 'A') and (Line[I] <= 'Z') and (Line[I+1] = ':') then
|
||||||
|
begin
|
||||||
|
DriveLetter := Line[I] + ':';
|
||||||
|
SpacePos := I + 2;
|
||||||
|
while (SpacePos <= Length(Line)) and (Line[SpacePos] = ' ') do
|
||||||
|
SpacePos := SpacePos + 1;
|
||||||
|
|
||||||
|
if (SpacePos < Length(Line)) and (Line[SpacePos] = '\') and (Line[SpacePos+1] = '\') then
|
||||||
|
begin
|
||||||
|
SecondSpace := SpacePos;
|
||||||
|
while (SecondSpace <= Length(Line)) and (Line[SecondSpace] <> ' ') do
|
||||||
|
SecondSpace := SecondSpace + 1;
|
||||||
|
RemotePath := Copy(Line, SpacePos, SecondSpace - SpacePos);
|
||||||
|
end;
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (DriveLetter <> '') and (RemotePath <> '') then
|
||||||
|
begin
|
||||||
|
ServerName := ExtractServerFromUNC(RemotePath);
|
||||||
|
ShareName := ExtractShareFromUNC(RemotePath);
|
||||||
|
Canonical := GetCanonicalFQDN(ServerName);
|
||||||
|
|
||||||
|
if Canonical <> '' then
|
||||||
|
begin
|
||||||
|
DriveLetters[DriveCount] := DriveLetter;
|
||||||
|
RemotePaths[DriveCount] := RemotePath;
|
||||||
|
ShareNames[DriveCount] := ShareName;
|
||||||
|
CanonicalFQDNs[DriveCount] := Canonical;
|
||||||
|
DriveCount := DriveCount + 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if DriveCount = 0 then
|
||||||
|
begin
|
||||||
|
Log('No drives found mapped to target servers.');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Log('Found ' + IntToStr(DriveCount) + ' drive(s):');
|
||||||
|
for I := 0 to DriveCount - 1 do
|
||||||
|
Log(' ' + DriveLetters[I] + ' -> ' + RemotePaths[I]);
|
||||||
|
|
||||||
|
BackupContent := '';
|
||||||
|
for I := 0 to DriveCount - 1 do
|
||||||
|
BackupContent := BackupContent + DriveLetters[I] + '|' + RemotePaths[I] + NL;
|
||||||
|
|
||||||
|
BackupPath := GetLogDir + '\fqdnupdate_' + GetTimestamp + '.txt';
|
||||||
|
SaveStringToFile(BackupPath, BackupContent, False);
|
||||||
|
Log('');
|
||||||
|
Log('Backup saved to ' + BackupPath);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// PHASE 2: DISCONNECT & CLEAR
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
procedure DisconnectAndClear;
|
||||||
|
var
|
||||||
|
Output: String;
|
||||||
|
Variants: TArrayOfString;
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
Log('');
|
||||||
|
Log('=== Phase 2: Disconnect & Clear ===');
|
||||||
|
Log('');
|
||||||
|
Variants := GetServerVariants;
|
||||||
|
|
||||||
|
for I := 0 to DriveCount - 1 do
|
||||||
|
begin
|
||||||
|
ExecWithOutput('net', 'use ' + DriveLetters[I] + ' /delete /y', Output);
|
||||||
|
Log(' Disconnected ' + DriveLetters[I]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
for I := 0 to GetArrayLength(Variants) - 1 do
|
||||||
|
begin
|
||||||
|
ExecWithOutput('net', 'use "\\' + Variants[I] + '\IPC$" /delete /y', Output);
|
||||||
|
ExecWithOutput('net', 'use "\\' + Variants[I] + '" /delete /y', Output);
|
||||||
|
end;
|
||||||
|
Log(' Cleared IPC$/server connections');
|
||||||
|
|
||||||
|
for I := 0 to GetArrayLength(Variants) - 1 do
|
||||||
|
begin
|
||||||
|
ExecWithOutput('cmdkey', '/delete:' + Variants[I], Output);
|
||||||
|
ExecWithOutput('cmdkey', '/delete:"Domain:target=' + Variants[I] + '"', Output);
|
||||||
|
end;
|
||||||
|
Log(' Cleared cached credentials');
|
||||||
|
|
||||||
|
ExecWithOutput('klist', 'purge', Output);
|
||||||
|
Log(' Purged Kerberos ticket cache');
|
||||||
|
|
||||||
|
Sleep(2000);
|
||||||
|
Log(' Waited 2 seconds for connections to release');
|
||||||
|
end;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// PHASE 3: REMAP WITH SSO
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
procedure RemapDrives;
|
||||||
|
var
|
||||||
|
Output, NewPath: String;
|
||||||
|
ExitCode, I: Integer;
|
||||||
|
begin
|
||||||
|
Log('');
|
||||||
|
Log('=== Phase 3: Remap with SSO ===');
|
||||||
|
Log('');
|
||||||
|
FailureCount := 0;
|
||||||
|
|
||||||
|
for I := 0 to DriveCount - 1 do
|
||||||
|
begin
|
||||||
|
NewPath := '\\' + CanonicalFQDNs[I] + '\' + ShareNames[I];
|
||||||
|
ExitCode := ExecWithOutput('net', 'use ' + DriveLetters[I] + ' "' + NewPath + '" /persistent:yes', Output);
|
||||||
|
|
||||||
|
if ExitCode = 0 then
|
||||||
|
Log(' OK: ' + DriveLetters[I] + ' -> ' + NewPath)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Log(' FAILED: ' + DriveLetters[I] + ' -> ' + NewPath + ' (Error ' + IntToStr(ExitCode) + ')');
|
||||||
|
FailureCount := FailureCount + 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Log('');
|
||||||
|
Log('=== Complete ===');
|
||||||
|
end;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// WIZARD PAGE CREATION
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
procedure InitializeWizard;
|
||||||
|
begin
|
||||||
|
ProgressPage := CreateOutputProgressPage('Remapping Drives', 'Please wait while your drives are remapped...');
|
||||||
|
end;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// PAGE NAVIGATION
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
function NextButtonClick(CurPageID: Integer): Boolean;
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
|
||||||
|
if CurPageID = wpWelcome then
|
||||||
|
begin
|
||||||
|
LogContent := '';
|
||||||
|
FailureCount := 0;
|
||||||
|
Log('FQDNUpdate Log - ' + GetDateTimeString('yyyy-mm-dd hh:nn:ss', '-', ':'));
|
||||||
|
Log('User: ' + GetUserNameString + ' Computer: ' + ExpandConstant('{computername}'));
|
||||||
|
Log('');
|
||||||
|
|
||||||
|
ProgressPage.Show;
|
||||||
|
try
|
||||||
|
// Phase 1: Scan & Backup
|
||||||
|
ProgressPage.SetText('Scanning for target drives...', '');
|
||||||
|
ProgressPage.SetProgress(10, 100);
|
||||||
|
ScanAndBackup;
|
||||||
|
|
||||||
|
if DriveCount > 0 then
|
||||||
|
begin
|
||||||
|
// Phase 2: Disconnect & Clear
|
||||||
|
ProgressPage.SetText('Disconnecting drives and clearing credentials...', '');
|
||||||
|
ProgressPage.SetProgress(30, 100);
|
||||||
|
DisconnectAndClear;
|
||||||
|
|
||||||
|
// Phase 3: Remap
|
||||||
|
ProgressPage.SetText('Remapping drives with SSO...', '');
|
||||||
|
ProgressPage.SetProgress(70, 100);
|
||||||
|
RemapDrives;
|
||||||
|
end;
|
||||||
|
|
||||||
|
ProgressPage.SetProgress(100, 100);
|
||||||
|
finally
|
||||||
|
ProgressPage.Hide;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Save log
|
||||||
|
LogPath := GetLogDir + '\fqdnupdate_' + GetTimestamp + '.log';
|
||||||
|
SaveStringToFile(LogPath, LogContent, False);
|
||||||
|
|
||||||
|
// Update finished page text dynamically
|
||||||
|
if DriveCount = 0 then
|
||||||
|
WizardForm.FinishedLabel.Caption :=
|
||||||
|
'No drives were found mapped to target servers.' + NL + NL +
|
||||||
|
'Nothing was changed.' + NL + NL +
|
||||||
|
'Log saved to:' + NL + LogPath
|
||||||
|
else if FailureCount = 0 then
|
||||||
|
WizardForm.FinishedLabel.Caption :=
|
||||||
|
'All ' + IntToStr(DriveCount) + ' drive(s) were successfully remapped to use Windows SSO.' + NL + NL +
|
||||||
|
'Backup: ' + BackupPath + NL +
|
||||||
|
'Log: ' + LogPath
|
||||||
|
else
|
||||||
|
WizardForm.FinishedLabel.Caption :=
|
||||||
|
IntToStr(DriveCount - FailureCount) + ' of ' + IntToStr(DriveCount) + ' drive(s) remapped successfully.' + NL +
|
||||||
|
IntToStr(FailureCount) + ' drive(s) failed — check the log for details.' + NL + NL +
|
||||||
|
'Backup: ' + BackupPath + NL +
|
||||||
|
'Log: ' + LogPath;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
end;
|
||||||
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 ""
|
||||||
BIN
FQDNUpdate/gea-logo.ico
Normal file
BIN
FQDNUpdate/gea-logo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
BIN
FQDNUpdate/patrick-sm.bmp
Normal file
BIN
FQDNUpdate/patrick-sm.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
BIN
FQDNUpdate/patrick.bmp
Normal file
BIN
FQDNUpdate/patrick.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 151 KiB |
@@ -102,8 +102,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function GetBackupFilePath: String;
|
function GetBackupFilePath: String;
|
||||||
|
var
|
||||||
|
LogDir: String;
|
||||||
begin
|
begin
|
||||||
Result := ExpandConstant('{userdocs}\') + BACKUP_FILENAME;
|
LogDir := ExpandConstant('{userdocs}\wjdt\logs');
|
||||||
|
ForceDirectories(LogDir);
|
||||||
|
Result := LogDir + '\' + BACKUP_FILENAME;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function GetLegacyServers: TArrayOfString;
|
function GetLegacyServers: TArrayOfString;
|
||||||
|
|||||||
@@ -31,10 +31,11 @@ $LegacyDomain = "logon.ds.ge.com"
|
|||||||
# Password reset URL
|
# Password reset URL
|
||||||
$PasswordResetURL = "https://mypassword.ge.com"
|
$PasswordResetURL = "https://mypassword.ge.com"
|
||||||
|
|
||||||
# Backup file location (OneDrive Documents)
|
# Backup file location
|
||||||
$OneDrivePath = [Environment]::GetFolderPath('MyDocuments') # Falls back if OneDrive not configured
|
$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"
|
$BackupFileName = "NetworkDriveMappings.json"
|
||||||
$BackupFilePath = Join-Path -Path $OneDrivePath -ChildPath $BackupFileName
|
$BackupFilePath = Join-Path -Path $LogDir -ChildPath $BackupFileName
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# FUNCTIONS
|
# FUNCTIONS
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Collection of Inno Setup installer packages for GE Aerospace manufacturing tools
|
|||||||
| [HPOfflineInstaller](HPOfflineInstaller/) | HP Universal Print Driver offline installer | [README](HPOfflineInstaller/README.md) |
|
| [HPOfflineInstaller](HPOfflineInstaller/) | HP Universal Print Driver offline installer | [README](HPOfflineInstaller/README.md) |
|
||||||
| [JT2GO](JT2GO/) | Siemens JT2Go installer with prerequisite checking | [README](JT2GO/README.md) |
|
| [JT2GO](JT2GO/) | Siemens JT2Go installer with prerequisite checking | [README](JT2GO/README.md) |
|
||||||
| [MachineAuth](MachineAuth/) | 802.1x Machine Authentication 3.0 network configuration | [README](MachineAuth/README.md) |
|
| [MachineAuth](MachineAuth/) | 802.1x Machine Authentication 3.0 network configuration | [README](MachineAuth/README.md) |
|
||||||
|
| [FQDNUpdate](FQDNUpdate/) | Drive remapping tool for SSO migration | - |
|
||||||
| [MappedDrive](MappedDrive/) | Network drive mapping tool | [README](MappedDrive/README.md) |
|
| [MappedDrive](MappedDrive/) | Network drive mapping tool | [README](MappedDrive/README.md) |
|
||||||
| [NetworkDriveManager](NetworkDriveManager/) | Advanced network drive management with migration | [README](NetworkDriveManager/README.md) |
|
| [NetworkDriveManager](NetworkDriveManager/) | Advanced network drive management with migration | [README](NetworkDriveManager/README.md) |
|
||||||
| [PrinterInstaller](PrinterInstaller/) | Network printer installer with ShopDB integration | [README](PrinterInstaller/README.md) |
|
| [PrinterInstaller](PrinterInstaller/) | Network printer installer with ShopDB integration | [README](PrinterInstaller/README.md) |
|
||||||
@@ -28,6 +29,7 @@ Collection of Inno Setup installer packages for GE Aerospace manufacturing tools
|
|||||||
|
|
||||||
### Network Drive Tools
|
### Network Drive Tools
|
||||||
- **NetworkDriveManager** - Full-featured menu-based drive management
|
- **NetworkDriveManager** - Full-featured menu-based drive management
|
||||||
|
- **FQDNUpdate** - SSO drive remapping (scan, backup, remap without password)
|
||||||
- **MappedDrive** - Simple drive mapping with server selection
|
- **MappedDrive** - Simple drive mapping with server selection
|
||||||
|
|
||||||
### Application Installers
|
### Application Installers
|
||||||
@@ -90,6 +92,7 @@ inno-installers/
|
|||||||
├── HPOfflineInstaller/ # HP printer drivers
|
├── HPOfflineInstaller/ # HP printer drivers
|
||||||
├── JT2GO/ # CAD viewer installer
|
├── JT2GO/ # CAD viewer installer
|
||||||
├── MachineAuth/ # 802.1x network configuration
|
├── MachineAuth/ # 802.1x network configuration
|
||||||
|
├── FQDNUpdate/ # SSO drive remapping tool
|
||||||
├── MappedDrive/ # Drive mapping tool
|
├── MappedDrive/ # Drive mapping tool
|
||||||
├── NetworkDriveManager/ # Advanced drive management
|
├── NetworkDriveManager/ # Advanced drive management
|
||||||
├── PrinterInstaller/ # Network printer installer
|
├── PrinterInstaller/ # Network printer installer
|
||||||
|
|||||||
Reference in New Issue
Block a user