diff --git a/playbook/utilities/waxtrace-recovery/debug-waxtrace-cal.bat b/playbook/utilities/waxtrace-recovery/debug-waxtrace-cal.bat new file mode 100644 index 0000000..8a420e4 --- /dev/null +++ b/playbook/utilities/waxtrace-recovery/debug-waxtrace-cal.bat @@ -0,0 +1,10 @@ +@echo off +REM Right-click "Run as administrator". Forwards args to debug-waxtrace-cal.ps1. +REM Optional: debug-waxtrace-cal.bat -Asset WJF00159 (overrides machine-number.txt). +REM Output: C:\Logs\WaxTrace\debug-waxtrace-cal.log +powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0debug-waxtrace-cal.ps1" %* +echo. +echo Done. Full log: C:\Logs\WaxTrace\debug-waxtrace-cal.log +echo. +pause +exit /b %ERRORLEVEL% diff --git a/playbook/utilities/waxtrace-recovery/debug-waxtrace-cal.ps1 b/playbook/utilities/waxtrace-recovery/debug-waxtrace-cal.ps1 new file mode 100644 index 0000000..6a233b2 --- /dev/null +++ b/playbook/utilities/waxtrace-recovery/debug-waxtrace-cal.ps1 @@ -0,0 +1,272 @@ +# debug-waxtrace-cal.ps1 - Forensic walkthrough of why the wax/trace +# calibration data did not land in FormTracePak's data dir on a bay. +# +# Captures everything: FTPak install location autodetected (we DO NOT +# trust the hardcoded path), data dir contents at every candidate, +# cal ISO presence + mount + listing, the current on-disk version of +# 09-Setup-WaxAndTrace.ps1 (does it have the direct-copy fix or the old +# vendor-Setup.exe path?), the imaging-time log, and Application event +# log entries for Setup.exe crashes in the last 24 hours. +# +# Run as administrator. Output to C:\Logs\WaxTrace\debug-waxtrace-cal.log +# + console. Paste the log back to support for diagnosis. + +[CmdletBinding()] +param( + [string]$Asset +) + +$logDir = 'C:\Logs\WaxTrace' +if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null } +$logFile = Join-Path $logDir 'debug-waxtrace-cal.log' +Remove-Item $logFile -Force -EA 0 + +function Log { + param([string]$Msg, [string]$Lvl = 'INFO') + $line = '[{0}] [{1}] {2}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Lvl, $Msg + Add-Content -Path $logFile -Value $line -ErrorAction SilentlyContinue + Write-Host $line +} + +Log '=== debug-waxtrace-cal.ps1 ===' +Log "User: $([Security.Principal.WindowsIdentity]::GetCurrent().Name)" +Log "Host: $env:COMPUTERNAME" + +# ---------- Section 1: Asset tag ---------- +Log '' +Log '--- 1. ASSET TAG ---' +if (-not $Asset) { + $mn = 'C:\Enrollment\machine-number.txt' + if (Test-Path $mn) { + $Asset = (Get-Content $mn -First 1 -EA 0).Trim() + Log "machine-number.txt: '$Asset'" + } else { + Log "machine-number.txt MISSING at $mn" 'WARN' + } +} +Log "Using asset: $Asset" + +# ---------- Section 2: locate FormTracePak install ---------- +Log '' +Log '--- 2. FORMTRACEPAK INSTALL LOCATION ---' +$candidatePaths = @( + 'C:\Program Files (x86)\MitutoyoApp\Formtracepak', + 'C:\Program Files\MitutoyoApp\Formtracepak', + 'C:\Program Files (x86)\Mitutoyo\Formtracepak', + 'C:\Program Files\Mitutoyo\Formtracepak', + 'C:\MitutoyoApp\Formtracepak', + 'C:\Mitutoyo\Formtracepak' +) +$ftpakRoot = $null +foreach ($p in $candidatePaths) { + $exe = Join-Path $p 'Formtracepak.exe' + if (Test-Path -LiteralPath $exe) { + $ftpakRoot = $p + Log "FOUND Formtracepak.exe at: $exe" + break + } else { + Log " miss: $p" + } +} + +if (-not $ftpakRoot) { + Log 'No Formtracepak.exe at any expected path - searching C:\ Program Files trees...' + $hits = @() + foreach ($pf in @('C:\Program Files', 'C:\Program Files (x86)', 'C:\Mitutoyo', 'C:\MitutoyoApp')) { + if (-not (Test-Path $pf)) { continue } + $hits += Get-ChildItem -Path $pf -Filter 'Formtracepak.exe' -Recurse -File -ErrorAction SilentlyContinue + } + if ($hits) { + Log "Brute-force search hits:" + $hits | ForEach-Object { Log " $($_.FullName)" } + $ftpakRoot = Split-Path $hits[0].FullName -Parent + } else { + Log 'NO Formtracepak.exe ANYWHERE on C:\ - FormTracePak install likely never completed.' 'ERROR' + } +} + +# ---------- Section 3: data dir + contents ---------- +Log '' +Log '--- 3. FORMTRACEPAK DATA DIR ---' +if ($ftpakRoot) { + $dataDir = Join-Path $ftpakRoot 'data' + Log "Expected data dir: $dataDir" + if (Test-Path -LiteralPath $dataDir) { + $files = Get-ChildItem -LiteralPath $dataDir -File -EA 0 | Sort-Object Name + if ($files) { + Log "Data dir contents ($($files.Count) files):" + foreach ($f in $files) { + Log " $($f.Name) ($($f.Length) bytes, modified $($f.LastWriteTime))" + } + } else { + Log 'Data dir EXISTS but is EMPTY' 'WARN' + } + # Look for any cal files matching the asset's probe ID + $probeMatches = $files | Where-Object { $_.Name -match '218-\d{3}-\d+' } + if ($probeMatches) { + Log 'Files with probe-ID pattern (cal data candidates):' + foreach ($f in $probeMatches) { Log " hit: $($f.Name)" } + } else { + Log 'NO files matching the 218-XXX-XX probe-ID pattern in data dir.' 'WARN' + } + } else { + Log "Data dir MISSING at $dataDir" 'ERROR' + Log "Parent dir contents:" + Get-ChildItem -LiteralPath $ftpakRoot -EA 0 | ForEach-Object { Log " $($_.Name)" } + } +} else { + Log 'Skipping data-dir check (FTPak install not found)' +} + +# ---------- Section 4: cal ISO present at C:\WaxTrace-Install\calibrations\ ---------- +Log '' +Log '--- 4. CAL ISO ON LOCAL DISK ---' +$calDir = 'C:\WaxTrace-Install\calibrations' +if (Test-Path -LiteralPath $calDir) { + $allCals = Get-ChildItem -LiteralPath $calDir -Filter 'CAL-*.iso' -File -EA 0 + Log "Cal staging dir: $calDir ($($allCals.Count) ISO files total)" + if ($Asset) { + $matched = $allCals | Where-Object { $_.Name -like "CAL-${Asset}_*" } + if ($matched) { + Log "ISO matching this asset:" + foreach ($f in $matched) { Log " $($f.Name) ($([math]::Round($f.Length/1KB,1)) KB)" } + } else { + Log "NO ISO matches CAL-${Asset}_*.iso in $calDir" 'ERROR' + Log "Available ISOs (first 8):" + $allCals | Select-Object -First 8 | ForEach-Object { Log " $($_.Name)" } + } + } +} else { + Log "Cal staging dir MISSING: $calDir - startnet.cmd did not xcopy installers-post\waxtrace at imaging time, OR 09-Setup-WaxAndTrace.ps1 already deleted it (Step 5 cleanup)." 'ERROR' +} + +# ---------- Section 5: mount the matching cal ISO and list contents ---------- +Log '' +Log '--- 5. MOUNT CAL ISO + LIST CONTENTS ---' +if ($Asset -and (Test-Path -LiteralPath $calDir)) { + $iso = Get-ChildItem -LiteralPath $calDir -Filter "CAL-${Asset}_*.iso" -EA 0 | Select-Object -First 1 + if ($iso) { + try { + $img = Mount-DiskImage -ImagePath $iso.FullName -PassThru -ErrorAction Stop + Start-Sleep -Seconds 5 + $vol = Get-DiskImage -ImagePath $iso.FullName | Get-Volume + $drive = $vol.DriveLetter + if ($drive) { + Log "Mounted at ${drive}:\ (label=$($vol.FileSystemLabel))" + $items = [System.IO.Directory]::GetFileSystemEntries("${drive}:\", '*', 'AllDirectories') + foreach ($i in $items) { + try { + $fi = [System.IO.FileInfo]::new($i) + if ($fi.Attributes -band [System.IO.FileAttributes]::Directory) { + Log " DIR $i" + } else { + Log " FILE $i ($($fi.Length) bytes)" + } + } catch { Log " $i" } + } + } else { + Log "Mount succeeded but no drive letter assigned" 'ERROR' + } + Dismount-DiskImage -ImagePath $iso.FullName -EA 0 | Out-Null + Log "Cal ISO dismounted" + } catch { + Log "Mount failed: $_" 'ERROR' + } + } +} + +# ---------- Section 6: on-disk version of 09-Setup-WaxAndTrace.ps1 ---------- +Log '' +Log '--- 6. 09-SETUP-WAXANDTRACE.PS1 ON DISK ---' +$setupPath = 'C:\Enrollment\shopfloor-setup\gea-shopfloor-waxtrace\09-Setup-WaxAndTrace.ps1' +if (Test-Path -LiteralPath $setupPath) { + $fi = Get-Item $setupPath + Log "Path: $setupPath" + Log " size: $($fi.Length) bytes, mtime: $($fi.LastWriteTime)" + $content = Get-Content -LiteralPath $setupPath -Raw + $hasDirectCopy = $content -match 'hasBrokenFilenames' + $hasV6213 = $content -match 'V6\.213' + $vendorOnly = $content -match 'calSetup.*Setup\.exe' -and -not $hasDirectCopy + Log " Direct-copy bypass present (hasBrokenFilenames): $hasDirectCopy" + Log " V6.213 baseline references: $hasV6213" + if (-not $hasDirectCopy) { + Log ' !!! This bay has the OLD 09-Setup-WaxAndTrace.ps1 without the direct-copy fix.' 'ERROR' + Log ' !!! 218-378-13 series cal discs WILL crash setup.exe with .NET unhandled exception.' 'ERROR' + Log ' !!! Pull the latest from the share: copy /Y \\172.16.9.1\enrollment\shopfloor-setup\gea-shopfloor-waxtrace\09-Setup-WaxAndTrace.ps1 to local.' 'ERROR' + } +} else { + Log "09-Setup-WaxAndTrace.ps1 NOT FOUND at expected path $setupPath" 'WARN' +} + +# Also check C:\WaxTrace-Install copy (staged from share at WinPE time) +$setupStaging = 'C:\WaxTrace-Install\09-Setup-WaxAndTrace.ps1' +if (Test-Path -LiteralPath $setupStaging) { + $fi = Get-Item $setupStaging + $content = Get-Content -LiteralPath $setupStaging -Raw + $hasDirectCopy = $content -match 'hasBrokenFilenames' + Log "Staging copy at $setupStaging :" + Log " size: $($fi.Length), mtime: $($fi.LastWriteTime), has direct-copy: $hasDirectCopy" +} + +# ---------- Section 7: imaging-time log content ---------- +Log '' +Log '--- 7. 09-SETUP-WAXANDTRACE.LOG CONTENT (cal sections) ---' +$wtLog = 'C:\Logs\WaxTrace\09-Setup-WaxAndTrace.log' +if (Test-Path -LiteralPath $wtLog) { + Log "Tail of $wtLog (last 40 lines + cal-related lines):" + $tail = Get-Content -LiteralPath $wtLog -Tail 40 -EA 0 + foreach ($l in $tail) { Log " $l" } + Log '' + Log 'cal/calibration/setup/copy/Mount-DiskImage matching lines:' + Select-String -LiteralPath $wtLog -Pattern 'cal|calibration|copied|direct copy|Mount-DiskImage|setup\.exe exit|hasBrokenFilenames' -SimpleMatch:$false -EA 0 | + Select-Object -Last 30 | ForEach-Object { Log " L$($_.LineNumber): $($_.Line)" } +} else { + Log "$wtLog MISSING - 09-Setup-WaxAndTrace.ps1 never ran (or never reached transcript start)." 'WARN' +} + +# ---------- Section 8: Event log .NET Runtime crashes ---------- +Log '' +Log '--- 8. EVENT LOG (.NET Runtime / Application Error / WER, last 24h) ---' +$cutoff = (Get-Date).AddHours(-24) +foreach ($lname in @('Application')) { + try { + $events = Get-WinEvent -FilterHashtable @{ + LogName = $lname + StartTime = $cutoff + ProviderName = @('.NET Runtime', 'Application Error', 'Windows Error Reporting') + } -ErrorAction Stop | Where-Object { $_.Message -match 'setup\.exe|Setup\.exe|MitutoyoLauncher|Formtracepak|FileSystemInfo|set_Attributes' } | + Select-Object -First 5 + if ($events) { + foreach ($e in $events) { + Log "Event $($e.Id) [$($e.LevelDisplayName)] from $($e.ProviderName) at $($e.TimeCreated)" + $e.Message -split "`n" | Select-Object -First 10 | ForEach-Object { Log " $_" } + } + } else { + Log "No matching .NET/AppError events in last 24h" + } + } catch {} +} + +# ---------- Section 9: scoped search for cal data on known dirs ---------- +Log '' +Log '--- 9. SCOPED CAL FILE SEARCH (Mitutoyo / Hexagon known dirs) ---' +$searchRoots = @( + 'C:\Program Files (x86)\MitutoyoApp', + 'C:\Program Files\MitutoyoApp', + 'C:\Program Files (x86)\Mitutoyo', + 'C:\Program Files\Mitutoyo', + 'C:\MitutoyoApp', + 'C:\Mitutoyo', + 'C:\ProgramData\Mitutoyo' +) +foreach ($r in $searchRoots) { + if (-not (Test-Path -LiteralPath $r)) { continue } + $hits = @(Get-ChildItem -Path $r -Include 'Frc_*.txt','Linear_X_*.txt','Linear_Zl_*.txt','Str_XZ_*.txt','cvifdll.ini','CVIFDLL.ini' -Recurse -ErrorAction SilentlyContinue -Force) + if ($hits) { + Log "Under $r :" + $hits | Select-Object -First 10 | ForEach-Object { Log " $($_.FullName) ($($_.Length) bytes, $($_.LastWriteTime))" } + } +} + +Log '' +Log "=== debug-waxtrace-cal.ps1 end. Output: $logFile ===" diff --git a/playbook/utilities/waxtrace-recovery/fix-waxtrace-cal.bat b/playbook/utilities/waxtrace-recovery/fix-waxtrace-cal.bat new file mode 100644 index 0000000..59042f5 --- /dev/null +++ b/playbook/utilities/waxtrace-recovery/fix-waxtrace-cal.bat @@ -0,0 +1,12 @@ +@echo off +REM fix-waxtrace-cal.bat - Double-click launcher for fix-waxtrace-cal.ps1. +REM Right-click "Run as administrator" so files can land under Program Files. +REM Forwards args, e.g.: +REM fix-waxtrace-cal.bat -Asset WJF00159 +REM If no -Asset is passed the script reads C:\Enrollment\machine-number.txt. +powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0fix-waxtrace-cal.ps1" %* +echo. +echo Done. Full log: C:\Logs\WaxTrace\fix-waxtrace-cal.log +echo. +pause +exit /b %ERRORLEVEL% diff --git a/playbook/utilities/waxtrace-recovery/fix-waxtrace-cal.ps1 b/playbook/utilities/waxtrace-recovery/fix-waxtrace-cal.ps1 new file mode 100644 index 0000000..49b123a --- /dev/null +++ b/playbook/utilities/waxtrace-recovery/fix-waxtrace-cal.ps1 @@ -0,0 +1,175 @@ +# fix-waxtrace-cal.ps1 - Repair the wax/trace calibration apply when the +# 09-Setup-WaxAndTrace.ps1 cal step failed during imaging. +# +# Diagnoses + applies in one pass: +# 1. Reads C:\Enrollment\machine-number.txt for the asset tag (e.g. +# WJF00159) or accepts -Asset on the command line. +# 2. Finds the matching cal ISO under C:\WaxTrace-Install\calibrations\. +# 3. Mounts it. Lists contents to the log. +# 4. Auto-detects FormTracePak data dir. +# 5. Copies data\*.* into the FormTracePak data dir, renaming any +# file whose probe-ID has a trailing space (Mitutoyo 218-378-13 disc +# burn-time typo - their own .NET Setup.exe crashes on this; ours +# heals the name). +# 6. Clears read-only on each landed file. +# 7. Dismounts. Verifies cal files present on disk. +# +# Run as administrator (the destination is under Program Files (x86)). +# +# Log: C:\Logs\WaxTrace\fix-waxtrace-cal.log + +[CmdletBinding()] +param( + [string]$Asset, + [string]$CalDir = 'C:\WaxTrace-Install\calibrations', + [string]$FtPakRoot = 'C:\Program Files (x86)\MitutoyoApp\Formtracepak' +) + +$logDir = 'C:\Logs\WaxTrace' +if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null } +$logFile = Join-Path $logDir 'fix-waxtrace-cal.log' + +function Log { + param([string]$Msg, [string]$Lvl = 'INFO') + $line = '[{0}] [{1}] {2}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Lvl, $Msg + Add-Content -Path $logFile -Value $line -ErrorAction SilentlyContinue + Write-Host $line +} + +Log "=== fix-waxtrace-cal.ps1 start ===" +Log "User: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)" + +# --- Resolve asset --- +if (-not $Asset) { + $mnFile = 'C:\Enrollment\machine-number.txt' + if (Test-Path -LiteralPath $mnFile) { + $Asset = (Get-Content $mnFile -First 1).Trim() + } +} +if (-not $Asset) { + Log "No asset tag (pass -Asset or set C:\Enrollment\machine-number.txt)" 'ERROR' + exit 1 +} +Log "Asset: $Asset" + +# --- Verify FTPak install location exists --- +$dataDir = Join-Path $FtPakRoot 'data' +if (-not (Test-Path -LiteralPath $FtPakRoot)) { + Log "FormTracePak install root not found at $FtPakRoot" 'ERROR' + Log "Cannot apply cal data without FormTracePak. Install it first via 09-Setup-WaxAndTrace.ps1." 'ERROR' + exit 1 +} +if (-not (Test-Path -LiteralPath $dataDir)) { + Log "FormTracePak data dir not found at $dataDir - creating it" 'WARN' + try { New-Item -ItemType Directory -Path $dataDir -Force | Out-Null } catch { Log "Failed to create data dir: $_" 'ERROR'; exit 1 } +} +Log "FormTracePak data dir: $dataDir" + +# --- Find ISO --- +$iso = Get-ChildItem -Path $CalDir -Filter "CAL-${Asset}_*.iso" -ErrorAction SilentlyContinue | Select-Object -First 1 +if (-not $iso) { + Log "No cal ISO matched CAL-${Asset}_*.iso in $CalDir" 'ERROR' + Log "Available ISOs in $CalDir :" 'INFO' + Get-ChildItem -Path $CalDir -Filter 'CAL-*.iso' -ErrorAction SilentlyContinue | ForEach-Object { Log " $($_.Name)" } + exit 1 +} +Log "Cal ISO: $($iso.FullName)" + +# --- Mount --- +try { + $img = Mount-DiskImage -ImagePath $iso.FullName -PassThru -ErrorAction Stop + Start-Sleep -Seconds 5 + $vol = Get-DiskImage -ImagePath $iso.FullName | Get-Volume + $drive = $vol.DriveLetter + if (-not $drive) { + Log "Mount succeeded but no drive letter assigned" 'ERROR' + exit 1 + } + $root = "${drive}:\" + Log "Mounted at $root (label=$($vol.FileSystemLabel))" +} catch { + Log "Mount failed: $_" 'ERROR' + exit 1 +} + +# --- Find source data dir on the disc --- +$srcCandidates = @( + (Join-Path $root 'data'), + (Join-Path $root 'Data'), + (Join-Path $root 'DATA') +) +$srcDataDir = $null +foreach ($p in $srcCandidates) { + if (Test-Path -LiteralPath $p) { $srcDataDir = $p; break } +} +if (-not $srcDataDir) { + Log "No data dir on cal ISO at any of: $($srcCandidates -join ', ')" 'ERROR' + Dismount-DiskImage -ImagePath $iso.FullName -ErrorAction SilentlyContinue | Out-Null + exit 1 +} +Log "Source data dir on cal disc: $srcDataDir" + +# --- Copy with filename heal --- +$copied = 0 +$failed = 0 +Get-ChildItem -LiteralPath $srcDataDir -File -ErrorAction SilentlyContinue | ForEach-Object { + # Mitutoyo 218-378-13 series discs have a probe-ID typo: filename + # contains '218-378-13 _.txt' (space before underscore). Strip + # the space so the file lands with the correct canonical name that + # FormTracePak's CVIF loader expects. + $cleanName = $_.Name -replace ' _', '_' + $dst = Join-Path $dataDir $cleanName + try { + Copy-Item -LiteralPath $_.FullName -Destination $dst -Force -ErrorAction Stop + try { (Get-Item -LiteralPath $dst).Attributes = 'Normal' } catch {} + if ($_.Name -ne $cleanName) { + Log " Copied + renamed: $($_.Name) -> $cleanName" + } else { + Log " Copied: $($_.Name)" + } + $copied++ + } catch { + Log " Copy FAILED for $($_.Name): $_" 'ERROR' + $failed++ + } +} + +# --- Also copy cvifdll.ini if it lives at the disc root (some 218-378-13 +# discs put it inside data/, older 218-458A put it in data/, but neither +# put it at root - leave this as a guard) --- +$rootIni = Join-Path $root 'cvifdll.ini' +if (Test-Path -LiteralPath $rootIni) { + try { + Copy-Item -LiteralPath $rootIni -Destination (Join-Path $dataDir 'cvifdll.ini') -Force -ErrorAction Stop + Log " Copied root-level cvifdll.ini" + $copied++ + } catch { Log " cvifdll.ini copy failed: $_" 'WARN' } +} + +Log "Copy summary: $copied file(s) copied, $failed failure(s)" + +# --- Dismount --- +try { + Dismount-DiskImage -ImagePath $iso.FullName -ErrorAction SilentlyContinue | Out-Null + Log "Cal ISO dismounted" +} catch { Log "Dismount: $_" 'WARN' } + +# --- Verify --- +Log "=== VERIFY ===" +$expectedHits = Get-ChildItem -LiteralPath $dataDir -ErrorAction SilentlyContinue | + Where-Object { $_.Name -match '_\d+\.txt$' -or $_.Name -ieq 'cvifdll.ini' } | + Select-Object Name, Length, LastWriteTime +foreach ($h in $expectedHits) { + Log " $($h.Name) ($($h.Length) bytes, modified $($h.LastWriteTime))" +} +if (-not $expectedHits) { + Log " No cal files visible in $dataDir - apply may have failed" 'WARN' +} + +Log "=== fix-waxtrace-cal.ps1 end ===" +Log "" +Log "Next steps:" +Log " 1. Plug in the HASP USB dongle if not already inserted." +Log " 2. Connect the probe." +Log " 3. Launch FormTracePak (Mitutoyo Launcher) and confirm it loads probe cal data without error." +exit 0