JT2GO: - Inno Setup installer for JT2Go with prerequisite checking - Checks for VC++ x86/x64 redistributables and .NET 4.8 - Verifies admin privileges before installation - Supports silent installation mode NetworkDriveManager: - Full Inno Setup implementation with integrated PowerShell logic - Menu-based interface for managing legacy domain network drives - Features: backup/restore mappings, credential testing, drive reset - Server migration from rd.ds.ge.com to wjs.geaerospace.net - Three-phase reconnection to prevent error 1219 with multiple shares - Add predefined drives (S:, V:, Y:) functionality Template: - Reusable Inno Setup project template for co-workers - Documented sections with examples and best practices - Includes utility functions and common patterns Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1262 lines
46 KiB
PowerShell
1262 lines
46 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Network Drive Manager - Backup, validate credentials, and reconnect SMB shares
|
|
.DESCRIPTION
|
|
This script helps users manage network drives connected to legacy domain servers.
|
|
It backs up current mappings, validates credentials, and reconnects drives after
|
|
password changes.
|
|
.NOTES
|
|
Author: Cameron Proudlock / GE Aerospace
|
|
Version: 1.0
|
|
Requires: PowerShell 5.1+
|
|
#>
|
|
|
|
#Requires -Version 5.1
|
|
|
|
# ============================================================================
|
|
# CONFIGURATION - Modify these variables as needed
|
|
# ============================================================================
|
|
|
|
# Legacy domain servers to manage (add/remove as needed)
|
|
$LegacyServers = @(
|
|
"tsgwp00525.rd.ds.ge.com"
|
|
# Add additional servers here:
|
|
# "server2.rd.ds.ge.com"
|
|
# "server3.rd.ds.ge.com"
|
|
)
|
|
|
|
# Legacy domain suffix
|
|
$LegacyDomain = "logon.ds.ge.com"
|
|
|
|
# Password reset URL
|
|
$PasswordResetURL = "https://mypassword.ge.com"
|
|
|
|
# Backup file location (OneDrive Documents)
|
|
$OneDrivePath = [Environment]::GetFolderPath('MyDocuments') # Falls back if OneDrive not configured
|
|
$BackupFileName = "NetworkDriveMappings.json"
|
|
$BackupFilePath = Join-Path -Path $OneDrivePath -ChildPath $BackupFileName
|
|
|
|
# ============================================================================
|
|
# FUNCTIONS
|
|
# ============================================================================
|
|
|
|
function Get-LegacyUsername {
|
|
<#
|
|
.SYNOPSIS
|
|
Derives the legacy username from the current Windows profile
|
|
#>
|
|
$currentUser = $env:USERNAME
|
|
return "$currentUser@$LegacyDomain"
|
|
}
|
|
|
|
function Invoke-PasswordResetFlow {
|
|
<#
|
|
.SYNOPSIS
|
|
Guides user through password reset and re-prompts for new credentials
|
|
.OUTPUTS
|
|
Returns new SecureString password if successful, $null if cancelled
|
|
#>
|
|
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host " Password Reset Required" -ForegroundColor Yellow
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host " Your legacy domain password needs to be reset." -ForegroundColor White
|
|
Write-Host ""
|
|
Write-Host " Steps to complete:" -ForegroundColor Cyan
|
|
Write-Host " 1. Click 'Y' below to open the password reset portal"
|
|
Write-Host " 2. Reset your password at $PasswordResetURL"
|
|
Write-Host " 3. Return here and type 'DONE'"
|
|
Write-Host " 4. Wait for the 10-minute sync timer"
|
|
Write-Host " 5. Enter your NEW password to continue"
|
|
Write-Host ""
|
|
Write-Host " NOTE: Password changes can take up to 10 minutes to sync" -ForegroundColor Gray
|
|
Write-Host " from Azure AD to the legacy domain. The script will wait" -ForegroundColor Gray
|
|
Write-Host " automatically after you confirm the reset." -ForegroundColor Gray
|
|
Write-Host ""
|
|
|
|
$openPortal = Read-Host "Open password reset portal now? (Y/n)"
|
|
if ($openPortal.ToLower() -ne 'n') {
|
|
Start-Process $PasswordResetURL
|
|
Write-Host ""
|
|
Write-Host " Browser opened to password reset portal..." -ForegroundColor Gray
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host " [ ] I have reset my password at $PasswordResetURL" -ForegroundColor White
|
|
Write-Host ""
|
|
|
|
$confirmed = $false
|
|
while (-not $confirmed) {
|
|
$confirmation = Read-Host "Type 'DONE' when you have reset your password (or 'CANCEL' to abort)"
|
|
|
|
switch ($confirmation.ToUpper()) {
|
|
"DONE" {
|
|
$confirmed = $true
|
|
}
|
|
"CANCEL" {
|
|
Write-Host ""
|
|
Write-Host " Password reset cancelled." -ForegroundColor Yellow
|
|
return $null
|
|
}
|
|
default {
|
|
Write-Host " Please type 'DONE' or 'CANCEL'" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host " [X] Password reset confirmed!" -ForegroundColor Green
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host " Waiting for AD Sync (~10 minutes)" -ForegroundColor Cyan
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
Write-Host " Your new password needs time to sync to the legacy domain." -ForegroundColor White
|
|
Write-Host " Please wait for the timer to complete, or press 'S' to skip" -ForegroundColor White
|
|
Write-Host " if you've already waited." -ForegroundColor White
|
|
Write-Host ""
|
|
|
|
# 10 minute countdown timer
|
|
$totalSeconds = 600 # 10 minutes
|
|
$startTime = Get-Date
|
|
$endTime = $startTime.AddSeconds($totalSeconds)
|
|
$skipped = $false
|
|
|
|
# Check if a key is available to read (non-blocking)
|
|
$host.UI.RawUI.FlushInputBuffer()
|
|
|
|
while ((Get-Date) -lt $endTime -and -not $skipped) {
|
|
$remaining = $endTime - (Get-Date)
|
|
$minutes = [math]::Floor($remaining.TotalMinutes)
|
|
$seconds = $remaining.Seconds
|
|
|
|
# Create progress bar
|
|
$elapsed = ((Get-Date) - $startTime).TotalSeconds
|
|
$percentComplete = [math]::Min(100, [math]::Floor(($elapsed / $totalSeconds) * 100))
|
|
$barLength = 40
|
|
$filledLength = [math]::Floor($barLength * $percentComplete / 100)
|
|
$bar = ("█" * $filledLength) + ("░" * ($barLength - $filledLength))
|
|
|
|
# Write progress on same line
|
|
Write-Host "`r [$bar] $($minutes.ToString('00')):$($seconds.ToString('00')) remaining (Press 'S' to skip) " -NoNewline -ForegroundColor Cyan
|
|
|
|
# Check for keypress (non-blocking)
|
|
if ([Console]::KeyAvailable) {
|
|
$key = [Console]::ReadKey($true)
|
|
if ($key.Key -eq 'S') {
|
|
$skipped = $true
|
|
Write-Host ""
|
|
Write-Host ""
|
|
Write-Host " Timer skipped by user." -ForegroundColor Yellow
|
|
}
|
|
}
|
|
|
|
Start-Sleep -Milliseconds 500
|
|
}
|
|
|
|
if (-not $skipped) {
|
|
Write-Host ""
|
|
Write-Host ""
|
|
Write-Host " [OK] Sync wait complete!" -ForegroundColor Green
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
Write-Host " Please enter your NEW password below." -ForegroundColor White
|
|
Write-Host ""
|
|
|
|
$newPassword = Read-Host " Enter your NEW legacy password" -AsSecureString
|
|
|
|
if ($newPassword.Length -eq 0) {
|
|
Write-Host ""
|
|
Write-Host " [ERROR] Password cannot be empty." -ForegroundColor Red
|
|
return $null
|
|
}
|
|
|
|
# Confirm password
|
|
Write-Host ""
|
|
$confirmPassword = Read-Host " Confirm your NEW legacy password" -AsSecureString
|
|
|
|
# Compare the two passwords
|
|
$BSTR1 = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($newPassword)
|
|
$BSTR2 = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($confirmPassword)
|
|
$plain1 = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR1)
|
|
$plain2 = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR2)
|
|
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR1)
|
|
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR2)
|
|
|
|
if ($plain1 -ne $plain2) {
|
|
Write-Host ""
|
|
Write-Host " [ERROR] Passwords do not match. Please try again." -ForegroundColor Red
|
|
$plain1 = $null
|
|
$plain2 = $null
|
|
return $null
|
|
}
|
|
|
|
$plain1 = $null
|
|
$plain2 = $null
|
|
|
|
Write-Host ""
|
|
Write-Host " [OK] Password confirmed!" -ForegroundColor Green
|
|
|
|
return $newPassword
|
|
}
|
|
|
|
function Invoke-ZscalerReauthPrompt {
|
|
<#
|
|
.SYNOPSIS
|
|
Prompts user to re-authenticate to Zscaler and retry
|
|
.OUTPUTS
|
|
Returns $true if user wants to retry, $false to cancel
|
|
#>
|
|
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host " Zscaler Re-Authentication Required" -ForegroundColor Yellow
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host " The network path could not be found. This typically means" -ForegroundColor White
|
|
Write-Host " your Zscaler connection needs to be re-authenticated." -ForegroundColor White
|
|
Write-Host ""
|
|
Write-Host " Steps to fix:" -ForegroundColor Cyan
|
|
Write-Host " 1. Look for the Zscaler icon in your system tray"
|
|
Write-Host " 2. Right-click and select 'Sign In' or 'Authenticate'"
|
|
Write-Host " 3. Complete the authentication process"
|
|
Write-Host " 4. Return here and select 'Retry'"
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
|
|
$retry = Read-Host "Type 'RETRY' after re-authenticating to Zscaler (or 'CANCEL' to abort)"
|
|
|
|
return ($retry.ToUpper() -eq "RETRY")
|
|
}
|
|
|
|
function Invoke-ErrorActionHandler {
|
|
<#
|
|
.SYNOPSIS
|
|
Handles specific error actions and returns whether to retry
|
|
.OUTPUTS
|
|
Hashtable with:
|
|
- Retry: $true if operation should be retried
|
|
- NewPassword: SecureString if password was reset, $null otherwise
|
|
- Cancel: $true if user wants to cancel entirely
|
|
#>
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string]$Action,
|
|
|
|
[Parameter(Mandatory)]
|
|
[int]$ErrorCode,
|
|
|
|
[string]$AdditionalInfo = ""
|
|
)
|
|
|
|
$result = @{
|
|
Retry = $false
|
|
NewPassword = $null
|
|
Cancel = $false
|
|
}
|
|
|
|
switch ($Action) {
|
|
"contact_manager" {
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Red
|
|
Write-Host " Access Denied (Error 5)" -ForegroundColor Red
|
|
Write-Host "============================================================" -ForegroundColor Red
|
|
Write-Host ""
|
|
Write-Host " You do not have permission to access this share." -ForegroundColor White
|
|
Write-Host ""
|
|
Write-Host " ACTION REQUIRED:" -ForegroundColor Yellow
|
|
Write-Host " Contact your manager to request access to this resource."
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Red
|
|
Write-Host ""
|
|
Read-Host "Press Enter to continue..."
|
|
$result.Cancel = $true
|
|
}
|
|
|
|
"zscaler_reauth" {
|
|
$retry = Invoke-ZscalerReauthPrompt
|
|
$result.Retry = $retry
|
|
$result.Cancel = (-not $retry)
|
|
}
|
|
|
|
"retry_or_zscaler" {
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host " Connection Dropped (Error 64)" -ForegroundColor Yellow
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host " The network connection was unexpectedly terminated." -ForegroundColor White
|
|
Write-Host ""
|
|
Write-Host " This could be caused by:" -ForegroundColor Cyan
|
|
Write-Host " - Zscaler connection timeout (most common)"
|
|
Write-Host " - Network instability"
|
|
Write-Host " - Server-side connection reset"
|
|
Write-Host ""
|
|
Write-Host " Try re-authenticating to Zscaler first." -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
|
|
$retry = Invoke-ZscalerReauthPrompt
|
|
$result.Retry = $retry
|
|
$result.Cancel = (-not $retry)
|
|
}
|
|
|
|
"verify_path" {
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host " Invalid Share Path (Error 67)" -ForegroundColor Yellow
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host " The share path appears to be invalid or malformed." -ForegroundColor White
|
|
if ($AdditionalInfo) {
|
|
Write-Host " Path: $AdditionalInfo" -ForegroundColor Gray
|
|
}
|
|
Write-Host ""
|
|
Write-Host " Possible causes:" -ForegroundColor Cyan
|
|
Write-Host " - The share may have been renamed or removed"
|
|
Write-Host " - The path may be incorrectly formatted"
|
|
Write-Host " - Typo in the server or share name"
|
|
Write-Host ""
|
|
Write-Host " ACTION REQUIRED:" -ForegroundColor Yellow
|
|
Write-Host " Verify the share path is correct, or contact IT support"
|
|
Write-Host " if you believe this share should exist."
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Read-Host "Press Enter to continue..."
|
|
# Don't retry automatically - path needs manual verification
|
|
$result.Cancel = $true
|
|
}
|
|
|
|
"reassign_drive_letter" {
|
|
# This is handled automatically - we'll disconnect and reconnect
|
|
Write-Host ""
|
|
Write-Host " [INFO] Drive letter conflict detected - will reassign automatically" -ForegroundColor Cyan
|
|
$result.Retry = $true
|
|
}
|
|
|
|
"reset_password_flow" {
|
|
$newPassword = Invoke-PasswordResetFlow
|
|
if ($null -ne $newPassword) {
|
|
$result.Retry = $true
|
|
$result.NewPassword = $newPassword
|
|
}
|
|
else {
|
|
$result.Cancel = $true
|
|
}
|
|
}
|
|
|
|
"clear_connections" {
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host " Multiple Connections Detected (Error 1219)" -ForegroundColor Yellow
|
|
Write-Host "============================================================" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
Write-Host " You have existing connections to this server with different" -ForegroundColor White
|
|
Write-Host " credentials. This often happens when:" -ForegroundColor White
|
|
Write-Host " - You have mapped drives from a previous session" -ForegroundColor Gray
|
|
Write-Host " - Windows cached old credentials" -ForegroundColor Gray
|
|
Write-Host " - Another application connected to the server" -ForegroundColor Gray
|
|
Write-Host ""
|
|
Write-Host " Clearing all connections to legacy servers..." -ForegroundColor Cyan
|
|
|
|
# Clear all connections to legacy servers
|
|
foreach ($server in $LegacyServers) {
|
|
# Clear IPC$ connection
|
|
$null = net use "\\$server\IPC$" /delete /y 2>&1
|
|
# Clear server root
|
|
$null = net use "\\$server" /delete /y 2>&1
|
|
}
|
|
|
|
# Clear any mapped drives to legacy servers
|
|
$netUseList = net use 2>&1
|
|
foreach ($server in $LegacyServers) {
|
|
$serverConnections = $netUseList | Select-String -Pattern $server
|
|
foreach ($conn in $serverConnections) {
|
|
$connString = $conn.ToString()
|
|
if ($connString -match '^(OK|Disconnected|Unavailable)?\s*([A-Z]:)') {
|
|
$driveLetter = $Matches[2]
|
|
Write-Host " Disconnecting $driveLetter..." -NoNewline
|
|
$null = net use $driveLetter /delete /y 2>&1
|
|
Write-Host " Done" -ForegroundColor Green
|
|
}
|
|
}
|
|
}
|
|
|
|
# Also clear cached credentials
|
|
foreach ($server in $LegacyServers) {
|
|
$null = cmdkey /delete:$server 2>&1
|
|
$null = cmdkey /delete:"Domain:target=$server" 2>&1
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host " [OK] Connections cleared. Will retry..." -ForegroundColor Green
|
|
Write-Host ""
|
|
Start-Sleep -Seconds 2
|
|
$result.Retry = $true
|
|
}
|
|
|
|
"contact_helpdesk" {
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Red
|
|
Write-Host " Account Issue Detected" -ForegroundColor Red
|
|
Write-Host "============================================================" -ForegroundColor Red
|
|
Write-Host ""
|
|
Write-Host " Your account has a restriction that prevents connection." -ForegroundColor White
|
|
Write-Host " Error Code: $ErrorCode" -ForegroundColor Gray
|
|
Write-Host ""
|
|
Write-Host " ACTION REQUIRED:" -ForegroundColor Yellow
|
|
Write-Host " Please contact the IT Helpdesk for assistance."
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Red
|
|
Write-Host ""
|
|
Read-Host "Press Enter to continue..."
|
|
$result.Cancel = $true
|
|
}
|
|
|
|
"unknown_error" {
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Red
|
|
Write-Host " Unknown Error (Code: $ErrorCode)" -ForegroundColor Red
|
|
Write-Host "============================================================" -ForegroundColor Red
|
|
Write-Host ""
|
|
Write-Host " An unexpected error occurred." -ForegroundColor White
|
|
if ($AdditionalInfo) {
|
|
Write-Host " Details: $AdditionalInfo" -ForegroundColor Gray
|
|
}
|
|
Write-Host ""
|
|
Write-Host " Options:" -ForegroundColor Cyan
|
|
Write-Host " - Try re-authenticating to Zscaler"
|
|
Write-Host " - Check your network connection"
|
|
Write-Host " - Contact IT Helpdesk if the issue persists"
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Red
|
|
Write-Host ""
|
|
|
|
$choice = Read-Host "Type 'RETRY' to try again, or press Enter to cancel"
|
|
$result.Retry = ($choice.ToUpper() -eq "RETRY")
|
|
$result.Cancel = (-not $result.Retry)
|
|
}
|
|
|
|
default {
|
|
$result.Cancel = $true
|
|
}
|
|
}
|
|
|
|
return $result
|
|
}
|
|
|
|
function Get-CurrentDriveMappings {
|
|
<#
|
|
.SYNOPSIS
|
|
Gets all current network drive mappings and filters for legacy servers
|
|
#>
|
|
param(
|
|
[switch]$AllDrives,
|
|
[string[]]$ServerFilter = $LegacyServers
|
|
)
|
|
|
|
$mappings = @()
|
|
|
|
# Get all network drives
|
|
$netDrives = Get-WmiObject -Class Win32_MappedLogicalDisk -ErrorAction SilentlyContinue
|
|
|
|
foreach ($drive in $netDrives) {
|
|
$mapping = [PSCustomObject]@{
|
|
DriveLetter = $drive.DeviceID
|
|
RemotePath = $drive.ProviderName
|
|
ServerName = if ($drive.ProviderName -match '\\\\([^\\]+)\\') { $Matches[1] } else { $null }
|
|
ShareName = if ($drive.ProviderName -match '\\\\[^\\]+\\(.+)$') { $Matches[1] } else { $null }
|
|
IsLegacy = $false
|
|
}
|
|
|
|
# Check if this is a legacy server drive
|
|
foreach ($server in $ServerFilter) {
|
|
if ($mapping.ServerName -like "*$server*" -or $mapping.RemotePath -like "*$server*") {
|
|
$mapping.IsLegacy = $true
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($AllDrives -or $mapping.IsLegacy) {
|
|
$mappings += $mapping
|
|
}
|
|
}
|
|
|
|
return $mappings
|
|
}
|
|
|
|
function Backup-DriveMappings {
|
|
<#
|
|
.SYNOPSIS
|
|
Saves current drive mappings to a JSON file in OneDrive
|
|
#>
|
|
param(
|
|
[string]$FilePath = $BackupFilePath
|
|
)
|
|
|
|
$mappings = Get-CurrentDriveMappings -AllDrives
|
|
|
|
$backupData = [PSCustomObject]@{
|
|
BackupDate = (Get-Date -Format "yyyy-MM-dd HH:mm:ss")
|
|
ComputerName = $env:COMPUTERNAME
|
|
Username = $env:USERNAME
|
|
Mappings = $mappings
|
|
}
|
|
|
|
try {
|
|
$backupData | ConvertTo-Json -Depth 3 | Out-File -FilePath $FilePath -Encoding UTF8 -Force
|
|
Write-Host "[OK] " -ForegroundColor Green -NoNewline
|
|
Write-Host "Backup saved to: $FilePath"
|
|
return $true
|
|
}
|
|
catch {
|
|
Write-Host "[ERROR] " -ForegroundColor Red -NoNewline
|
|
Write-Host "Failed to save backup: $_"
|
|
return $false
|
|
}
|
|
}
|
|
|
|
function Get-SavedMappings {
|
|
<#
|
|
.SYNOPSIS
|
|
Loads previously saved drive mappings from backup file
|
|
#>
|
|
param(
|
|
[string]$FilePath = $BackupFilePath
|
|
)
|
|
|
|
if (-not (Test-Path $FilePath)) {
|
|
Write-Host "[WARN] " -ForegroundColor Yellow -NoNewline
|
|
Write-Host "No backup file found at: $FilePath"
|
|
return $null
|
|
}
|
|
|
|
try {
|
|
$backupData = Get-Content -Path $FilePath -Raw | ConvertFrom-Json
|
|
Write-Host "[OK] " -ForegroundColor Green -NoNewline
|
|
Write-Host "Loaded backup from: $($backupData.BackupDate)"
|
|
return $backupData
|
|
}
|
|
catch {
|
|
Write-Host "[ERROR] " -ForegroundColor Red -NoNewline
|
|
Write-Host "Failed to read backup: $_"
|
|
return $null
|
|
}
|
|
}
|
|
|
|
function Test-SMBCredentials {
|
|
<#
|
|
.SYNOPSIS
|
|
Tests credentials against a legacy SMB server
|
|
.OUTPUTS
|
|
Returns a hashtable with Success, ErrorCode, and Message
|
|
#>
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string]$Server,
|
|
|
|
[Parameter(Mandatory)]
|
|
[string]$Username,
|
|
|
|
[Parameter(Mandatory)]
|
|
[SecureString]$Password
|
|
)
|
|
|
|
$result = @{
|
|
Success = $false
|
|
ErrorCode = 0
|
|
Message = ""
|
|
Action = ""
|
|
}
|
|
|
|
# Convert SecureString to plain text for net use (unfortunately required)
|
|
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
|
|
$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
|
|
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
|
|
|
|
# Try to connect to the server's IPC$ share (doesn't require a specific share to exist)
|
|
$testPath = "\\$Server\IPC$"
|
|
|
|
# First, remove ALL existing connections to this server (not just IPC$)
|
|
$null = net use $testPath /delete /y 2>&1
|
|
$null = net use "\\$Server" /delete /y 2>&1
|
|
# Also try to clear any other connections to this server
|
|
$existingConnections = net use 2>&1 | Select-String -Pattern $Server
|
|
foreach ($conn in $existingConnections) {
|
|
if ($conn -match '([A-Z]:)\s+\\\\') {
|
|
$null = net use $Matches[1] /delete /y 2>&1
|
|
}
|
|
}
|
|
|
|
# Attempt connection
|
|
$netUseOutput = net use $testPath /user:$Username $PlainPassword 2>&1
|
|
$exitCode = $LASTEXITCODE
|
|
|
|
# Parse the actual system error code from the output message
|
|
# net use often returns exit code 2 but the real error is in the message
|
|
$parsedErrorCode = $exitCode
|
|
$outputString = $netUseOutput | Out-String
|
|
if ($outputString -match 'System error (\d+)') {
|
|
$parsedErrorCode = [int]$Matches[1]
|
|
}
|
|
elseif ($outputString -match 'error (\d+)') {
|
|
$parsedErrorCode = [int]$Matches[1]
|
|
}
|
|
|
|
# Clean up the test connection
|
|
$null = net use $testPath /delete /y 2>&1
|
|
|
|
# Clear password from memory
|
|
$PlainPassword = $null
|
|
|
|
# Interpret the result using parsed error code
|
|
switch ($parsedErrorCode) {
|
|
0 {
|
|
$result.Success = $true
|
|
$result.Message = "Credentials validated successfully"
|
|
$result.Action = "none"
|
|
}
|
|
5 {
|
|
$result.ErrorCode = 5
|
|
$result.Message = "Access denied - you may not have permission to this share"
|
|
$result.Action = "contact_manager"
|
|
}
|
|
53 {
|
|
$result.ErrorCode = 53
|
|
$result.Message = "Network path not found - Zscaler may need re-authentication"
|
|
$result.Action = "zscaler_reauth"
|
|
}
|
|
64 {
|
|
$result.ErrorCode = 64
|
|
$result.Message = "Network connection was dropped unexpectedly"
|
|
$result.Action = "retry_or_zscaler"
|
|
}
|
|
67 {
|
|
$result.ErrorCode = 67
|
|
$result.Message = "Network name cannot be found - invalid share path"
|
|
$result.Action = "verify_path"
|
|
}
|
|
85 {
|
|
$result.ErrorCode = 85
|
|
$result.Message = "Drive letter is already in use"
|
|
$result.Action = "reassign_drive_letter"
|
|
}
|
|
86 {
|
|
$result.ErrorCode = 86
|
|
$result.Message = "Invalid password"
|
|
$result.Action = "reset_password_flow"
|
|
}
|
|
1219 {
|
|
$result.ErrorCode = 1219
|
|
$result.Message = "Multiple connections to server exist with different credentials"
|
|
$result.Action = "clear_connections"
|
|
}
|
|
1326 {
|
|
$result.ErrorCode = 1326
|
|
$result.Message = "Logon failure - unknown username or bad password"
|
|
$result.Action = "reset_password_flow"
|
|
}
|
|
1327 {
|
|
$result.ErrorCode = 1327
|
|
$result.Message = "Account restriction - policy is preventing logon"
|
|
$result.Action = "contact_helpdesk"
|
|
}
|
|
1330 {
|
|
$result.ErrorCode = 1330
|
|
$result.Message = "Password has expired"
|
|
$result.Action = "reset_password_flow"
|
|
}
|
|
1331 {
|
|
$result.ErrorCode = 1331
|
|
$result.Message = "Account is disabled"
|
|
$result.Action = "contact_helpdesk"
|
|
}
|
|
1909 {
|
|
$result.ErrorCode = 1909
|
|
$result.Message = "Account is locked out"
|
|
$result.Action = "reset_password_flow"
|
|
}
|
|
default {
|
|
$result.ErrorCode = $parsedErrorCode
|
|
$result.Message = "Unknown error (code: $parsedErrorCode) - $outputString"
|
|
$result.Action = "unknown_error"
|
|
}
|
|
}
|
|
|
|
return $result
|
|
}
|
|
|
|
function Remove-LegacyDriveMappings {
|
|
<#
|
|
.SYNOPSIS
|
|
Removes all network drive mappings for legacy servers
|
|
#>
|
|
param(
|
|
[string[]]$Servers = $LegacyServers
|
|
)
|
|
|
|
$currentMappings = Get-CurrentDriveMappings
|
|
$removed = @()
|
|
|
|
foreach ($mapping in $currentMappings) {
|
|
if ($mapping.IsLegacy) {
|
|
Write-Host " Removing $($mapping.DriveLetter) ($($mapping.RemotePath))... " -NoNewline
|
|
|
|
$result = net use $mapping.DriveLetter /delete /y 2>&1
|
|
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Host "OK" -ForegroundColor Green
|
|
$removed += $mapping
|
|
}
|
|
else {
|
|
Write-Host "Failed" -ForegroundColor Red
|
|
}
|
|
}
|
|
}
|
|
|
|
# Also clear any cached connections to these servers
|
|
foreach ($server in $Servers) {
|
|
$null = net use "\\$server\IPC$" /delete /y 2>&1
|
|
}
|
|
|
|
return $removed
|
|
}
|
|
|
|
function Remove-WindowsCredentials {
|
|
<#
|
|
.SYNOPSIS
|
|
Removes stored Windows credentials for legacy servers
|
|
#>
|
|
param(
|
|
[string[]]$Servers = $LegacyServers
|
|
)
|
|
|
|
foreach ($server in $Servers) {
|
|
Write-Host " Clearing credentials for $server... " -NoNewline
|
|
|
|
# Try different credential target formats
|
|
$targets = @(
|
|
$server,
|
|
"Domain:target=$server",
|
|
"LegacyGeneric:target=$server",
|
|
"*$server*"
|
|
)
|
|
|
|
$cleared = $false
|
|
foreach ($target in $targets) {
|
|
$result = cmdkey /delete:$target 2>&1
|
|
if ($LASTEXITCODE -eq 0) {
|
|
$cleared = $true
|
|
}
|
|
}
|
|
|
|
if ($cleared) {
|
|
Write-Host "OK" -ForegroundColor Green
|
|
}
|
|
else {
|
|
Write-Host "Not found/Already cleared" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
}
|
|
|
|
function Add-DriveMappings {
|
|
<#
|
|
.SYNOPSIS
|
|
Reconnects drive mappings with new credentials
|
|
Handles error 85 (drive letter in use) automatically
|
|
#>
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[PSCustomObject[]]$Mappings,
|
|
|
|
[Parameter(Mandatory)]
|
|
[string]$Username,
|
|
|
|
[Parameter(Mandatory)]
|
|
[SecureString]$Password
|
|
)
|
|
|
|
# Convert SecureString to plain text
|
|
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
|
|
$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
|
|
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
|
|
|
|
$results = @()
|
|
|
|
foreach ($mapping in $Mappings) {
|
|
if (-not $mapping.IsLegacy) { continue }
|
|
|
|
Write-Host " Mapping $($mapping.DriveLetter) to $($mapping.RemotePath)... " -NoNewline
|
|
|
|
# First attempt
|
|
$netUseOutput = net use $mapping.DriveLetter $mapping.RemotePath /user:$Username $PlainPassword /persistent:yes 2>&1
|
|
$exitCode = $LASTEXITCODE
|
|
|
|
# Handle error 85 - drive letter already in use
|
|
if ($exitCode -eq 85) {
|
|
Write-Host "in use, reassigning... " -NoNewline -ForegroundColor Yellow
|
|
|
|
# Try to disconnect the existing mapping
|
|
$null = net use $mapping.DriveLetter /delete /y 2>&1
|
|
Start-Sleep -Milliseconds 500
|
|
|
|
# Retry the mapping
|
|
$netUseOutput = net use $mapping.DriveLetter $mapping.RemotePath /user:$Username $PlainPassword /persistent:yes 2>&1
|
|
$exitCode = $LASTEXITCODE
|
|
}
|
|
|
|
$mapResult = [PSCustomObject]@{
|
|
DriveLetter = $mapping.DriveLetter
|
|
RemotePath = $mapping.RemotePath
|
|
Success = ($exitCode -eq 0)
|
|
ErrorCode = $exitCode
|
|
Message = $netUseOutput
|
|
}
|
|
|
|
if ($exitCode -eq 0) {
|
|
Write-Host "OK" -ForegroundColor Green
|
|
}
|
|
else {
|
|
Write-Host "Failed (Error: $exitCode)" -ForegroundColor Red
|
|
}
|
|
|
|
$results += $mapResult
|
|
}
|
|
|
|
# Clear password from memory
|
|
$PlainPassword = $null
|
|
|
|
return $results
|
|
}
|
|
|
|
function Show-Menu {
|
|
<#
|
|
.SYNOPSIS
|
|
Displays the main menu
|
|
#>
|
|
Clear-Host
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host " GE Aerospace - Network Drive Manager" -ForegroundColor Cyan
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
Write-Host " Current User: $env:USERNAME" -ForegroundColor Gray
|
|
Write-Host " Legacy User: $(Get-LegacyUsername)" -ForegroundColor Gray
|
|
Write-Host " Backup File: $BackupFilePath" -ForegroundColor Gray
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
Write-Host " 1. " -NoNewline -ForegroundColor Yellow
|
|
Write-Host "View current network drive mappings"
|
|
Write-Host " 2. " -NoNewline -ForegroundColor Yellow
|
|
Write-Host "Backup current mappings to OneDrive"
|
|
Write-Host " 3. " -NoNewline -ForegroundColor Yellow
|
|
Write-Host "Test legacy credentials"
|
|
Write-Host " 4. " -NoNewline -ForegroundColor Yellow
|
|
Write-Host "Full reset - Disconnect, clear creds, and reconnect drives"
|
|
Write-Host " 5. " -NoNewline -ForegroundColor Yellow
|
|
Write-Host "Restore drives from backup"
|
|
Write-Host " 6. " -NoNewline -ForegroundColor Yellow
|
|
Write-Host "Open password reset portal"
|
|
Write-Host ""
|
|
Write-Host " Q. " -NoNewline -ForegroundColor Red
|
|
Write-Host "Quit"
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
}
|
|
|
|
function Invoke-FullReset {
|
|
<#
|
|
.SYNOPSIS
|
|
Performs full credential reset and drive reconnection
|
|
With intelligent error handling and retry logic
|
|
#>
|
|
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host " Full Credential Reset & Drive Reconnection" -ForegroundColor Cyan
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
# Step 1: Backup current mappings
|
|
Write-Host "[Step 1/5] Backing up current drive mappings..." -ForegroundColor Yellow
|
|
$backupSuccess = Backup-DriveMappings
|
|
if (-not $backupSuccess) {
|
|
Write-Host ""
|
|
$continue = Read-Host "Backup failed. Continue anyway? (y/N)"
|
|
if ($continue -ne 'y') { return }
|
|
}
|
|
|
|
# Load the backup we just made (or existing one)
|
|
$savedMappings = Get-SavedMappings
|
|
$legacyMappings = $savedMappings.Mappings | Where-Object { $_.IsLegacy -eq $true }
|
|
|
|
if (-not $legacyMappings -or $legacyMappings.Count -eq 0) {
|
|
Write-Host ""
|
|
Write-Host "[WARN] " -ForegroundColor Yellow -NoNewline
|
|
Write-Host "No legacy drive mappings found to restore."
|
|
Write-Host " Press Enter to return to menu..."
|
|
Read-Host
|
|
return
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Found $($legacyMappings.Count) legacy drive(s) to manage:" -ForegroundColor Cyan
|
|
foreach ($map in $legacyMappings) {
|
|
Write-Host " $($map.DriveLetter) -> $($map.RemotePath)" -ForegroundColor Gray
|
|
}
|
|
Write-Host ""
|
|
|
|
# Step 2: Get credentials from user
|
|
Write-Host "[Step 2/5] Enter your legacy domain credentials" -ForegroundColor Yellow
|
|
$legacyUser = Get-LegacyUsername
|
|
Write-Host " Username: $legacyUser" -ForegroundColor Gray
|
|
Write-Host ""
|
|
$password = Read-Host " Enter your legacy password" -AsSecureString
|
|
|
|
if ($password.Length -eq 0) {
|
|
Write-Host "[ERROR] " -ForegroundColor Red -NoNewline
|
|
Write-Host "Password cannot be empty."
|
|
Read-Host "Press Enter to return to menu..."
|
|
return
|
|
}
|
|
|
|
# Step 3: Test credentials first (with retry loop for errors)
|
|
$credentialsValid = $false
|
|
$maxRetries = 3
|
|
$retryCount = 0
|
|
|
|
while (-not $credentialsValid -and $retryCount -lt $maxRetries) {
|
|
Write-Host ""
|
|
Write-Host "[Step 3/5] Testing credentials against $($LegacyServers[0])..." -ForegroundColor Yellow
|
|
$testResult = Test-SMBCredentials -Server $LegacyServers[0] -Username $legacyUser -Password $password
|
|
|
|
if ($testResult.Success) {
|
|
$credentialsValid = $true
|
|
Write-Host "[OK] " -ForegroundColor Green -NoNewline
|
|
Write-Host "Credentials validated successfully!"
|
|
}
|
|
else {
|
|
Write-Host ""
|
|
Write-Host "[FAILED] " -ForegroundColor Red -NoNewline
|
|
Write-Host $testResult.Message
|
|
|
|
# Handle the specific error
|
|
$errorHandler = Invoke-ErrorActionHandler -Action $testResult.Action -ErrorCode $testResult.ErrorCode
|
|
|
|
if ($errorHandler.Cancel) {
|
|
Write-Host ""
|
|
Write-Host "Operation cancelled." -ForegroundColor Yellow
|
|
Read-Host "Press Enter to return to menu..."
|
|
return
|
|
}
|
|
|
|
if ($errorHandler.NewPassword) {
|
|
# User reset their password - use the new one
|
|
$password = $errorHandler.NewPassword
|
|
Write-Host ""
|
|
Write-Host " Retrying with new password..." -ForegroundColor Cyan
|
|
}
|
|
elseif ($errorHandler.Retry) {
|
|
# Retry with same credentials (e.g., after Zscaler reauth)
|
|
Write-Host ""
|
|
Write-Host " Retrying..." -ForegroundColor Cyan
|
|
}
|
|
|
|
$retryCount++
|
|
}
|
|
}
|
|
|
|
if (-not $credentialsValid) {
|
|
Write-Host ""
|
|
Write-Host "[ERROR] " -ForegroundColor Red -NoNewline
|
|
Write-Host "Maximum retry attempts reached. Please try again later."
|
|
Read-Host "Press Enter to return to menu..."
|
|
return
|
|
}
|
|
|
|
Write-Host ""
|
|
|
|
# Step 4: Remove existing mappings and credentials
|
|
Write-Host "[Step 4/5] Removing existing mappings and credentials..." -ForegroundColor Yellow
|
|
Remove-LegacyDriveMappings
|
|
Remove-WindowsCredentials
|
|
|
|
Write-Host ""
|
|
|
|
# Step 5: Reconnect drives (with individual error handling)
|
|
Write-Host "[Step 5/5] Reconnecting drives with new credentials..." -ForegroundColor Yellow
|
|
$mapResults = Add-DriveMappings -Mappings $legacyMappings -Username $legacyUser -Password $password
|
|
|
|
# Check for failures that need individual handling
|
|
$failedMappings = $mapResults | Where-Object { -not $_.Success }
|
|
|
|
foreach ($failed in $failedMappings) {
|
|
Write-Host ""
|
|
Write-Host " Handling failed mapping: $($failed.DriveLetter)" -ForegroundColor Yellow
|
|
|
|
# Determine the action based on error code
|
|
$action = switch ($failed.ErrorCode) {
|
|
5 { "contact_manager" }
|
|
53 { "zscaler_reauth" }
|
|
64 { "retry_or_zscaler" }
|
|
67 { "verify_path" }
|
|
86 { "reset_password_flow" }
|
|
1326 { "reset_password_flow" }
|
|
1330 { "reset_password_flow" }
|
|
1909 { "reset_password_flow" }
|
|
default { "unknown_error" }
|
|
}
|
|
|
|
$errorHandler = Invoke-ErrorActionHandler -Action $action -ErrorCode $failed.ErrorCode -AdditionalInfo $failed.RemotePath
|
|
|
|
if ($errorHandler.Retry -and -not $errorHandler.Cancel) {
|
|
if ($errorHandler.NewPassword) {
|
|
$password = $errorHandler.NewPassword
|
|
}
|
|
|
|
# Retry just this one mapping
|
|
Write-Host " Retrying $($failed.DriveLetter)... " -NoNewline
|
|
|
|
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
|
|
$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
|
|
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
|
|
|
|
$retryOutput = net use $failed.DriveLetter $failed.RemotePath /user:$legacyUser $PlainPassword /persistent:yes 2>&1
|
|
$PlainPassword = $null
|
|
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Host "OK" -ForegroundColor Green
|
|
# Update the result
|
|
$failed.Success = $true
|
|
$failed.ErrorCode = 0
|
|
}
|
|
else {
|
|
Write-Host "Still failed (Error: $LASTEXITCODE)" -ForegroundColor Red
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host " Summary" -ForegroundColor Cyan
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
|
|
$successCount = ($mapResults | Where-Object { $_.Success }).Count
|
|
$failCount = ($mapResults | Where-Object { -not $_.Success }).Count
|
|
|
|
Write-Host ""
|
|
Write-Host " Successful: " -NoNewline
|
|
Write-Host $successCount -ForegroundColor Green
|
|
Write-Host " Failed: " -NoNewline
|
|
Write-Host $failCount -ForegroundColor $(if ($failCount -gt 0) { "Red" } else { "Green" })
|
|
Write-Host ""
|
|
|
|
if ($failCount -gt 0) {
|
|
Write-Host "Failed mappings:" -ForegroundColor Red
|
|
foreach ($result in ($mapResults | Where-Object { -not $_.Success })) {
|
|
Write-Host " $($result.DriveLetter) - Error $($result.ErrorCode)" -ForegroundColor Red
|
|
}
|
|
Write-Host ""
|
|
Write-Host " You may need to map these drives manually or contact IT support." -ForegroundColor Yellow
|
|
}
|
|
|
|
Write-Host ""
|
|
Read-Host "Press Enter to return to menu..."
|
|
}
|
|
|
|
# ============================================================================
|
|
# MAIN SCRIPT
|
|
# ============================================================================
|
|
|
|
# Check if running interactively or with parameters
|
|
param(
|
|
[switch]$Silent,
|
|
[switch]$BackupOnly,
|
|
[switch]$Reset
|
|
)
|
|
|
|
if ($BackupOnly) {
|
|
Backup-DriveMappings
|
|
exit 0
|
|
}
|
|
|
|
if ($Reset) {
|
|
# Non-interactive reset - would need credentials passed in or prompted
|
|
Write-Host "Non-interactive reset not yet implemented. Please run without -Reset for interactive mode."
|
|
exit 1
|
|
}
|
|
|
|
# ============================================================================
|
|
# AUTO-BACKUP ON STARTUP
|
|
# ============================================================================
|
|
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host " GE Aerospace - Network Drive Manager" -ForegroundColor Cyan
|
|
Write-Host "============================================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
# Check for existing backup and auto-backup
|
|
$doBackup = $true
|
|
if (Test-Path $BackupFilePath) {
|
|
# Backup exists - ask if user wants to overwrite
|
|
try {
|
|
$existingBackup = Get-Content -Path $BackupFilePath -Raw | ConvertFrom-Json
|
|
$backupDate = $existingBackup.BackupDate
|
|
Write-Host " Existing backup found from: $backupDate" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
$overwrite = Read-Host " Overwrite existing backup with current mappings? (y/N)"
|
|
$doBackup = ($overwrite.ToLower() -eq 'y')
|
|
}
|
|
catch {
|
|
Write-Host " Existing backup file is corrupted. Creating new backup..." -ForegroundColor Yellow
|
|
$doBackup = $true
|
|
}
|
|
}
|
|
else {
|
|
Write-Host " No existing backup found. Creating automatic backup..." -ForegroundColor Cyan
|
|
}
|
|
|
|
if ($doBackup) {
|
|
$currentMappings = Get-CurrentDriveMappings -AllDrives
|
|
$legacyCount = ($currentMappings | Where-Object { $_.IsLegacy }).Count
|
|
|
|
if ($currentMappings.Count -gt 0) {
|
|
Backup-DriveMappings | Out-Null
|
|
Write-Host " [OK] Backed up $($currentMappings.Count) drive(s) ($legacyCount legacy)" -ForegroundColor Green
|
|
}
|
|
else {
|
|
Write-Host " [INFO] No network drives to backup" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
else {
|
|
Write-Host " [SKIP] Keeping existing backup" -ForegroundColor Gray
|
|
}
|
|
|
|
Write-Host ""
|
|
Start-Sleep -Seconds 1
|
|
|
|
# Interactive menu loop
|
|
do {
|
|
Show-Menu
|
|
$choice = Read-Host "Select an option"
|
|
|
|
switch ($choice.ToLower()) {
|
|
"1" {
|
|
# View current mappings
|
|
Write-Host ""
|
|
Write-Host "Current Network Drive Mappings:" -ForegroundColor Cyan
|
|
Write-Host "================================" -ForegroundColor Cyan
|
|
$mappings = Get-CurrentDriveMappings -AllDrives
|
|
|
|
if ($mappings.Count -eq 0) {
|
|
Write-Host " No network drives mapped." -ForegroundColor Yellow
|
|
}
|
|
else {
|
|
foreach ($map in $mappings) {
|
|
$legacyTag = if ($map.IsLegacy) { " [LEGACY]" } else { "" }
|
|
$color = if ($map.IsLegacy) { "Yellow" } else { "Gray" }
|
|
Write-Host " $($map.DriveLetter) -> $($map.RemotePath)$legacyTag" -ForegroundColor $color
|
|
}
|
|
}
|
|
Write-Host ""
|
|
Read-Host "Press Enter to continue..."
|
|
}
|
|
"2" {
|
|
# Backup mappings
|
|
Write-Host ""
|
|
Backup-DriveMappings
|
|
Write-Host ""
|
|
Read-Host "Press Enter to continue..."
|
|
}
|
|
"3" {
|
|
# Test credentials
|
|
Write-Host ""
|
|
Write-Host "Testing Legacy Credentials" -ForegroundColor Cyan
|
|
Write-Host "==========================" -ForegroundColor Cyan
|
|
$legacyUser = Get-LegacyUsername
|
|
Write-Host "Username: $legacyUser" -ForegroundColor Gray
|
|
Write-Host ""
|
|
$password = Read-Host "Enter your legacy password" -AsSecureString
|
|
|
|
Write-Host ""
|
|
Write-Host "Testing against servers..." -ForegroundColor Yellow
|
|
|
|
foreach ($server in $LegacyServers) {
|
|
Write-Host " $server... " -NoNewline
|
|
$result = Test-SMBCredentials -Server $server -Username $legacyUser -Password $password
|
|
|
|
if ($result.Success) {
|
|
Write-Host "OK" -ForegroundColor Green
|
|
}
|
|
else {
|
|
Write-Host "FAILED - $($result.Message)" -ForegroundColor Red
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Read-Host "Press Enter to continue..."
|
|
}
|
|
"4" {
|
|
# Full reset
|
|
Invoke-FullReset
|
|
}
|
|
"5" {
|
|
# Restore from backup
|
|
Write-Host ""
|
|
$savedMappings = Get-SavedMappings
|
|
|
|
if ($savedMappings) {
|
|
Write-Host ""
|
|
Write-Host "Saved mappings from $($savedMappings.BackupDate):" -ForegroundColor Cyan
|
|
foreach ($map in $savedMappings.Mappings) {
|
|
$legacyTag = if ($map.IsLegacy) { " [LEGACY]" } else { "" }
|
|
Write-Host " $($map.DriveLetter) -> $($map.RemotePath)$legacyTag"
|
|
}
|
|
|
|
Write-Host ""
|
|
$restore = Read-Host "Restore legacy drives from this backup? (y/N)"
|
|
|
|
if ($restore -eq 'y') {
|
|
$legacyUser = Get-LegacyUsername
|
|
Write-Host ""
|
|
Write-Host "Username: $legacyUser" -ForegroundColor Gray
|
|
$password = Read-Host "Enter your legacy password" -AsSecureString
|
|
|
|
$legacyMappings = $savedMappings.Mappings | Where-Object { $_.IsLegacy }
|
|
Add-DriveMappings -Mappings $legacyMappings -Username $legacyUser -Password $password
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Read-Host "Press Enter to continue..."
|
|
}
|
|
"6" {
|
|
# Open password portal
|
|
Write-Host ""
|
|
Write-Host "Opening $PasswordResetURL ..." -ForegroundColor Cyan
|
|
Start-Process $PasswordResetURL
|
|
Start-Sleep -Seconds 2
|
|
}
|
|
"q" {
|
|
Write-Host ""
|
|
Write-Host "Goodbye!" -ForegroundColor Cyan
|
|
}
|
|
default {
|
|
Write-Host ""
|
|
Write-Host "Invalid option. Please try again." -ForegroundColor Red
|
|
Start-Sleep -Seconds 1
|
|
}
|
|
}
|
|
} while ($choice.ToLower() -ne 'q')
|