v1.3.0: Fixed header UI + auto-elevate to Administrator

- GE Aerospace ASCII banner stays fixed at top of console
- Live status line updates (Processing, Cleaned, Failed, etc.)
- Live stats counter in header (Cleaned/Failed counts)
- Batch file auto-elevates to Administrator via UAC

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2025-12-12 08:40:35 -05:00
parent ba2dbbefda
commit 9a8b16e0d4
3 changed files with 125 additions and 28 deletions

View File

@@ -36,9 +36,15 @@
.NOTES
Author: GE Aerospace - Rutland
Version: 1.2.1
Version: 1.3.0
Date: 2025-12-12
v1.3.0 - Fixed header UI:
- GE Aerospace ASCII banner stays at top
- Live status updates in header (Processing, Cleaned, Failed)
- Live stats counter (Cleaned/Failed count)
- Auto-elevate to Administrator via batch file
v1.2.0 - Immediate processing:
- Process file immediately when eDNC releases it (50ms initial delay)
- Aggressive retry: 100ms -> 200ms -> 400ms -> 800ms (15 attempts)
@@ -68,38 +74,82 @@ param(
)
# Script info
$ScriptVersion = "1.2.1"
$ScriptVersion = "1.3.0"
$ScriptName = "eDNC Special Character Fix"
# Display banner
Write-Host ""
Write-Host " ____ ____ " -ForegroundColor Cyan
Write-Host " / ___|| ___| / \ ___ _ __ ___ ___ _ __ __ _ ___ ___ " -ForegroundColor Cyan
Write-Host "| | _ | _| / _ \ / _ \ '__/ _ \/ __| '_ \ / _`` |/ __/ _ \" -ForegroundColor Cyan
Write-Host "| |_| || |___ / ___ \ __/ | | (_) \__ \ |_) | (_| | (_| __/" -ForegroundColor Cyan
Write-Host " \____||_____| /_/ \_\___|_| \___/|___/ .__/ \__,_|\___\___|" -ForegroundColor Cyan
Write-Host " |_| " -ForegroundColor Cyan
Write-Host ""
Write-Host " $ScriptName" -ForegroundColor White
Write-Host " by Cam P. | v$ScriptVersion" -ForegroundColor Gray
Write-Host ""
Write-Host "================================================================" -ForegroundColor DarkGray
# Header display function
function Show-Header {
param([int]$Cleaned = 0, [int]$Failed = 0, [string]$Status = "Watching...")
$headerLines = @(
""
" ____ ____ "
" / ___|| ___| / \ ___ _ __ ___ ___ _ __ __ _ ___ ___ "
"| | _ | _| / _ \ / _ \ '__/ _ \/ __| '_ \ / _`` |/ __/ _ \"
"| |_| || |___ / ___ \ __/ | | (_) \__ \ |_) | (_| | (_| __/"
" \____||_____| /_/ \_\___|_| \___/|___/ .__/ \__,_|\___\___|"
" |_| "
""
" $ScriptName"
" by Cam P. | v$ScriptVersion"
""
" Folder: $WatchFolder"
" Filter: $FileFilter | Cleaned: $Cleaned | Failed: $Failed"
""
" Status: $Status"
"================================================================"
)
# Save cursor, go to top, draw header
[Console]::SetCursorPosition(0, 0)
for ($i = 0; $i -lt $headerLines.Count; $i++) {
$line = $headerLines[$i]
# Clear line and write
Write-Host ("`r" + $line.PadRight([Console]::WindowWidth - 1)) -NoNewline
# Apply colors
[Console]::SetCursorPosition(0, $i)
if ($i -ge 1 -and $i -le 6) {
Write-Host $line -ForegroundColor Cyan
} elseif ($i -eq 8) {
Write-Host $line -ForegroundColor White
} elseif ($i -eq 9) {
Write-Host $line -ForegroundColor Gray
} elseif ($i -eq 14) {
if ($Status -like "*ERROR*" -or $Status -like "*FAILED*") {
Write-Host $line -ForegroundColor Red
} elseif ($Status -like "*CLEANED*") {
Write-Host $line -ForegroundColor Green
} else {
Write-Host $line -ForegroundColor Yellow
}
} elseif ($i -eq 15) {
Write-Host $line -ForegroundColor DarkGray
} else {
Write-Host $line
}
}
return $headerLines.Count
}
# Initialize console
Clear-Host
$script:HeaderHeight = Show-Header -Status "Initializing..."
# Validate watch folder exists
if (-not (Test-Path $WatchFolder)) {
Write-Host "[ERROR] Watch folder does not exist: $WatchFolder" -ForegroundColor Red
Show-Header -Status "ERROR: Watch folder does not exist!"
[Console]::SetCursorPosition(0, $script:HeaderHeight + 1)
Write-Host "Please create the folder or specify a different path." -ForegroundColor Yellow
exit 1
}
# Display configuration
Write-Host "Configuration:" -ForegroundColor Yellow
Write-Host " Watch Folder: $WatchFolder"
Write-Host " File Filter: $FileFilter"
Write-Host " Subfolders: $IncludeSubfolders"
Write-Host " Removing bytes: $($CharactersToRemove -join ', ') (0x$($CharactersToRemove | ForEach-Object { '{0:X2}' -f $_ } | Join-String -Separator ', 0x'))"
Write-Host ""
Write-Host "Watching for files... Press Ctrl+C to stop" -ForegroundColor Green
# Update header with ready status
Show-Header -Status "Watching for files... (Ctrl+C to stop)" | Out-Null
[Console]::SetCursorPosition(0, $script:HeaderHeight + 1)
Write-Host "Removing bytes: $($CharactersToRemove -join ', ') (0x$($CharactersToRemove | ForEach-Object { '{0:X2}' -f $_ } | Join-String -Separator ', 0x'))" -ForegroundColor DarkGray
Write-Host ""
# Statistics
@@ -127,6 +177,24 @@ $action = {
# Get parameters from message data
$charsToRemove = $Event.MessageData.CharsToRemove
$debounceSeconds = $Event.MessageData.DebounceSeconds
$statusLine = $Event.MessageData.StatusLine
# Helper to update status line in header
$updateStatus = {
param($msg, $color = "Yellow")
$savedPos = [Console]::CursorTop
[Console]::SetCursorPosition(0, $statusLine)
Write-Host (" Status: " + $msg).PadRight([Console]::WindowWidth - 1) -ForegroundColor $color
[Console]::SetCursorPosition(0, $savedPos)
}
# Helper to update stats line in header
$updateStats = {
$savedPos = [Console]::CursorTop
[Console]::SetCursorPosition(0, 12)
Write-Host (" Filter: $($Event.MessageData.FileFilter) | Cleaned: $($script:FilesProcessed) | Failed: $($script:FailedFiles)").PadRight([Console]::WindowWidth - 1) -ForegroundColor White
[Console]::SetCursorPosition(0, $savedPos)
}
# Debounce check - skip if we processed this file recently
$now = Get-Date
@@ -137,6 +205,7 @@ $action = {
}
}
& $updateStatus "Processing: $fileName" "Yellow"
Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | $changeType | $fileName" -ForegroundColor White
# Brief initial delay to let eDNC finish (50ms)
@@ -186,8 +255,11 @@ $action = {
Write-Host " [CLEANED] Removed $removed byte(s)" -ForegroundColor Green
$script:FilesProcessed++
$script:BytesRemoved += $removed
& $updateStatus "CLEANED: $fileName ($removed bytes)" "Green"
& $updateStats
} else {
Write-Host " [OK] No special characters found" -ForegroundColor Gray
& $updateStatus "OK: $fileName (no changes)" "Gray"
}
# Mark as recently processed
@@ -197,18 +269,23 @@ $action = {
catch [System.IO.IOException] {
$retryCount++
if ($retryCount -lt $maxRetries) {
# Exponential backoff: 500ms, 1s, 2s, 4s, 8s, 16s...
# Exponential backoff: 100ms, 200ms, 400ms, 800ms...
$delay = [math]::Min($baseDelay * [math]::Pow(2, $retryCount - 1), 16000)
Write-Host " [RETRY] File locked, waiting $([math]::Round($delay/1000, 1))s... ($retryCount/$maxRetries)" -ForegroundColor Yellow
& $updateStatus "RETRY: $fileName ($retryCount/$maxRetries)" "Yellow"
Start-Sleep -Milliseconds $delay
} else {
Write-Host " [FAILED] Could not access file after $maxRetries attempts" -ForegroundColor Red
$script:FailedFiles++
& $updateStatus "FAILED: $fileName" "Red"
& $updateStats
}
}
catch {
Write-Host " [ERROR] $($_.Exception.Message)" -ForegroundColor Red
$script:FailedFiles++
& $updateStatus "ERROR: $fileName" "Red"
& $updateStats
break
}
finally {
@@ -224,6 +301,8 @@ $action = {
$messageData = @{
CharsToRemove = $CharactersToRemove
DebounceSeconds = $script:DebounceSeconds
StatusLine = 14 # Line number for status updates
FileFilter = $FileFilter
}
# Register event handlers