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.
This commit is contained in:
cproudlock
2026-05-24 08:51:30 -04:00
parent ed12988591
commit fce6680c6f
3 changed files with 31 additions and 7 deletions

View File

@@ -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\<AssetNumber>
S:\DT\Shopfloor\backup\waxandtrace\<AssetNumber>
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

View File

@@ -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 `

View File

@@ -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\<AssetNumber>
S:\DT\Shopfloor\backup\waxandtrace\<AssetNumber>
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