Wax/Trace: heal 218-378-13 cal disc filename bug + VC++ 2017 + picker

09-Setup-WaxAndTrace.ps1 Step 3:
- Detect Mitutoyo's burn-time typo on 218-378-13 series cal discs
  (filenames carry a trailing space inside the probe ID component,
  e.g. "Linear_X_218-378-13 _100072210.txt"). Their own .NET Setup.exe
  calls FileSystemInfo.set_Attributes on the source path and throws
  System.ArgumentException because the path contains an embedded space
  component, crashing every cal apply on 218-378-13 bays (exit
  -532462766 = 0xE0434352, .NET unhandled exception). Confirmed via
  WER Event 1026 captured during today's WJF00159 imaging.
- When the buggy filenames are detected, bypass the broken vendor
  Setup.exe and direct-copy data\*.* into
  C:\Program Files (x86)\MitutoyoApp\Formtracepak\data\, renaming
  each file to strip ' _' (space-underscore) -> '_'. Clear read-only
  attr on each landed file. Older 218-458A discs have clean filenames
  and still use the vendor Setup.exe path.

waxtrace-manifest.json:
- Drop DetectionValue=v14.15.26706 from both VC++ 2017 redist entries.
  Windows Update routinely bumps the VS14 runtime to 14.16+ / 14.3x+,
  the older Mitutoyo redist refuses to install over the newer (exit
  1638 'Another version already installed') and the manifest engine
  marked it as failed even though the runtime was fine. Detection is
  now by registry-key+name presence, which any VC++ 2015-2022 redist
  satisfies (they are backward-compatible).

startnet.cmd:prompt_waxtrace_asset:
- Replace free-text input with select-waxtrace-asset.ps1 arrow-key
  picker driven from installers-post/waxtrace/calibrations/INDEX.csv.
- Map Y: enrollment share early so the picker can read INDEX.csv.
- Replace parens-in-parens block (echo of '(e.g. WJRP2335)' inside
  the if-paren caused 'to was unexpected at this time' parse error
  observed by tech mid-imaging) with goto-flow.
- Fall back to free-text prompt if picker unavailable or operator
  presses Esc.

select-waxtrace-asset.ps1:
- Sort bays descending by asset tag so WJRP* lands at top of menu.
- Also staged as gea-shopfloor-waxtrace/select-waxtrace-asset.ps1 so
  sync-waxtrace.sh ships it to installers-post/waxtrace/ on the share.

sync-waxtrace.sh:
- Push select-waxtrace-asset.ps1 next to INDEX.csv on the share.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-05-21 19:38:19 -04:00
parent e1ea6b7c62
commit 5891a1966f
6 changed files with 202 additions and 27 deletions

View File

@@ -27,7 +27,9 @@ function Read-BayList {
param([string]$Path) param([string]$Path)
if (-not (Test-Path -LiteralPath $Path)) { return @() } if (-not (Test-Path -LiteralPath $Path)) { return @() }
try { try {
return Import-Csv -LiteralPath $Path | Select-Object -Property asset_tag, unit_serial, probe_part return Import-Csv -LiteralPath $Path |
Select-Object -Property asset_tag, unit_serial, probe_part |
Sort-Object -Property asset_tag -Descending
} catch { } catch {
return @() return @()
} }

View File

@@ -164,20 +164,76 @@ if (-not $asset) {
Write-WTLog "Mounting cal ISO: $($candidate.FullName)" Write-WTLog "Mounting cal ISO: $($candidate.FullName)"
try { try {
$img = Mount-DiskImage -ImagePath $candidate.FullName -PassThru -ErrorAction Stop $img = Mount-DiskImage -ImagePath $candidate.FullName -PassThru -ErrorAction Stop
Start-Sleep -Seconds 2 Start-Sleep -Seconds 5
$calDrive = ($img | Get-Volume).DriveLetter $calDrive = (Get-DiskImage -ImagePath $candidate.FullName | Get-Volume).DriveLetter
Write-WTLog " mounted at ${calDrive}:" $calRoot = "${calDrive}:\"
Write-WTLog " mounted at $calRoot"
# Disc layout differs by probe series. We have observed two:
#
# Older 218-458A: E:\App.ini, E:\Setup.exe, E:\data\CVIFDLL.ini,
# E:\data\Cvif_Correction.exe, E:\data\<files>.txt.
# Vendor Setup.exe works (VB6, may prompt).
#
# Newer 218-378-13: E:\setup.bat, E:\setup.exe (.NET 4.0),
# E:\iniStatus\<png>, E:\data\cvifdll.ini,
# E:\data\<files>.txt - BUT the filenames have a
# bug: probe ID ends with a TRAILING SPACE
# ("218-378-13 _100072210.txt"). The vendor's
# .NET Setup.exe calls FileSystemInfo.set_Attributes
# on the source path and throws System.ArgumentException
# because the path contains an embedded space
# component, crashing every time
# (exit -532462766 = 0xE0434352, .NET unhandled
# exception). See diag-cal.log, WER Event 1026.
#
# We bypass the vendor wrapper entirely when the disc carries
# the buggy filenames and do a direct file copy into FormTracePak's
# data dir, renaming each file to strip the trailing space.
$srcDataDir = Join-Path $calRoot 'data'
$dstDataDir = 'C:\Program Files (x86)\MitutoyoApp\Formtracepak\data'
$hasBrokenFilenames = $false
if (Test-Path -LiteralPath $srcDataDir) {
$hasBrokenFilenames = [bool](Get-ChildItem -LiteralPath $srcDataDir -Filter '*[0-9] _*.txt' -ErrorAction SilentlyContinue | Select-Object -First 1)
}
if ($hasBrokenFilenames) {
Write-WTLog " disc has trailing-space probe-ID filenames (218-378-13 series) - bypassing buggy vendor Setup.exe, doing direct copy"
if (-not (Test-Path -LiteralPath $dstDataDir)) {
Write-WTLog " destination data dir does not exist: $dstDataDir" 'ERROR'
Write-WTLog " (FormTracePak install may not be complete; cal apply aborted)" 'ERROR'
} else {
$copied = 0
Get-ChildItem -LiteralPath $srcDataDir -File -ErrorAction SilentlyContinue | ForEach-Object {
# Strip ' _' (space-underscore) -> '_' inside the filename to
# heal the Mitutoyo burn-time typo. cvifdll.ini etc unaffected.
$cleanName = $_.Name -replace ' _', '_'
$dst = Join-Path $dstDataDir $cleanName
try {
Copy-Item -LiteralPath $_.FullName -Destination $dst -Force -ErrorAction Stop
# Clear read-only on the destination so future overwrites work.
try { (Get-Item -LiteralPath $dst).Attributes = 'Normal' } catch {}
Write-WTLog " copied $($_.Name) -> $cleanName"
$copied++
} catch {
Write-WTLog " copy failed for $($_.Name): $_" 'ERROR'
}
}
Write-WTLog " direct copy complete: $copied file(s) into $dstDataDir"
}
} else {
# Older-style disc (clean filenames). Vendor Setup.exe is reliable.
$calSetup = "${calDrive}:\Setup.exe" $calSetup = "${calDrive}:\Setup.exe"
if (Test-Path -LiteralPath $calSetup) { if (Test-Path -LiteralPath $calSetup) {
Write-WTLog " running cal Setup.exe (may prompt - VB6 wrapper, same vintage as main installer)" Write-WTLog " running cal Setup.exe (may prompt - VB6 wrapper, same vintage as main installer)"
# Cal ISO Setup.exe is tiny (135KB) - if it prompts, user has to click through. $p = Start-Process -FilePath $calSetup -WorkingDirectory $calRoot -Wait -PassThru
# Acceptable today; future: dark-deploy the data/*.txt files directly into
# the FormTracePak data dir + skip Setup.exe.
$p = Start-Process -FilePath $calSetup -WorkingDirectory "${calDrive}:\" -Wait -PassThru
Write-WTLog " cal Setup.exe exit $($p.ExitCode)" Write-WTLog " cal Setup.exe exit $($p.ExitCode)"
} else { } else {
Write-WTLog " cal Setup.exe not found on ISO at $calSetup" 'WARN' Write-WTLog " cal Setup.exe not found at $calSetup" 'WARN'
} }
}
Dismount-DiskImage -ImagePath $candidate.FullName -ErrorAction SilentlyContinue | Out-Null Dismount-DiskImage -ImagePath $candidate.FullName -ErrorAction SilentlyContinue | Out-Null
Write-WTLog " cal ISO dismounted" Write-WTLog " cal ISO dismounted"
} catch { } catch {

View File

@@ -0,0 +1,102 @@
# select-waxtrace-asset.ps1 - Arrow-key bay picker for wax/trace imaging.
#
# Reads the calibration INDEX.csv on the PXE share to build the menu of known
# bays. Operator picks with Up/Down arrows + Enter. Always appends an
# "Other (new bay)" option at the end for bays that don't have a cal ISO yet -
# selecting it falls back to a free-text prompt.
#
# Writes the chosen asset tag to $OutFile (one line, no trailing newline).
# startnet.cmd reads that file back into the MACHINENUM batch var.
#
# Runs in WinPE PowerShell. Win10/11 WinPE ships powershell.exe with
# System.Console.ReadKey support. Tested 2026-05-18.
#
# Exit codes:
# 0 = asset tag written to $OutFile
# 1 = user cancelled (Esc) - $OutFile not written
# 2 = INDEX.csv unreadable AND no fallback entered
param(
[string]$IndexPath = 'Y:\installers-post\waxtrace\calibrations\INDEX.csv',
[Parameter(Mandatory=$true)][string]$OutFile
)
$ErrorActionPreference = 'Continue'
function Read-BayList {
param([string]$Path)
if (-not (Test-Path -LiteralPath $Path)) { return @() }
try {
return Import-Csv -LiteralPath $Path |
Select-Object -Property asset_tag, unit_serial, probe_part |
Sort-Object -Property asset_tag -Descending
} catch {
return @()
}
}
function Show-Menu {
param(
[object[]]$Items,
[int]$Selected,
[string]$Title
)
Clear-Host
Write-Host ""
Write-Host " ========================================"
Write-Host " $Title"
Write-Host " ========================================"
Write-Host ""
Write-Host " Up / Down arrows = navigate, Enter = select, Esc = cancel"
Write-Host ""
for ($i = 0; $i -lt $Items.Count; $i++) {
$item = $Items[$i]
$line = if ($item -is [string]) { $item } else { "{0,-10} serial={1,-12} probe={2}" -f $item.asset_tag, $item.unit_serial, $item.probe_part }
if ($i -eq $Selected) {
Write-Host (" > " + $line) -ForegroundColor Black -BackgroundColor White
} else {
Write-Host (" " + $line)
}
}
Write-Host ""
}
$bays = @(Read-BayList -Path $IndexPath)
$menuItems = @()
foreach ($b in $bays) { $menuItems += $b }
$menuItems += '** Other (new bay - enter asset tag manually) **'
$sel = 0
while ($true) {
Show-Menu -Items $menuItems -Selected $sel -Title "Wax/Trace Asset Tag"
$key = [System.Console]::ReadKey($true)
switch ($key.Key) {
'UpArrow' { if ($sel -gt 0) { $sel-- } }
'DownArrow' { if ($sel -lt ($menuItems.Count - 1)) { $sel++ } }
'Enter' {
if ($sel -eq ($menuItems.Count - 1)) {
# Manual entry
Write-Host ""
$manual = Read-Host " Enter asset tag (e.g. WJRP9999) or blank to abort"
if ($manual) {
$manual = $manual.Trim().ToUpper()
Set-Content -LiteralPath $OutFile -Value $manual -NoNewline -Encoding ascii
Write-Host ""
Write-Host " Saved asset tag: $manual"
Start-Sleep -Seconds 1
exit 0
} else {
exit 1
}
} else {
$pick = $bays[$sel].asset_tag
Set-Content -LiteralPath $OutFile -Value $pick -NoNewline -Encoding ascii
Write-Host ""
Write-Host " Selected: $pick"
Start-Sleep -Seconds 1
exit 0
}
}
'Escape' { exit 1 }
}
}

View File

@@ -25,26 +25,24 @@
"DetectionValue": "9.0.21022" "DetectionValue": "9.0.21022"
}, },
{ {
"_comment": "Visual C++ 2017 x86 redist (14.15.26706 = VS2017 Update 7 era). Mitutoyo's vc_redist.x86.exe at Lang\\English\\ on the FormTracePak ISO. Uses VS2015+ universal redist installer flag set.", "_comment": "Visual C++ 2017 x86 redist (Mitutoyo ships 14.15.26706 = VS2017 Update 7 era). Detection by key+name presence only, NOT exact version: Windows Update or other software routinely bumps VS14 runtime to 14.16+ or 14.3x+, and the older Mitutoyo redist refuses to install over the newer (exits non-zero) which the engine then marks as failed even though the runtime is fine. All VS14 / VC++ 2015-2022 redists are backward-compatible so any installed version satisfies FormTracePak.",
"Name": "Microsoft Visual C++ 2017 Redistributable (x86)", "Name": "Microsoft Visual C++ 2017 Redistributable (x86)",
"Installer": "prereqs\\vc_redist.x86.exe", "Installer": "prereqs\\vc_redist.x86.exe",
"Type": "EXE", "Type": "EXE",
"InstallArgs": "/quiet /norestart", "InstallArgs": "/quiet /norestart",
"DetectionMethod": "Registry", "DetectionMethod": "Registry",
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x86", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x86",
"DetectionName": "Version", "DetectionName": "Version"
"DetectionValue": "v14.15.26706"
}, },
{ {
"_comment": "Visual C++ 2017 x64 redist.", "_comment": "Visual C++ 2017 x64 redist. Same key+name-presence detection as x86 (see comment above).",
"Name": "Microsoft Visual C++ 2017 Redistributable (x64)", "Name": "Microsoft Visual C++ 2017 Redistributable (x64)",
"Installer": "prereqs\\vc_redist.x64.exe", "Installer": "prereqs\\vc_redist.x64.exe",
"Type": "EXE", "Type": "EXE",
"InstallArgs": "/quiet /norestart", "InstallArgs": "/quiet /norestart",
"DetectionMethod": "Registry", "DetectionMethod": "Registry",
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64",
"DetectionName": "Version", "DetectionName": "Version"
"DetectionValue": "v14.15.26706"
}, },
{ {
"_comment": "Sentinel Runtime / HASP USB dongle driver from Gemalto (now Thales). Vintage 2019 InstallShield wrapper, classic InstallShield silent install via /s + nested /v args. FormTracePak licensing is dongle-bound; the runtime + drivers must be present before Formtracepak.exe will run. Tech inserts physical HASP USB dongle on the bay post-imaging to license.", "_comment": "Sentinel Runtime / HASP USB dongle driver from Gemalto (now Thales). Vintage 2019 InstallShield wrapper, classic InstallShield silent install via /s + nested /v args. FormTracePak licensing is dongle-bound; the runtime + drivers must be present before Formtracepak.exe will run. Tech inserts physical HASP USB dongle on the bay post-imaging to license.",

View File

@@ -189,13 +189,24 @@ echo Machine number: %MACHINENUM%
goto skip_machinenum goto skip_machinenum
:prompt_waxtrace_asset :prompt_waxtrace_asset
echo. echo.
echo Wax/Trace bays use the asset tag (e.g. WJRP2335) to pick the right echo Loading Wax/Trace bay list from PXE share...
echo calibration ISO during shopfloor setup. REM Mount enrollment share early so the picker can read INDEX.csv. Later
set /p MACHINENUM=Enter asset tag (e.g. WJRP2335): REM net use Y: will be a no-op if Y: is already mapped.
if "%MACHINENUM%"=="" ( net use Y: \\172.16.9.1\enrollment /user:pxe-upload pxe /persistent:no >NUL 2>NUL
echo WARNING: no asset tag entered - calibration apply will be skipped. del X:\waxtrace-asset.txt 2>NUL
if not exist "Y:\installers-post\waxtrace\select-waxtrace-asset.ps1" goto waxtrace_picker_skip
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "Y:\installers-post\waxtrace\select-waxtrace-asset.ps1" -IndexPath "Y:\installers-post\waxtrace\calibrations\INDEX.csv" -OutFile "X:\waxtrace-asset.txt"
:waxtrace_picker_skip
set MACHINENUM= set MACHINENUM=
) if exist X:\waxtrace-asset.txt set /p MACHINENUM=<X:\waxtrace-asset.txt
if not "%MACHINENUM%"=="" goto waxtrace_have_asset
echo.
echo Picker unavailable or cancelled. Falling back to free-text prompt.
echo Wax/Trace bays use the asset tag, e.g. WJRP2335 or WJF00159, to pick
echo the right calibration ISO during shopfloor setup.
set /p MACHINENUM=Enter asset tag:
:waxtrace_have_asset
if "%MACHINENUM%"=="" echo WARNING: no asset tag entered - calibration apply will be skipped.
echo Asset tag: %MACHINENUM% echo Asset tag: %MACHINENUM%
:skip_machinenum :skip_machinenum

View File

@@ -58,6 +58,12 @@ trap "rm -rf $STAGE" EXIT
mkdir -p "$STAGE/prereqs" "$STAGE/calibrations" "$STAGE/formtracepak" mkdir -p "$STAGE/prereqs" "$STAGE/calibrations" "$STAGE/formtracepak"
cp "$WAXTRACE_DIR/waxtrace-manifest.json" "$STAGE/" cp "$WAXTRACE_DIR/waxtrace-manifest.json" "$STAGE/"
cp "$WAXTRACE_DIR/09-Setup-WaxAndTrace.ps1" "$STAGE/" cp "$WAXTRACE_DIR/09-Setup-WaxAndTrace.ps1" "$STAGE/"
# Arrow-key picker invoked from startnet.cmd. Reads INDEX.csv to build the
# menu, falls back to free-text prompt if it errors. Lives next to the
# calibrations dir since it depends on INDEX.csv being adjacent.
if [ -f "$WAXTRACE_DIR/select-waxtrace-asset.ps1" ]; then
cp "$WAXTRACE_DIR/select-waxtrace-asset.ps1" "$STAGE/"
fi
cp "$WAXTRACE_DIR/captured-binary/prereqs/"*.exe "$STAGE/prereqs/" cp "$WAXTRACE_DIR/captured-binary/prereqs/"*.exe "$STAGE/prereqs/"
# FormTracePak v6.213 vendor installer ISO (2 GB). Pulled from # FormTracePak v6.213 vendor installer ISO (2 GB). Pulled from