Commit Graph

23 Commits

Author SHA1 Message Date
cproudlock
c88b2b0ab8 Wax/Trace: classify restore .reg by content root, not filename
Install-FormtracepakSettings decided per-user vs HKLM by matching the
filename against 'HKEY_USERS'. The backup names files after their source
path, so an operator pref captured from HKCU:\ lands in a file named
"HKCU_..." with content root HKEY_CURRENT_USER - which the filename match
missed entirely, dropping it from the restore.

Read each .reg once and classify by its content root(s):
  [HKEY_CURRENT_USER...  -> per-user, remap root to HKEY_USERS\<targetSid>
  [HKEY_USERS\<srcSid>... -> per-user, remap srcSid -> targetSid
  [HKEY_LOCAL_MACHINE...  -> HKLM
The temp rewrite (UTF-16-LE for reg.exe import) is only written when the
content actually changes; otherwise the file imports as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 11:54:00 -04:00
cproudlock
1860a92afa 09-Setup-WaxAndTrace: bypass vendor cal Setup.exe for all 218-378-13 probes
The .NET cal Setup.exe crashes (0xE0434352) on 218-378-13 series ISOs
even when filenames are clean (no trailing-space bug). Previously only
bypassed when the ' _' trailing-space signature was detected. Now
detects by probe series ID in the data filenames too and always does
direct file copy for 218-378-13.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 13:06:57 -04:00
cproudlock
9ad467ba6c 09-Setup-WaxAndTrace: fix stale $backupDir in no-backup log message
The variable was renamed to $backupDirCandidates + $bd loop but the
else-branch log message still referenced the old $backupDir, producing
a malformed path like "\.zip" in the log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 13:05:14 -04:00
cproudlock
9b46d0279f select-waxtrace-asset: fix blank serial/probe columns in bay picker
The picker was reading unit_serial and probe_part from the old INDEX.csv
format. bay-config.csv uses different column names (ftpak_version, model,
host). Updated Select-Object and display format to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 12:20:37 -04:00
cproudlock
de7d41f5e5 Wax/Trace: defer HKEY_USERS per-user prefs restore to first ShopFloor logon via SYSTEM scheduled task
Bay's ShopFloor user account exists but has never logged in at imaging
time, so its NTUSER.DAT doesn't exist yet and we can't reg-load its
hive to remap source SID -> ShopFloor SID. The in-line restore at
09-Setup Step 3b handles HKLM (controller config, device-map) + files,
but per-user prefs (LouteditS Layout, Page margins, Recent Files, ~2700
rows in a typical WJF capture) get skipped.

Fix: register a SYSTEM-context scheduled task at imaging time that
fires AtLogOn UserId=ShopFloor. When ShopFloor first logs in, Windows
loads their NTUSER.DAT automatically; task fires (running as SYSTEM
so lockdown policies on ShopFloor's user-context don't block HKLM
writes via the same Install script); SID-remap path finds the live
hive and writes prefs into HKEY_USERS\<ShopFloor-sid>. Task writes a
flag file + unregisters itself after one successful run.

Pieces:
- Install-FormtracepakSettings.ps1: new -HKEYUsersOnly switch that
  skips the HKLM .reg files + HKLM CSV rows (already restored at
  imaging time). Fallback user chain ShopFloor->SupportUser->$USERNAME.
- Schedule-WaxTracePerUserRestore.ps1: registers the task, writes
  C:\WaxTrace-Install\Run-WaxTracePerUserRestore.ps1 task action which
  invokes Install with -HKEYUsersOnly and self-cleans on success.
- 09-Setup-WaxAndTrace.ps1 Step 3b: in-line restore now uses
  -RestoreRegistry -RestoreData -RestoreConfig (HKLM + files now);
  calls Schedule-WaxTracePerUserRestore.ps1 to queue HKEY_USERS for
  first ShopFloor logon.
- sync-waxtrace.sh: pushes Schedule-WaxTracePerUserRestore.ps1 to
  PXE share alongside Install-FormtracepakSettings.ps1.

Smoke tested on win11 VM partially: task registration works, manual
trigger fires + self-unregisters cleanly, flag file lands. Real per-
user SID-remap happens at first ShopFloor logon (can't simulate from
qga without an interactive ShopFloor session).
2026-05-24 16:19:45 -04:00
cproudlock
77c917157d select-waxtrace-asset.ps1: read bay-config.csv (17 bays) by default
Picker was still pointed at calibrations/INDEX.csv, which only listed
14 bays that have a per-asset cal ISO ripped. Three bays we just
refreshed into bay-config.csv (WJF00450, WJF00461, WJRP0423) had no
cal-disc entry, so they fell off the menu and tech had to drop to the
free-text prompt to type the asset by hand - felt like a regression.

Two changes:
- select-waxtrace-asset.ps1: prefer bay-config.csv when -IndexPath
  points there (now the default). Auto-detect schema by checking for
  the ftpak_version column. Display columns become
  ASSET / FTPAK / MODEL / USER ID so the tech can confirm bay metadata
  at a glance before pressing Enter. Falls back to
  calibrations/INDEX.csv if bay-config.csv missing.
- startnet.cmd: invoke the picker with -IndexPath bay-config.csv.

Pushed: both boot.wim copies refreshed via wimupdate, new
select-waxtrace-asset.ps1 deployed to PXE share, new boot.wim landed
at /var/www/html/win11/sources/boot.wim on 172.16.9.1.

bay-config.csv parent-dir copy synced with scripts/bay-config.csv so
resolve-bay-config.ps1 (called from startnet.cmd in WinPE) and the
picker both see the same 17-bay set.
2026-05-24 13:12:03 -04:00
cproudlock
d0dcce5427 Wax/Trace: auto-restore captured backup ZIP during imaging
Wires the three pieces that make the per-bay backup restore happen as
part of the PXE imaging pass, no manual post-imaging step required:

1. sync-waxtrace.sh: stage per-asset backup ZIPs from
   /home/camp/pxe-images/wt/<asset>/formtracepak_backup_*.zip (newest)
   into installers-post/waxtrace/backups/<asset>.zip on the PXE share.
   Also pushes scripts/Install-FormtracepakSettings.ps1 alongside the
   bootstrap bundle so 09-Setup can call it post-vendor-install.
2. startnet.cmd: after the FTPak ISO cherry-pick, xcopy
   Y:\installers-post\waxtrace\backups\%MACHINENUM%.zip to
   W:\WaxTrace-Install\backup\%MACHINENUM%.zip. Logs INFO if no per-asset
   ZIP exists - 09-Setup will then skip the restore step.
3. 09-Setup-WaxAndTrace.ps1 Step 3b: between cal ISO and OpenText
   auto-start steps, look for C:\WaxTrace-Install\backup\<asset>.zip
   and invoke Install-FormtracepakSettings.ps1 -BackupPath ...
   -RestoreData -RestoreConfig -Force. Registry restore is intentionally
   omitted - captured HKLM is overwritten by the vendor MSI install in
   Step 2 anyway, and captured HKEY_USERS would land at the source
   bay's SID (which doesn't exist on the freshly imaged bay).

bay-config.csv refresh: 17 captured bays with full version/model/
user_id/hw_sn/hw_id/host. Versions stick to the original bay-config.csv
target values where the live binary drifted to a release we don't have
an ISO for (e.g. WJRP2035 live 5.7.0.82 -> imaging targets 6.0).
WJF00450 flagged MISSING_DATA in user_id + hw_id columns so the
imaging path aborts cleanly until the dongle is read.

Smoke tested on win11 VM with WJF00545's real capture: staged the
expected bay-side layout (C:\WaxTrace-Install\Install-FormtracepakSettings.ps1
+ C:\WaxTrace-Install\backup\WJF00545.zip), invoked the resolve +
call path from a simulated Step 3b - 17 files restored cleanly, 0
errors.
2026-05-24 12:55:37 -04:00
cproudlock
6602afde38 Backup-FormtracepakSettings: timeout-fence reg.exe + recursive walk
WJF00052 / WJF00083 / WJF00084 / WJF00159 produced 0-byte ZIPs on the
2026-05-24 capture pass. Export-FormtracepakInventory was the primary
culprit (Get-Service hang, fixed in d359563), but Backup has the same
root failure mode for the same bays: reg.exe export via Start-Process
-Wait and the recursive Get-ChildItem walk over HKLM:\SOFTWARE\
WOW6432Node\Mitutoyo (95k+ values) both lack timeouts, so a degraded
SCM / antivirus interception / WMI repository on the bay can wedge the
script and the operator kills the .bat - same outcome as the inventory
hang.

Two timeout fences:
- reg.exe export: switch from Start-Process -PassThru -Wait to
  [System.Diagnostics.Process]::Start + WaitForExit(300_000). If the
  process hasn't exited after 5 minutes, Kill() it and log + count an
  error; the .reg file for that one root is skipped but other roots
  + the CSV fallback + the file/data captures continue. Bonus: the
  ProcessStartInfo path also gives reliable $proc.ExitCode access; the
  Start-Process -PassThru object sometimes returned a stub with
  unpopulated ExitCode, producing a false "reg.exe exit  for ..."
  warning even on successful exports.
- Recursive Get-ChildItem CSV walk: move into a Start-Job + Wait-Job
  -Timeout 600 (10 min). If the walk hangs, Stop-Job, log, increment
  error count, .reg file remains authoritative for that root.

Also fixed a subtle Start-Job return-shape bug introduced in the same
edit: emitting the rows via the pipeline inside the job + Receive-Job
flattens correctly, whereas `return ,$list` wrapped the whole List in a
single-element array, so the outer foreach was treating the list-of-95k
as a single row. Net effect was Registry Values: 4 instead of 95152 in
the manifest. Verified fixed via a full real-install run on the VM:
95152 values captured cleanly in 22 s, 0 errors.

Net behaviour: the failed-bay re-runs (WJF00052/00083/00084/00159)
should now either produce real ZIPs or print a clear warning naming the
specific reg root that hung, instead of leaving an empty ZIP behind.
2026-05-24 11:43:42 -04:00
cproudlock
d359563a4c Export-FormtracepakInventory: drop Get-Service entirely (SCM hang)
WJF00052 / WJF00083 / WJF00084 / WJF00159 hung indefinitely on step [5/5]
during the 2026-05-24 capture pass and the operator killed the .bat,
leaving empty inventory CSVs. The earlier Start-Job + Wait-Job -Timeout 30
guard (commit fce6680) was insufficient: Stop-Job on a Get-Service that's
blocked on a degraded Service Control Manager can itself block in the SCM
call (Sentinel HASP driver service in particular has been observed to
wedge Get-Service for minutes), so the main script never unblocked even
after the 30s timeout fired.

Service state isn't load-bearing for identifying the install on a bay
(version + model + DeviceName come from disk + registry, not the SCM),
so the cleanest fix is to drop the Get-Service block entirely. Get-Process
is fast and stays. Step [5/5] label changed from "Checking running
processes and services" to "Checking running processes".

Smoke tested on win11 VM: full Export against a real v6.213 / AVANT
install completes in ~25 s (was 2.9 s with no install, 25 s now reflects
the legitimate ~95k registry walk that dominates the runtime - not the
service hang).
2026-05-24 11:03:20 -04:00
cproudlock
cb149ed8cd Backup-FormtracepakSettings: empirically-grounded version + model detection, HKEY_USERS sweep, manifest evidence stamp
Installed FormTracePak v6.213 on the win11 VM (picking FORMTRACER Avant
in the dialogs) and probed the resulting registry / disk layout to find
out what evidence a real FormTracePak install actually carries. Two
empirical findings:

1. ACTIVE MODEL lives at
   HKLM:\SOFTWARE\WOW6432Node\Mitutoyo\FORMPAK\Config\device map\DeviceName
   (string value). For the AVANT install the value is "FORMTRACER Avant";
   for the CV/SV/CS controllers the value contains the matching model id.
   The Surfpak\FormMes\MachineInfo\Machine\Machine* subtree lists EVERY
   supported machine and is NOT the active selection - the previous
   heuristic that scanned uninstall-entry DisplayName picked up bogus
   WinUSB driver-package entries from "Mitutoyo Corporation" instead.

2. INSTALLED BINARY VERSION is in Formtracepak.exe VersionInfo:
   FileVersion=6.2.0.51, ProductVersion=6.2.0.0. This does NOT match the
   Mitutoyo MSI release label ("6.213") that bay-config.csv uses. The
   uninstall entry's DisplayVersion is empty. So bay-config.csv stays
   canonical for the per-asset marketing version; exe FileVersion is a
   concrete cross-check.

Backup rewrites:
- Replace the previous one-shot version detection with evidence reading:
  bay-config.csv (asset->version+model), Formtracepak.exe VersionInfo,
  device-map\DeviceName. The over-broad uninstall-reg regex is gone.
- Normalize DeviceName ("FORMTRACER Avant" / "CV-4500" / "CV-3200" /
  "Contracer" / "Surftest") to bay-config notation (AVANT / CV-4500 / ...).
- Emit BayConfigMatch flag - true when bay-config-predicted model agrees
  with the device-map\DeviceName on disk. False = drift, tech rechecks
  before restoring to a new bay.
- manifest.json now stamps: AssetNumber, FormtracepakVersion, Model,
  BayConfigVersion, BayConfigModel, BayConfigSource, InstalledExeVersion,
  InstalledExePath, InstalledDeviceName, InstalledModelNormalized,
  BayConfigMatch.

HKEY_USERS sweep:
- Wax/Trace bays log in as a per-site user (lg782713sd at WJ today,
  ShopFloor post-SFLD-2.0, other accounts at other sites). The previous
  HKCU:\ scan only captured the script's running user. Sweep every
  loaded HKEY_USERS hive whose SID matches S-1-5-21-* (real user SIDs)
  for Software\Mitutoyo / FORMTRACEPAK / FORMPAK / SURFPAK subkeys,
  add them to $RegistryRoots. Username-agnostic - works at any site
  without changes.

reg.exe export now also accepts the Registry::HKEY_USERS\<sid>\... PSPath
form by stripping the "Registry::" prefix when building the reg.exe
argument (previously emitted "Invalid key name" errors on HKEY_USERS roots).

Smoke tested against a real v6.213 / FORMTRACER Avant install on win11
VM: bay-config lookup matches, exe FileVersion read, device-map
normalized to AVANT, all four .reg files (HKLM, HKLM-WOW6432Node, HKCU,
HKEY_USERS\<interactive-sid>) exported clean, 0 errors.

Restore-side SID translation (HKEY_USERS\<src-sid>\... -> target user's
SID or HKCU on the new bay) is a follow-up. HKLM tree carries the
critical device-map\DeviceName, controller config, and machine settings;
the HKEY_USERS hive captures per-user UI prefs only.
2026-05-24 09:58:24 -04:00
cproudlock
821e3179d1 Wax/Trace triad: switch to SHA256 hashes (FIPS-compliant) + separate hash-failure path from copy-failure path
Backup-FormtracepakSettings observed 17 Errors on a real shopfloor PC
(G5PRTW04ESF / WJF00159 capture) - all of the form:
  WARNING: Failed to copy ...App.ini: Exception calling ".ctor" with "0"
  argument(s): "This implementation is not part of the Windows Platform
  FIPS validated cryptographic algorithms."

Cause: Windows FIPS policy is enabled on West Jefferson shopfloor PCs.
The per-file Get-FileHash -Algorithm MD5 call throws a hard .NET exception
that bypasses -ErrorAction SilentlyContinue (the throw is from the MD5
constructor, not the cmdlet's parameter binder). That exception was caught
by the broad try/catch around both Copy-Item + manifest add, producing a
misleading "Failed to copy" message even though Copy-Item already succeeded.
Net effect: files copied fine, but manifest rows were missing for those
files (Install would fall back to its bulk-copy path).

Two fixes:
- Switch the hash algorithm from MD5 to SHA256 in both Backup (manifest
  row capture) and Install (Restore-FileItem hash-skip compare). SHA256
  is Get-FileHash's default and is FIPS-compliant. Old MD5-hashed backups
  remain restorable because Install computes hashes fresh from disk at
  restore time and does not read the Hash column from file_manifest.csv.
- Split the broad try/catch in Backup's Copy-ToStaging into two
  try/catches: the first wraps only Copy-Item (real copy failure -> Errors
  counter + skip the file), the second wraps only Get-FileHash (hash
  failure -> log warning, manifest row gets a null Hash and is still
  recorded). A hash failure no longer pretends the copy failed.
- Install's hash compare is wrapped in try/catch too so a hash exception
  falls through to overwrite-mode rather than crashing the restore.

Smoke tested on win11 VM: SHA256 round-trip works (64-char hashes in
file_manifest.csv), Backup reports 0 Errors, Install hash-skip path
correctly skips Identical files on second-run idempotency check.
2026-05-24 09:23:53 -04:00
cproudlock
fce6680c6f 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.
2026-05-24 08:51:30 -04:00
cproudlock
ed12988591 Wax/Trace triad: harden against empty $PSScriptRoot
Tech ran Export-FormtracepakInventory.ps1 from S:\DT\shopfloor\scripts\
waxandtrace\ and the picker fired correctly but Export-Csv failed with
'Cannot bind argument to parameter Path because it is an empty string'.
Root cause: $OutputPath defaulted to $PSScriptRoot and $PSScriptRoot came
through empty in that invocation path (suspected ISE / IEX-style host or
remote wrapper). On a [string] param, $null/empty default coerces to ''
and Join-Path then errors.

Fix in all three triad scripts: resolve a local $scriptDir via a fallback
chain ($PSScriptRoot -> $PSCommandPath -> Get-Location), and use that
instead of $PSScriptRoot for sibling lookups (Select-WaxtraceAsset.ps1,
bay-config.csv).

Export additionally:
- Drops the $OutputPath = $PSScriptRoot param default in favor of the
  same fallback chain.
- Tests / creates $OutputPath BEFORE the 90k-item registry scan so a bad
  output dir surfaces immediately instead of after a long scan.

Smoke tested on win11 VM: explicit -OutputPath '' now resolves to a
writable directory and the CSV writes successfully.
2026-05-24 08:00:00 -04:00
cproudlock
b8bb00e2fe Wax/Trace triad: arrow-key bay picker + S: backup path
Two operator-UX improvements for the Backup / Export / Install triad.

1. Backup target moves from \\tsgwp00525\...\formtracepac to S:\2 WJ Scans
   Record Retention\backup\waxtrace\<asset>\. S: is mapped at shopfloor
   imaging time and stays mapped post-categorization, so the same default
   path works whether the operator runs the backup on an old bay (manual
   pre-image capture) or a freshly imaged one. The destination directory
   is created if missing.

2. New Select-WaxtraceAsset.ps1 - arrow-key bay picker patterned after
   the WinPE select-waxtrace-asset.ps1. Reads bay-config.csv (sibling
   file), shows asset_tag + ftpak_version + model + user_id per row, and
   returns the selected asset_tag via stdout. Falls back to a manual
   entry prompt if the CSV is missing or the operator picks "Other".

   Backup / Export / Install now invoke the picker when interactive AND
   bay-config.csv is alongside the script. Non-interactive paths
   (qga / SYSTEM / scheduled task) keep silently defaulting to
   COMPUTERNAME so unattended runs are unchanged.

   Export gained an -AssetNumber parameter and stamps it into the output
   CSV filename so multiple inventories from the same host stay
   distinguishable when the operator is auditing several bays in a row.

bay-config.csv is copied into the scripts\ dir so the picker has a
source of truth that ships next to the scripts (and into pxe-images
for tech distribution).

Smoke tested on win11 VM: all four PS1 parse-clean, non-interactive
backup path still produces a valid ZIP (silent COMPUTERNAME default),
picker handles missing-CSV gracefully (manual-entry fallback). The
arrow-key UX itself is operator-verifiable only on a real terminal.
2026-05-24 07:41:25 -04:00
cproudlock
a104cfdebb Wax/Trace triad: fix registry corruption + cover v6.213 vendor install path
Three fixes in Backup / Export / Install, validated end-to-end on the win11 VM
against a seeded HKCU\SOFTWARE\Mitutoyo\Formtracepak key carrying all five
registry value types (String, DWord, ExpandString, MultiString, Binary).

1. Registry corruption on REG_BINARY / REG_MULTI_SZ restore
   Backup wrote those values to registry_values.csv via [string]$val, which
   lossily coerces a byte[] to "System.Byte[]" and a string[] to a
   space-joined scalar. Install's CSV restore loop runs AFTER the .reg file
   import (which is lossless), so the CSV pass overwrites the good values
   with corrupted strings. Two-part fix:
   - Backup: skip Binary / MultiString / None / Unknown when writing the CSV.
     Only String, ExpandString, DWord, QWord roundtrip cleanly through
     New-ItemProperty -PropertyType, so capture only those. The .reg file
     remains authoritative for the rest.
   - Install: defensive filter on the CSV restore loop that skips any row
     whose Type is not in {String, ExpandString, DWord, QWord}. This catches
     legacy CSVs already on the share that were taken before this fix.

2. v6.213 vendor install path not scanned / not restored to
   The per-bay FormTracePak install (commit 54dddaa) lands under
   C:\Program Files (x86)\MitutoyoApp\Formtracepak, but the search-path
   lists in Backup + Export only covered C:\...\Mitutoyo (no MitutoyoApp).
   Result: a backup taken on a freshly imaged v6.213 bay produced Config
   Files = 0 because the script never looked at the actual install dir.
   Added MitutoyoApp (x86 + native ProgramFiles) ahead of the legacy
   paths in all three scripts.

3. Install $DefaultAppTargets fallback didn't include MitutoyoApp either,
   so a restore from an OLDER bay (source path C:\Mitutoyo\...) onto a
   freshly imaged v6.213 bay would fall back to ProgramFiles\Mitutoyo
   (does not exist), miss the MitutoyoApp\Formtracepak tree, and write
   the restored files into the first existing legacy path. Added the
   MitutoyoApp entries at the top of the ordered fallback table.

Smoke tested on win11 VM: backup of all 5 reg types, then corrupt every
value, then Install -RestoreAll restores all 5 byte-exact (incl. REG_BINARY
DE-AD-BE-EF-CA-FE-BA-BE-01-02-03-04 and REG_MULTI_SZ alpha.smp/beta.smp/
gamma.smp). Verified legacy poison-CSV path triggers the defensive filter
and the .reg-imported values survive untouched. -DryRun confirmed
non-mutating. Idempotency confirmed via hash-skip.
2026-05-24 07:29:27 -04:00
cproudlock
54dddaa760 Wax/Trace: per-bay FormTracePak version via bay-config.csv
Bays span 7 FormTracePak versions (5.510 - 6.213) and 3 sub-versions
(AVANT / CV-4500 / CV-3200), each with a unique licensing USER ID. Previously
all bays got v6.213 with no model/USER hint to the tech.

- bay-config.csv: 15 rows mapping asset_tag to ftpak_version + model + user_id.
- resolve-bay-config.ps1: WinPE-runnable resolver. Looks up the asset and
  writes version.txt / model.txt / userid.txt / bay-info.txt under
  W:\Enrollment\waxtrace\.
- startnet.cmd: xcopy WaxTrace bundle minus formtracepak\, invoke the
  resolver with %MACHINENUM%, then cherry-pick only the matching
  FORMTRACEPAK-V<ver>.iso (~2 GB local vs ~12 GB if all were staged).
- 09-Setup-WaxAndTrace.ps1: read the per-bay files, mount the right ISO,
  drop <asset>-FTPak-install-info.txt on SupportUser's desktop, and print
  a banner with MODEL + USER ID so the tech has them top-of-mind when
  Setup.exe dialogs come up.
- sync-waxtrace.sh: loop over all FORMTRACEPAK-V*.iso instead of hard-coding
  v6.213; also push bay-config.csv + resolve-bay-config.ps1 to the share.
2026-05-24 07:04:15 -04:00
cproudlock
de3018512a 09-Setup-WaxAndTrace: fix broken-filename detection (Get-ChildItem -Filter)
The direct-copy bypass added earlier was never firing - Get-ChildItem -Filter
uses Win32 filename filtering and does NOT honor PowerShell wildcards or
character classes. The previous detection filter '*[0-9] _*.txt' matched
literal bracket-zero-through-nine text, which never appears in any
filename. $hasBrokenFilenames was therefore always False, and every
218-378-13 series cal apply fell through to the vendor setup.exe which
crashes with System.ArgumentException (exit -532462766).

Confirmed via debug-waxtrace-cal.ps1 log on WJF00159: section 6 reports
the on-disk script has the direct-copy fix, section 7 shows the actual
runtime log line 'running cal Setup.exe' followed by exit -532462766.
The "fix" was never executing because the gate was broken.

Replace -Filter with Get-ChildItem -File + Where-Object regex match on
' _\d+\.txt$' which catches the actual buggy filename pattern (space-
underscore-digits-.txt at end of name) regardless of probe series.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 14:09:10 -04:00
cproudlock
44554b95b0 gea-shopfloor-waxtrace: stage Mitutoyo Backup/Install/Export triad
User received three PowerShell scripts from a Mitutoyo source for
backing up + restoring FormTracePak settings per asset:

  Export-FormtracepakInventory.ps1 - audit: enumerate files + reg keys
  Backup-FormtracepakSettings.ps1  - capture: config + data + reg into
                                     timestamped ZIP, manifest-driven
  Install-FormtracepakSettings.ps1 - restore: replay ZIP to a new bay,
                                     hash-skip identicals, backup
                                     existing as .pre_restore_bak

Cleanup pass over the vendor-shipped versions:
- Strip Unicode box-drawing characters from banners (ASCII-only policy)
- Install: switch to [ordered]@{} for DefaultAppTargets/DefaultDataTargets
  so fallback priority is deterministic
- Install: add -AssetNumber gate that defaults to per-asset SFLD path
  \\tsgwp00525...\Shopfloor\backup\formtracepac\<AssetNumber>
- Install: timestamp the .pre_restore_bak filename so re-runs don't
  clobber the previous backup
- Install: handle BackupPath being a directory containing
  formtracepak_backup_*.zip files (picks newest)
- .bat launchers for each PS1 (bypass execution policy, double-click)

Not yet wired into 09-Setup-WaxAndTrace.ps1; pending reference-backup
capture from a known-good bay before promoting to imaging path. Today
the V6.213 vendor MSI install + per-asset cal ISO still handle the
imaging-time setup directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:39:24 -04:00
cproudlock
5891a1966f 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>
2026-05-21 19:38:19 -04:00
cproudlock
e1ea6b7c62 Wax/Trace: switch baseline to FormTracePak v6.213 vendor install
Replace the V6.0 captured-binary replay (pf-x86-MitutoyoApp.zip +
c-MitutoyoApp.zip + hklm-wow-mitutoyo.reg.gz) with a real vendor install
from FORMTRACEPAK-V6.213.iso mounted via Mount-DiskImage.

09-Setup-WaxAndTrace.ps1:
- Step 2 rewritten: Mount-DiskImage on
  C:\WaxTrace-Install\formtracepak\FORMTRACEPAK-V6.213.iso, run the VB6
  Setup.exe wrapper from the assigned drive letter (DRIVE_CDROM check
  satisfied by virtual mount, no real CD needed), then Dismount.
- Header rewritten: drop captured/ description, note legacy fallback
  remains in the repo (captured-binary/ unchanged) for manual recovery
  if the v6.213 vendor install fails on a bay.

sync-waxtrace.sh:
- Push formtracepak/FORMTRACEPAK-V6.213.iso (2.0 GB) into the bundle
  instead of captured/ payload. Override path via $FTPAK_ISO env var if
  needed (e.g. testing a v6.213 patch ISO).
- Sanity check no longer demands pf-x86-MitutoyoApp.zip; only requires
  prereqs/ + the manifest + dispatcher PS1.

playbook/utilities/convert-cal-iso.sh:
- New helper. Rebuilds a Linux-dd of a multi-session UDF cal disc into
  a clean ISO9660+UDF hybrid that Windows Mount-DiskImage reads. mkisofs
  reads the file via loop-udf, repacks single-session with the asset tag
  as volume label. Run when `file CAL-*.iso` reports "data" (multi-session
  UDF dd produced a Linux-readable but Windows-unreadable container).
  Single-session 218-458A discs from dd are already ISO9660 and don't
  need this.

Verified on win11 VM via qga: V6.213 ISO mounts, Setup.exe locatable.
14 cal ISOs all converted to ISO9660 (md5s refreshed in INDEX.csv),
re-synced to /srv/samba/enrollment/installers-post/waxtrace/calibrations/.
PXE share bundle now 2.0 GB total (V6.213 ISO + 14 cal ISOs + prereqs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 15:44:42 -04:00
cproudlock
37357eee43 Shopfloor images: add Wax/Trace + Keyence per-model variants
Wax/Trace (gea-shopfloor-waxtrace):
- captured/ holds master FormTracePak v6.0 state (Program Files reg dump
  gzipped, ARP entries) taken from a win11 VM where the CD-ROM-bound VB6
  wrapper was driven to completion. xcopy + reg-import replays the install
  on real bays without running the wrapper itself.
- 09-Setup-WaxAndTrace.ps1 rewrites the stub: installs prereqs via manifest
  (VC++ 2008/2017 x86+x64, Sentinel HASP), expands the captured zips into
  C:\Program Files (x86)\MitutoyoApp + C:\MitutoyoApp, imports the reg
  hive, then mounts the bay's per-machine cal ISO (matched by asset tag
  in machine-number.txt) and runs its Setup.exe.
- waxtrace-manifest.json lists the 5 prereqs with InstallShield-style
  silent flags verified on the win11 VM.
- sync-waxtrace.sh ships captured-binary/ + prereqs + cal ISOs from
  /home/camp/pxe-images/iso/mitutoyo-cal/ to
  /srv/samba/enrollment/installers-post/waxtrace/ on the PXE box.
- select-waxtrace-asset.ps1 arrow-key bay picker for WinPE (parses
  INDEX.csv from the cal share, offers "Other (new bay)" fallback).
- startnet.cmd: prompt_waxtrace_asset prompt, skip_waxtrace_stage xcopy
  block (mirrors :skip_cmm_stage), machine-number.txt write covers bay
  asset tag (WJRP*).

Keyence (gea-shopfloor-keyence) - now multi-model:
- vr3000/manifest.json + vr5000/manifest.json + vr6000/manifest.json
  (current single-model VR-6000 moved into vr6000/ subdir). Each ships
  the model's MSI silent-install + DetectionPath via ProductCode.
  Big payloads (Data1.cab, Data11.cab) gitignored, staged via
  sync-keyence.sh from /home/camp/pxe-images/iso/keyence/.
- 09-Setup-Keyence.ps1 dispatches by C:\Enrollment\keyence-model.txt
  (written by startnet.cmd in :keyence_submenu) and points
  InstallerRoot at C:\KeyenceInstall\<model>. DXSETUP probe widened
  to all three Program Files paths (VR-3000 G2, VR-5000, VR-6000).
- startnet.cmd: :keyence_submenu picks vr3000/vr5000/vr6000,
  :skip_keyence_stage xcopy block selectively stages chosen model bundle,
  pc-subtype.txt also written = drops directly into existing GE-Enforce
  PCSubType wiring (looks for gea-shopfloor-keyence-<model>\manifest.json
  on the tsgwp00525 share for ongoing enforcement, no dispatcher change
  needed).
- sync-keyence.sh mirrors sync-waxtrace.sh pattern.

Verified silent MSI install for VR-3000 G2 v2.5.0 and VR-5000 v3.3.1 on
the win11 VM 2026-05-18 with /qn /norestart ALLUSERS=1 REBOOT=ReallySuppress
TRANSFORMS=1033.mst. boot.wim on 172.16.9.1 wimupdate'd with the new
startnet.cmd.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 16:34:20 -04:00
cproudlock
8cd0c147d8 imaging: renumber stages to be time-monotonic (1=WinPE, 7=Intune ID)
Previously the stage indices reflected logical milestones but not the
order they fire in. Run-ShopfloorSetup posted idx=1 (start) and idx=4
(PPKG) - but 09-Setup-Keyence (inside per-type loop) ran BETWEEN them
and posted idx=5/6. The dashboard then "regressed" from 6 back to 4
when PPKG fired, making it look stuck at the per-type-complete card.

New numbering matches actual execution order:

  1 - WinPE: PESetup / WIM apply              (startnet.cmd)
  2 - Run-ShopfloorSetup: starting            (Run-ShopfloorSetup.ps1)
  3 - 09-Setup-<Type>: starting               (per-type)
  4 - 09-Setup-<Type>: complete               (per-type)
  5 - Run-ShopfloorSetup: PPKG enrollment     (Run-ShopfloorSetup.ps1)
  6 - Run-ShopfloorSetup: handoff to Monitor  (Run-ShopfloorSetup.ps1)
  7 - Monitor-IntuneProgress: Intune Device ID captured

services/imaging_status.py rewind threshold reverts to stage_index <= 1
now that WinPE startnet posts idx=1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:34:01 -04:00
cproudlock
6dcf96e40a Phase 3+4 rename reorg: repo dir renames + startnet.cmd menu
Pairs with Phase 1+2 from earlier (alias maps in Install-FromManifest,
GE-Enforce, Get-PCProfile, verify-state). See project-shopfloor-rename-reorg
memory for the plan.

Phase 3 (repo + paths):
- git mv per-PC-type dirs to gea-shopfloor-* names:
    Standard      -> gea-shopfloor-collections
    CMM           -> gea-shopfloor-cmm
    Keyence       -> gea-shopfloor-keyence
    Genspect      -> gea-shopfloor-genspect
    WaxAndTrace   -> gea-shopfloor-waxtrace
    Display       -> gea-shopfloor-display
    Lab           -> gea-shopfloor-common (folded; Timeclock+Lab merge)
- New gea-shopfloor-nocollections/ (clone of collections sans UDC scripts).
- New gea-shopfloor-heattreat/ (placeholder, README only).
- Move Standard/ntlars-backups/ -> _ntlars-backups/ (per-MN, not per-type).
- Run-ShopfloorSetup.ps1: Resolve-PCTypeDir helper walks alias group when
  the on-disk dir for the current pcType is missing. Set-MachineNumber
  helper-copy gated on collections|nocollections|legacy Standard-Machine.
- Update-MachineNumber.ps1: pcProfiles lookups try gea-shopfloor-collections
  first, fall back to legacy Standard-Machine. PowerShell 5.1 compatible
  (no null-coalesce).

Phase 4 (startnet.cmd menu):
- Choice 3 "GEA Shopfloor" now drills into a 9-item sub-menu instead of
  going straight to enrollment. Sub-cats:
    1. Machine with Collections        -> gea-shopfloor-collections
    2. Machine without Collections     -> gea-shopfloor-nocollections
    3. Common (Timeclock, Lab)         -> gea-shopfloor-common
    4. Keyence                         -> gea-shopfloor-keyence
    5. CMM                             -> gea-shopfloor-cmm
    6. Genspect                        -> gea-shopfloor-genspect
    7. Heattreat                       -> gea-shopfloor-heattreat
    8. Wax and Trace                   -> gea-shopfloor-waxtrace
    9. Display                         -> gea-shopfloor-display
- Office menu (existing 6-option) follows for every sub-cat.
- Machine number prompt only for collections + nocollections.
- pc-subtype.txt + display-type.txt no longer written. PCTYPE is a
  single full string (gea-shopfloor-*); subtype-aware code paths fall
  back to empty and resolve via the alias map.
- CMM bootstrap stage gate switched from "%PCTYPE%"=="CMM" to
  "%PCTYPE%"=="gea-shopfloor-cmm".

Test harness:
- B-enforce/run.sh PCSUBTYPE default changed from "Machine" to "" so
  single-arg invocation matches the new single-string scheme. Two-arg
  legacy form ("Standard Machine") still works via aliasing.
- B-enforce/tamper.ps1 alias-aware Test-MatrixEntryMatches mirroring
  verify-state.ps1.

Smoke-tested on win11 VM as SYSTEM via qga: B-enforce harness 5-phase
cycle (stage / baseline / tamper / heal / idempotent) passes 10/10
with PCType=gea-shopfloor-collections AND with legacy "Standard Machine"
two-arg form.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 08:09:16 -04:00