Add fixnetworkshare, winrm-setup-package, udc remote-execution suites
- NetworkDriveManager.ps1: S: drive repair utility - winrm-setup-package: Invoke-RemoteTask helper + Setup-WinRM.bat + HTML guide - remote-execution/udc: UDC_Update.ps1 and batch wrappers for updating DNC controllers on shop-floor PCs - Invoke-RemoteMaintenance.ps1: substantial rework (~1650 lines) - Schedule-Maintenance and complete-asset minor updates - Bump edncfix gitlink to v1.6.0 (2748bfa) - .gitignore: block inventory.csv/xlsx (CUI) and logs_*.txt (per-host logs) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -68,11 +68,41 @@ param(
|
||||
[string]$Password
|
||||
)
|
||||
|
||||
$credFile = Join-Path $PSScriptRoot ".maintenance-cred.xml"
|
||||
$credDir = Join-Path $PSScriptRoot ".creds"
|
||||
$keyFile = Join-Path $credDir "aes.key"
|
||||
$userFile = Join-Path $credDir "username.txt"
|
||||
$passFile = Join-Path $credDir "password.txt"
|
||||
$scriptDir = $PSScriptRoot
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Save credentials (DPAPI - only decryptable by this user on this machine)
|
||||
# Helper: load or create AES key (works across all user contexts on this PC)
|
||||
# ---------------------------------------------------------------------------
|
||||
function Get-AESKey {
|
||||
if (-not (Test-Path $credDir)) {
|
||||
New-Item -Path $credDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
if (Test-Path $keyFile) {
|
||||
return [byte[]](Get-Content $keyFile)
|
||||
}
|
||||
$key = New-Object byte[] 32
|
||||
[System.Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($key)
|
||||
$key | Set-Content $keyFile
|
||||
return $key
|
||||
}
|
||||
|
||||
function Load-SavedCredential {
|
||||
if (-not (Test-Path $userFile) -or -not (Test-Path $passFile)) {
|
||||
return $null
|
||||
}
|
||||
$key = Get-AESKey
|
||||
$user = Get-Content $userFile
|
||||
$encPass = Get-Content $passFile
|
||||
$secPass = $encPass | ConvertTo-SecureString -Key $key
|
||||
return New-Object System.Management.Automation.PSCredential($user, $secPass)
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Save credentials (AES key file - works from any user context on this PC)
|
||||
# ---------------------------------------------------------------------------
|
||||
if ($SaveCredential) {
|
||||
if ($Username -and $Password) {
|
||||
@@ -87,9 +117,11 @@ if ($SaveCredential) {
|
||||
Write-Host "No credentials provided. Exiting." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
$cred | Export-Clixml -Path $credFile
|
||||
Write-Host "Credentials saved to: $credFile" -ForegroundColor Green
|
||||
Write-Host "Encrypted with DPAPI - only YOUR user account on THIS machine can decrypt them." -ForegroundColor Yellow
|
||||
$key = Get-AESKey
|
||||
$cred.UserName | Set-Content $userFile
|
||||
$cred.Password | ConvertFrom-SecureString -Key $key | Set-Content $passFile
|
||||
Write-Host "Credentials saved to: $credDir" -ForegroundColor Green
|
||||
Write-Host "Encrypted with AES-256 key - works from any user context (normal or admin)." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "You can now run tasks unattended:" -ForegroundColor Cyan
|
||||
Write-Host " .\Schedule-Maintenance.ps1 -ComputerListFile '.\shopfloor-pcs.txt' -Task Reboot"
|
||||
@@ -113,7 +145,7 @@ if ($CreateScheduledTask) {
|
||||
$absListFile = (Resolve-Path $ComputerListFile -ErrorAction Stop).Path
|
||||
$absScript = Join-Path $scriptDir "Schedule-Maintenance.ps1"
|
||||
|
||||
if (-not (Test-Path $credFile)) {
|
||||
if (-not (Test-Path $passFile)) {
|
||||
Write-Host "ERROR: No saved credentials found. Run with -SaveCredential first." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
@@ -177,20 +209,13 @@ if (-not $ComputerListFile) {
|
||||
}
|
||||
|
||||
# Load saved credentials
|
||||
if (-not (Test-Path $credFile)) {
|
||||
Write-Host "ERROR: No saved credentials found at $credFile" -ForegroundColor Red
|
||||
$cred = Load-SavedCredential
|
||||
if (-not $cred) {
|
||||
Write-Host "ERROR: No saved credentials found in $credDir" -ForegroundColor Red
|
||||
Write-Host "Run with -SaveCredential first to store credentials." -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
try {
|
||||
$cred = Import-Clixml -Path $credFile
|
||||
Write-Host "Loaded saved credentials for: $($cred.UserName)" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "ERROR: Failed to load credentials: $_" -ForegroundColor Red
|
||||
Write-Host "Re-run with -SaveCredential to save new credentials." -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
Write-Host "Loaded saved credentials for: $($cred.UserName)" -ForegroundColor Green
|
||||
|
||||
# Log output
|
||||
$logDir = Join-Path $scriptDir "logs"
|
||||
@@ -202,7 +227,41 @@ Write-Host "Log: $logFile" -ForegroundColor Gray
|
||||
|
||||
$mainScript = Join-Path $scriptDir "Invoke-RemoteMaintenance.ps1"
|
||||
|
||||
& $mainScript -ComputerListFile $ComputerListFile -Task $Task -Credential $cred 2>&1 | Tee-Object -FilePath $logFile
|
||||
Start-Transcript -Path $logFile -Force | Out-Null
|
||||
& $mainScript -ComputerListFile $ComputerListFile -Task $Task -Credential $cred
|
||||
Stop-Transcript | Out-Null
|
||||
|
||||
# Parse log for results summary
|
||||
$logContent = Get-Content $logFile -ErrorAction SilentlyContinue
|
||||
$okPCs = @($logContent | Select-String '\[OK\]\s+(\S+)' | ForEach-Object { $_.Matches[0].Groups[1].Value })
|
||||
$failPCs = @($logContent | Select-String '\[FAIL\]\s+(\S+)' | ForEach-Object { $_.Matches[0].Groups[1].Value } | Where-Object { $_ -ne ':' } | Sort-Object -Unique)
|
||||
|
||||
$summaryFile = Join-Path $logDir "LAST-RUN-SUMMARY.txt"
|
||||
$summary = @()
|
||||
$summary += "============================================"
|
||||
$summary += " MAINTENANCE RESULTS - $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
|
||||
$summary += " Task: $Task"
|
||||
$summary += "============================================"
|
||||
$summary += ""
|
||||
$summary += "SUCCEEDED: $($okPCs.Count)"
|
||||
foreach ($pc in $okPCs) { $summary += " [OK] $pc" }
|
||||
$summary += ""
|
||||
$summary += "FAILED: $($failPCs.Count)"
|
||||
foreach ($pc in $failPCs) { $summary += " [FAIL] $pc" }
|
||||
$summary += ""
|
||||
$summary += "Full log: $logFile"
|
||||
|
||||
$summary | Out-File -FilePath $summaryFile -Encoding UTF8
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Complete. Log saved to: $logFile" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "=== RESULTS ===" -ForegroundColor White
|
||||
Write-Host " Succeeded: $($okPCs.Count)" -ForegroundColor Green
|
||||
foreach ($pc in $okPCs) { Write-Host " $pc" -ForegroundColor Green }
|
||||
if ($failPCs.Count -gt 0) {
|
||||
Write-Host " Failed: $($failPCs.Count)" -ForegroundColor Red
|
||||
foreach ($pc in $failPCs) { Write-Host " $pc" -ForegroundColor Red }
|
||||
}
|
||||
Write-Host ""
|
||||
Write-Host "Summary also saved to: $summaryFile" -ForegroundColor Yellow
|
||||
|
||||
Reference in New Issue
Block a user