From fce6680c6f508098807bfa3bfe6df8fad0f4ad48 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Sun, 24 May 2026 08:51:30 -0400 Subject: [PATCH] Wax/Trace triad: relocate backup path + harden service enum against SCM hangs Two operator-driven fixes. 1. Backup target moves from S:\2 WJ Scans Record Retention\backup\waxtrace to S:\DT\Shopfloor\backup\waxandtrace per the canonical SFLD layout. Backup creates the per-asset folder if missing; Install reads from the same path by default. 2. Export-FormtracepakInventory hung on step [5/5] when run on a shopfloor PC. The original `Get-Service | Where-Object { DisplayName -match ... }` pattern materializes every service via the Service Control Manager + post filters in PowerShell, which can block indefinitely when any single service (Sentinel HASP driver, GE-Enforce agent, etc.) is in a degraded state. Two-part fix: - Switch to Get-Service -DisplayName 'Mitutoyo*','*FORMTRACEPAK*',... so the SCM only materializes matching services (server-side wildcard filter, faster + lower blast radius). - Wrap the enumeration in Start-Job + Wait-Job -Timeout 30 so a degraded SCM aborts gracefully with a warning rather than wedging the whole inventory pass. Smoke tested on win11 VM: full Export run with the new code completes in 2.9 s and emits the inventory CSV correctly. --- .../scripts/Backup-FormtracepakSettings.ps1 | 6 ++-- .../scripts/Export-FormtracepakInventory.ps1 | 28 +++++++++++++++++-- .../scripts/Install-FormtracepakSettings.ps1 | 4 +-- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Backup-FormtracepakSettings.ps1 b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Backup-FormtracepakSettings.ps1 index 6cccf46..b6986b0 100755 --- a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Backup-FormtracepakSettings.ps1 +++ b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Backup-FormtracepakSettings.ps1 @@ -16,13 +16,13 @@ Asset number (e.g. WJRP1234) used to namespace the backup on the shopfloor share. If omitted, the script prompts interactively and defaults to the current $env:COMPUTERNAME. The asset number is the leaf folder under - S:\2 WJ Scans Record Retention\backup\waxtrace\ + S:\DT\Shopfloor\backup\waxandtrace\ Ignored if -Destination is supplied. .PARAMETER Destination Where to write the ZIP file. Can be a USB drive, network share, or local path. If omitted, defaults to the per-asset path on the mapped S: drive: - S:\2 WJ Scans Record Retention\backup\waxtrace\ + S:\DT\Shopfloor\backup\waxandtrace\ The destination directory is created if it does not exist. .PARAMETER NoZip @@ -45,7 +45,7 @@ param( [switch]$IncludeExecutables ) -$SharedRoot = 'S:\2 WJ Scans Record Retention\backup\waxtrace' +$SharedRoot = 'S:\DT\Shopfloor\backup\waxandtrace' # Resolve the script's own directory robustly. $PSScriptRoot can come through # empty in some hosts (IEX / dot-source / certain remote wrappers), which diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Export-FormtracepakInventory.ps1 b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Export-FormtracepakInventory.ps1 index 76d39e7..088d53d 100755 --- a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Export-FormtracepakInventory.ps1 +++ b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Export-FormtracepakInventory.ps1 @@ -304,8 +304,32 @@ foreach ($pp in $processPatterns) { } } -$services = Get-Service -ErrorAction SilentlyContinue | - Where-Object { $_.DisplayName -match 'Mitutoyo|FORMTRACEPAK|FORMPAK|SURFPAK' } +# Service enumeration. The original `Get-Service | Where-Object { DisplayName -match ... }` +# materializes every service via the Service Control Manager + post-filters +# in PowerShell and has been observed to hang for minutes on shopfloor PCs +# where the SCM or a single service is in a degraded state (Sentinel HASP +# driver / GE-Enforce agent service have both blocked Get-Service before). +# Replace with -DisplayName server-side wildcard filter (the SCM only +# materializes matching services) and wrap in a 30-second runspace fence so +# any further hang aborts gracefully without taking the whole script down. +$serviceJob = Start-Job -ScriptBlock { + Get-Service -DisplayName 'Mitutoyo*','*FORMTRACEPAK*','*FORMPAK*','*SURFPAK*' -ErrorAction SilentlyContinue | + ForEach-Object { + [PSCustomObject]@{ + Name = $_.Name + DisplayName = $_.DisplayName + Status = [string]$_.Status + } + } +} +$services = @() +if (Wait-Job -Job $serviceJob -Timeout 30) { + $services = @(Receive-Job -Job $serviceJob -ErrorAction SilentlyContinue) +} else { + Write-Warning " Service enumeration exceeded 30s timeout - skipping (SCM degraded?)" + Stop-Job -Job $serviceJob -ErrorAction SilentlyContinue +} +Remove-Job -Job $serviceJob -Force -ErrorAction SilentlyContinue foreach ($svc in $services) { Add-Item -Category 'Service' -ItemType 'Service' ` -Path $svc.Name -Name $svc.DisplayName ` diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Install-FormtracepakSettings.ps1 b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Install-FormtracepakSettings.ps1 index 29a745b..8de70fc 100755 --- a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Install-FormtracepakSettings.ps1 +++ b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/scripts/Install-FormtracepakSettings.ps1 @@ -21,7 +21,7 @@ Path to the backup ZIP, directory containing a backup ZIP, or already-extracted backup folder created by Backup-FormtracepakSettings.ps1. If omitted, defaults to the per-asset path on the mapped S: drive: - S:\2 WJ Scans Record Retention\backup\waxtrace\ + S:\DT\Shopfloor\backup\waxandtrace\ If the path is a directory, the newest formtracepak_backup_*.zip inside it is used. .PARAMETER RestoreRegistry @@ -60,7 +60,7 @@ param( [switch]$Force ) -$SharedRoot = 'S:\2 WJ Scans Record Retention\backup\waxtrace' +$SharedRoot = 'S:\DT\Shopfloor\backup\waxandtrace' # Resolve the script's own directory robustly. $PSScriptRoot can come through # empty in some hosts (IEX / dot-source / certain remote wrappers), which