goCMM showed an empty parts list after restore though the bay reached the share.
Decompiled goCMM: PartGroupViewModel matches the registry Selected Part Group
against ApplicationSettings.xml <PartGroup FullName> with a CASE-SENSITIVE compare,
then enumerates that FullName for the parts. The host-canon rewrite fixed only the
hostname, leaving xml '\shared' (lowercase) vs registry '\SHARED' (uppercase) ->
Find null -> SelectedPartGroup null -> empty list. Fix spans the share segment too,
pinning both to \tsgwp00525.wjs.geaerospace.net\SHARED. Verified in PowerShell
(-ceq True). Runs at imaging in Restore-CMM, so all captured backups are fixed on
restore with no re-backup.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The pre-mount `net use Z: /delete /y` in Fetch-StagingPayload and
Verify-And-Heal-Staging emits "The network connection could not be found" when
Z: is not yet mapped (the normal first-attempt case). PowerShell surfaces that
native stderr as a NativeCommandError (System.Management.Automation.Remote-
Exception) at the call site EVEN WITH `2>$null` - it prints a red error during
the FirstLogonCommands run, alarming the tech and able to mask a real fault.
The mount then succeeds, so it was always cosmetic.
Wrap the cleanup in cmd.exe (`cmd /c "net use $drive /delete /y >/dev/null 2>&1"`) so
net.exe's stderr is redirected to nul INSIDE cmd and never reaches PowerShell as
an error record. Verified on the win11 VM: old pattern leaves $Error.Count=4
(RemoteException); new pattern leaves $Error.Count=0. All four call sites fixed
(both scripts' Mount-Share + end-of-run unmount).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The shallow present-check passed a file that merely existed, so a partially
transferred payload (e.g. a truncated PC-DMIS MSI) looked PRESENT and was never
re-pulled - then failed to install because it was incomplete. Replace it with a
per-item robocopy that compares size + timestamp on every file and re-pulls
anything missing OR partial, skipping ones already complete. VerifyOnly uses /L
to report INCOMPLETE without changing anything.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire the staging self-heal into the imaging flow so a bay re-pulls any missing
payload while still on the imaging LAN (172.16.9.1), before wait-for-internet
takes it to the production network.
- FlatUnattendW10-shopfloor.xml: insert Verify-And-Heal-Staging.ps1 as
FirstLogonCommands Order 5 (right after Fetch-StagingPayload Order 4, before
wait-for-internet); renumber the rest 6-10. Run-ShopfloorSetup stays last and
is NOT the heal point - it runs post-network-switch when the imaging LAN is
gone.
- Fetch-StagingPayload.ps1: also pull the small Verify-And-Heal-Staging.ps1 to
C:\Enrollment so the Order 5 step has it on disk.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- lib Install-FromManifest 2.5->2.6: add _CmmVersion per-entry filter (reads
C:\Enrollment\cmm\version.txt). Lifted the version gate out of 09-Setup-CMM
into the shared lib so imaging and GE-Enforce apply it identically and cannot
drift (root cause of PC-DMIS 2016 installing on every CMM).
- Install-goCMMSettings: canonicalize the part-group share host to the FQDN in
both the registry and ApplicationSettings.xml. Handles bare \\tsgwp00525\ and
the legacy rd.ds.ge.com domain; idempotent. VM-tested.
- Report-AssetToShopDB: resolve the machine number eDNC registry first, then fall
back to C:\Enrollment\machine-number.txt (matches the lib resolution order) so
a freshly imaged PC still reports its number for the PC-machine relationship.
- Add Update-CMMEnforcer.ps1/.bat: update one CMM's local lib to the gated
version and self-heal its PC-DMIS version.
- Add Debug-ShopDBReporting.ps1/.bat: one-shot reporter triage (preconditions,
client log, live test POST, verdict).
- Add Verify-And-Heal-Staging.ps1/.bat: post-boot check that every imaging
payload arrived and re-pull anything missing from the share, including the CMM
bundle and the selected bay's backup (the payload that times out in WinPE).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restore-CMM.ps1 (new) restores a CMM's PC-DMIS + goCMM settings at imaging from
its staged backup. Self-gating: reads C:\Enrollment\cmm\{cmmid,version,doda,
partgroup}.txt, skips DODA bays and bays with no staged backup, and restores
ONLY the config-version PC-DMIS zip via the existing Install-*Settings scripts.
Same-bay restore (cmmid match) so the backed-up controller CommPort is this
bay's own value - no cross-bay clobber.
Version selection matches the VERSION FIELD of the zip name, anchored on the
trailing timestamp, so version=2026 does not false-match a 2019/2016 zip whose
backup timestamp (20260612...) merely contains "2026".
09-Setup-CMM.ps1: new Step 2.8 calls Restore-CMM after app install + first-run
init (so a restored config is not clobbered by PC-DMIS defaults) and before the
C:\CMM-Install cleanup (the backup set lives under <stagingRoot>\backups\<cmmid>).
Best-effort: Restore-CMM always exits 0, imaging never fails on a restore.
startnet.cmd: stage ONLY the picked bay's backup into C:\CMM-Install\backups\
%CMMID% (the bulk robocopy now /XD-excludes the backups tree, which holds every
bay's backup - some 240 MB each - to avoid copying GBs to every imaged CMM).
Also bump the PPKG to v4.16 (the live boot.wim was already v4.16; the repo had
drifted to v4.14).
sync-cmm-backups.sh: source the backups from pxe-images/cmm/backups (where
Backup-CMM writes via the pulled-down copies), not the old cmm-bk path.
Smoke tested on the win11 VM against CMM3's real backup: version=2019 restored
the 2019 R2 zip (not 2016.0), imported HKLM+HKCU reg, converted the part-group
S:\ path to the tsgwp00525 UNC, created C:\geaofi, exit 0; version=2026 correctly
found no matching zip (anchor works).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Default output is now S:\2 WJ Scans Record Retention\backup\cmm\<CmmId>\ instead
of C:\Logs. If S: is not mapped/reachable it falls back to C:\Logs\CMM\cmm-backup
so the backup still runs. When -CmmId is not passed the script prompts for it
(loops until non-empty) since it names the per-bay folder.
Smoke tested on the win11 VM: S: fallback path + the Read-Host prompt (fed via
redirected stdin) both produce the correctly-named per-CMM folder.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Our patched standalone PC-DMIS MSI never installs the Amyuni Document
Converter 500 (system printer "PC-DMIS 50 Converter"). INSTALLPDFCONVERTER
is a Burn-bundle property the main MSI never reads (0 of 153 custom actions
reference it; not in the Property table), and the patched-MSI strategy
bypasses the bundle that would have chained the Amyuni install. The MSI only
lays the installer on disk at <installdir>\PDFDriverInstallFiles\
BatFileInstallPDF50.zip and nothing runs it.
Install-PCDMISPDFConverter.ps1 runs it: scans Program Files\Hexagon (and
Wai) for the laid-down zip, extracts it, parses the InstallPDF50.exe
invocation from the shipped bat (printer name + Wilcox licensee + license
code, read not hardcoded), and runs the exe directly from the extract dir
so sibling DLLs resolve. The shipped bat ends in `pause` (hangs under /qn)
so we never run it. InstallPDF50.exe creates the printer then hangs (same
trait as the bundle), so we poll for the printer and kill the stuck exe
once it appears. Idempotent: printer already present -> exit 0.
Wired as a PS1 manifest entry placed after the PC-DMIS MSIs (files must
exist on disk first), no _CmmVersion (one shared printer covers every
version), MarkerFile detection for one-shot at imaging.
Smoke tested on the win11 VM as SYSTEM: fresh install 7.2s (printer +
driver created), idempotent re-run 0.6s, both exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
sync-cmm-backups.sh pushes per-CMM backup sets (goCMM + PC-DMIS zips produced
by Backup-CMM) from pxe-images/cmm-bk/<cmm_id>/ to the PXE share at
installers-post/cmm/backups/<cmm_id>/, atomic-swap with a timestamped prior
copy. Distinct from sync-cmm.sh (which stages the CMM installer bundle).
resolve-cmm-bay-config.ps1 now also writes cmmid.txt alongside version/doda/
partgroup, so 09-Setup-CMM can locate this bay's staged backup for
restore-by-machine-number.
The 09-Setup-CMM restore block + startnet staging line are intentionally NOT
added yet - the restore needs manual end-to-end validation on a real CMM
before auto-running at imaging (per the live-bay restore issues we hit).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the PC-DMIS settings/probe backup-restore set alongside the existing
goCMM scripts, plus a single combined CMM backup and the diagnostics built
while debugging the live bays:
- Backup-PCDMISSettings / Install-PCDMISSettings: capture+restore PC-DMIS
registry + data/probe/cal files per installed version (2016/2019/2026).
Hardened from real-bay failures: detect install dir via Program Files
fallback; capture compens.dat (not just comp.dat) + interfac.dll; identify
the controller by hash-matching interfac.dll to its source DLL AND reading
the PE OriginalFilename (covers rename-without-copy); EXCLUDE the whole
Homepage state (Recent/Favorites/DetailsView) which null-refs PC-DMIS on
launch via stale routine paths; restore routes HKCU into the target user's
hive (-TargetUser ShopFloor), fails loud on a non-backup path, and applies
the legacy->new FQDN rewrite across reg + data files incl .bas.
- Backup-CMM: one wrapper running goCMM + PC-DMIS (all versions) into one
per-CMM folder + index, for staging on PXE and restore-by-machine-number.
- Clear-PCDMISRecent: fixes the Homepage recent-list NullReferenceException
crash on an already-broken bay.
- pcdmis-probe-debug / Export-PCDMISCrashEvents: diagnostics for the
custom-probe-not-showing and crash investigations.
- Modify-PCDMISRights / Grant-FullControl: grant the operator the registry +
filesystem access PC-DMIS needs under lockdown.
- Install-goCMMSettings: add .bas to the FQDN-rewrite include list.
Not yet wired into 09-Setup-CMM auto-restore - staging + the gated restore
block come next.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
goCMM settings live in two places: 3 pointer values at
HKLM\SOFTWARE\WOW6432Node\General Electric\goCMM, and the real content of all
7 Settings tabs (PC-DMIS, Quindos, Modus, Machine Definition, User Input,
Notifications, Part Groups) in C:\geaofi\ApplicationSettings.xml. Capture-replay
pair, mirroring the Wax/Trace Backup/Install scripts:
- Backup-goCMMSettings.ps1/.bat: on a live legacy bay (admin), zips the registry
key + the C:\geaofi tree (minus transient LocalProgramCopies/logs) to
gocmm_backup_<PC>_<ts>.zip.
- Install-goCMMSettings.ps1/.bat: restore at imaging (admin). Imports the key +
lays down C:\geaofi, then grants BUILTIN\Users WriteKey on the reg key and
Modify on C:\geaofi - goCMM's RegistrySettings.GetRegistryString opens the key
with writable:true even to READ, so a locked-down operator throws a
SecurityException without the grant (the post-lockdown 'registry access not
allowed' error). Applies a built-in legacy->new FQDN rewrite
(rd.ds.ge.com -> wjs.geaerospace.net) automatically across the registry values
and ApplicationSettings.xml (incl PartGroup FullName); -NoDefaultRewrite skips
it, /replace adds an extra pair, -SelectedPartGroup overrides per bay.
- gocmm-debug.ps1/.bat: run as the operator to reproduce the SecurityException
and dump the goCMM key ACL (confirms whether lockdown stripped the grant).
All round-trip + FQDN-rewrite verified on the win11 VM. NOTE: covers goCMM only;
PC-DMIS probe calibrations / custom tip angles / machine comp are owned by
PC-DMIS (Hexagon) and not captured here. Not yet wired into 09-Setup-CMM
auto-discovery.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Standardize the calibration source. Step 3b already restores a per-asset
backup ZIP (HKLM + data + config, incl. the probe cal tables) for any bay
that has one - which is now every migrated bay. When that ZIP is staged,
skip the redundant and fragile cal-ISO mount/vendor-Setup step so all
bays follow one flow (app ISO + backup restore), matching the bays that
never had a cal ISO. A future bay with a cal ISO but no backup still
falls through to the ISO path unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fill in user_id 0992830128 (was a MISSING_DATA placeholder pending a
dongle read). Keep ftpak_version 6.213: the bay runs FormTracePak
6.2.0.45 but no V6.204 app ISO exists, so it installs the V6.213 app and
restores the 6.2.0.45 config/cal from its per-asset backup ZIP - the same
pattern as WJF00461 (6.213 ISO / 6.2.0.51 backup). Cal .txt tables are
version-independent so they apply onto the 6.213 binaries. hw_id stays
MISSING_DATA (metadata, not consumed by the resolver). Sync the scripts/
copy so the resolver and the backup tools see identical data.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace per-type eDNC_6-4-5.msi with eDNC-6.4.7.msi (ProductVersion
6.4.7.0) in collections, nocollections, heattreat, and partmarker.
01-eDNC.ps1 already prefers the single shared installer at
C:\PreInstall\installers\dnc (6.4.7); aligning the per-type fallback
means an empty shared dir can no longer install a stale 6.4.5. All DNC
types now resolve to 6.4.7 on either path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace HeatTreat_6.2.1.msi with HeatTreat_6-4-9.msi (ProductVersion
6.4.9.0, ProductCode {9E603EFE-888A-4E3F-8CF5-7F03B7029919}). The install
script globs HeatTreat*.msi so no logic change; the MSI's NOT
NEWERVERSIONDETECTED LaunchCondition makes 6.2.1 -> 6.4.9 a clean
in-place upgrade. Update version references in 02-Setup-HeatTreat.ps1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
01-eDNC.ps1 (all 4 DNC types) now installs eDNC from the shared pre-install copy
staged by startnet.cmd to C:\PreInstall\installers\dnc - one source of truth
(currently 6.4.7) instead of a per-type bundled msi. Falls back to the per-type
eDNC\ folder when the shared copy is absent (older images). eMxInfo.txt, the
x86->64 mirror, and Site/MachineNo registry steps are unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Homepage/start-menu + Edge URLs: http://tsgwp00524.logon.ds.ge.com/ ->
https://tsgwp00525.wjs.geaerospace.net (8 refs across site-config + 08-EdgeDefaultBrowser).
- Every shopfloor working type now carries the same common base: Edge + WJ
Shopfloor + Defect_Tracker pins/desktop, WJ Shopfloor + Plant Apps startup,
3 web tabs. Timeclock/Genspect/Keyence/CMM upgraded to match.
- Per-type specialized apps: CMM (PC-DMIS 2016/2019 R2, CLM Admin, goCMM),
WaxAndTrace (Formtracepak), partmarker (Mark + Backup420 only - dropped
Telesis Backup400/470), heattreat (HeatTreat).
- eDNC/UDC/NTLARS listed only on bays that can run them; 06-OrganizeDesktop +
07-TaskbarLayout gate every exe entry on Test-Path, so uninstalled apps are
silently skipped (the "eDNC if it exists / UDC if it exists" behavior).
- Lab + Display-* left as kiosk/lab, not given the shopfloor base.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OpenText HostExplorer was skipped on Part Marker PCs because its PCTypes
filter in preinstall.json omitted PartMarker, so Setup-OpenText.ps1 never
ran - no MSI, no per-user profile/keymap/menu/macro fan-out, no .eb macros
into ProgramData\Hummingbird\Connectivity\15.00\Shared, and no public
desktop shortcuts.
- preinstall.json: add PartMarker + gea-shopfloor-partmarker to OpenText PCTypes
- 00-PreInstall-MachineApps.ps1: add PartMarker alias group to the preinstall
matcher (parity with Install-FromManifest.ps1, which already had it)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PS1 entries were crashing with a cryptic "Cannot bind LiteralPath because it is
null" when the resolved script path came back null - the per-entry try/catch
caught it (so the scope survived) but the cause was opaque. Now the PS1 branch
accepts either Script or Installer, null-guards before Join-Path/Test-Path, and
logs the resolved relative path, so a bad/empty entry is skipped with a clear
"has no Script/Installer value" line instead of a null-bind throw.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Install-FromManifest.ps1:
- Get-CurrentMachineNumber reads the eDNC/DNC registry FIRST (reassignment-
authoritative), falling back to C:\Enrollment\machine-number.txt. The txt is
written once at imaging and is NOT updated on reassignment, so txt-first
gated reassigned bays on a stale number.
- Per-entry try/catch in the app loop: a single entry that throws no longer
aborts the whole scope (skipping every later entry + the status write). It is
logged, counted failed, and the loop continues. This was silently killing the
collections scope at the MTConnect Makino entry, which also stopped the
ShopDB asset reporter (a later entry) from ever running.
Deploy-ShopfloorStartLayout.ps1 (new): local-DSC port of the Intune
desktop-weblinks + Start-menu pins (copies .url/.lnk to Public Desktop +
All-Users Start Menu, writes the ConfigureStartPins JSON policy, resets
start2.bin + restarts the shell). Verified on Win11: pins render after logon.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds Report-AssetToShopDB.ps1 (Type=PS1, DetectionMethod=Always manifest entry)
for collections PCs. Reads hostname, BIOS serial, eDNC MachineNo and the corp
NIC IPv4 (filtered to WJ corp ranges, controller NIC dropped) and POSTs
action=updateCompleteAsset to ShopDB api.asp, which upserts the machine, stores
the IP, and links the PC to its machine-number equipment. manifest-entry-report-asset.json
is the snippet to merge into the SFLD share collections manifest (+ stage the
script under apps/). Note: relies on the ShopDB api.asp LogToFile Err-leak fix
(separate shopdb repo commit) to create the relationship reliably.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PartMarker was missing from the PCType alias map, so gea-shopfloor-partmarker
matched no alias set and common manifest entries gated by PCTypes (notably
Oracle Client 11.2) were pc-filtered out - Part Marker PCs never installed
Oracle. Adds @('PartMarker','gea-shopfloor-partmarker') to the alias groups.
The companion fix (adding partmarker+heattreat to Oracle's PCTypes list) lives
in the SFLD share common/manifest.json. Verified on the win11 VM: with PCType
gea-shopfloor-partmarker the Oracle entry is now evaluated (0 pc-filtered).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
WinPE maps Y: early then idles for minutes during the WIM apply; samba
deadtime drops the idle session, so the WinPE staging copies failed (bay
left with only site-config.json). Add Fetch-StagingPayload.ps1, run from the
unattend FirstLogonCommands at first logon on a FRESH share mount (full
Windows, no prior idle), to pull the shopfloor-setup tree + preinstall
bundle. Detailed per-item log (exit code, counts, timing, mount retries) at
C:\Logs\Fetch\ - the old WinPE staging was opaque.
- Fetch runs as Order 4, BEFORE wait-for-internet.ps1 (Order 5) which switches
the bay to the production network and off the imaging LAN. So Fetch still
reaches \172.16.9.1\enrollment.
- WinPE bulk staging kept as best-effort fail-fast fallback (Phase 1); the
post-boot Fetch is now the authoritative path. Remove the WinPE bulk once
validated. Heavy per-type payloads (CMM/Keyence/WaxTrace) stay in WinPE for
now - Phase 2.
- startnet stages Fetch-StagingPayload.ps1 + writes fetch-source.txt
(UNC/user/pass) for the post-boot mount.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Neither new PC type had a pcProfile, so they fell back to the top-level
defaults, which deliberately exclude eDNC. Result: no DNC desktop shortcut
or taskbar pin on either type. Add profiles mirroring gea-shopfloor-
nocollections (eDNC + NTLARS baseline) plus the type-specific apps:
- gea-shopfloor-partmarker: Mark (C:\Program Files (x86)\Mark\bin\Mark.exe)
+ Telesis Backup400/420/470 (C:\Program Files (x86)\Telesis\Backup4xx\).
- gea-shopfloor-heattreat: HeatTreat
(C:\Program Files (x86)\HeatTreat\bin\HeatTreat.exe).
Deployed to the live enrollment share (config/ + shopfloor-setup/).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 09-Setup-CMM.ps1: Step 2.5 ACL list targeted C:\Program Files\DODA (a path
that never exists), so the BUILTIN\Users write grant on DODA was silently
skipped. Corrected to C:\Apps\DODA, where Install-DODA.ps1 actually extracts.
- Install-DODA.ps1: create C:\Apps\DODA\PreProcess after extract. The DODA
zip unpacks flat without it; MergeFiles.exe expects it and crashed with
DirectoryNotFoundException (MergeFiles.GetDoDAFolder) when absent.
- docs/cyberark-cmm-doda-policy.md: EPM admin reference for elevating the CMM
report toolchain. CyberArk EPM elevation is per-process and not inherited, so
the external tools PC-DMIS spawns (MergeFiles/PCDToIGES/RotateProbeVector/
DovetailAnalysis) run un-elevated and fail. Doc gives the Application Group
(by SHA-256), the Elevate policy, scope, verify steps, and the
CREATE_PDF_FROM_RTF.BAS rework that drops Word/Reader from the elevation set.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
A capture from a working CMM4 bay showed the goCMM registry holds two
distinct values under HKLM\SOFTWARE\WOW6432Node\General Electric\goCMM:
Shared Data Directory = C:\geaofi\ (constant on every bay)
Selected Part Group = \\tsgwp00525...\SHARED\... (the per-bay UNC path)
The prior commit (f6d970c) put the per-bay path into "Shared Data Directory",
which is wrong. Correct that:
- bay-config column shared_data_dir -> part_group
- resolve-cmm-bay-config emits partgroup.txt (was shareddatadir.txt)
- 09-Setup-CMM seeds "Shared Data Directory" to the constant C:\geaofi\ and
"Selected Part Group" to the per-bay path, converting the friendly S:\...
form to the \\tsgwp00525.wjs.geaerospace.net\SHARED UNC at apply time.
Users write grant on the key is unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
HeatTreat bays pick a machine number (6601-6604) at imaging; 02-Setup-
HeatTreat now imports the matching reg\<machine-number>.reg after the MSI,
rewritten to WOW6432Node (DNC is 32-bit; reg import does not honor /reg:32),
mirroring the Part Marker WJPRT.reg flow.
- startnet.cmd: route gea-shopfloor-heattreat to the machine-number prompt
(was defaulting to skip), so machine-number.txt is written for the picker.
- The 6601-6604 .reg files are gitignored (they carry a DNC FtpPasswd
credential) and deploy via the enrollment share from the working tree.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
goCMM (.NET x86) stores its program-source path in HKLM\SOFTWARE\
WOW6432Node\General Electric\goCMM value 'Shared Data Directory'. Being
HKLM, a non-admin shopfloor user cannot set it via goCMM's UI (nor save a
Selected Part Group switch). 09-Setup-CMM Step 2.7 now seeds the per-bay
path (admin context at imaging) and grants BUILTIN\Users write on the key,
mirroring the existing Step 2.5 install-dir ACL grant.
- cmm-bay-config.csv: add shared_data_dir column (per-bay paths, CMM1-12).
- resolve-cmm-bay-config.ps1: write C:\Enrollment\cmm\shareddatadir.txt
(space-safe; e.g. CMM8 'Venture CMM8').
- 09-Setup-CMM.ps1: Step 2.7 reg seed + Users ACL on the goCMM key.
Not yet deployed to the live server (held).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New gea-shopfloor-partmarker type (startnet menu option 10) and fill the
gea-shopfloor-heattreat stub. Both follow the collections eDNC pattern:
01-eDNC.ps1 installs DNC, then a 02-Setup script installs the vendor MSI.
Part Marker (02-Setup-PartMarker.ps1):
- msiexec Mark-6.2.1.msi /qn /norestart LAUNCHNTLARS=false (the LaunchNtlars
custom action otherwise fires under /qn and launches NTLARS mid-install,
same as eDNC).
- After install: import WJPRT.reg rewritten to WOW6432Node (reg import does
not honor /reg:32; DNC is 32-bit and reads the redirected hive), then copy
the Mark overlay + eMxInfo.txt into C:\Program Files (x86)\Mark.
HeatTreat (02-Setup-HeatTreat.ps1):
- msiexec HeatTreat_6.2.1.msi /qn /norestart LAUNCHNTLARS=false. Existing
09-Setup-Heattreat.ps1 (OpenText) still runs after. Optional .reg/file
copy left as a marked TODO pending confirmation.
Both MSIs decompiled: WiX/GE Aviation, no forced reboot, only LaunchCondition
is NOT NEWERVERSIONDETECTED. utilpassword.txt is gitignored (secret, deployed
via the enrollment share from the working tree).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
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>
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>
Add bay picker (same arrow-key pattern as waxtrace) that maps CMM1-12
to a PC-DMIS version (2016/2019/2026) and DODA flag via cmm-bay-config.csv.
startnet.cmd: replace Standard/DODA submenu with bay picker. Writes
CMMID (e.g. CMM4) to machine-number.txt so the existing
TargetMachineNumbers filter on the SFLD share manifest gates per-bay
entries with no lib changes.
09-Setup-CMM: reads resolved version.txt and filters cmm-manifest.json
by _CmmVersion tag at imaging time so only the matched PC-DMIS version
installs.
cmm-manifest.json: add PC-DMIS 2026.1 entry (patched MSI, product code
{81BACE1B-FB08-4DCF-8100-79911AD3EC1E}) and DODA entry (flat zip extract
to C:\Apps\DODA\). Existing 2016/2019 entries tagged with _CmmVersion.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
09-Setup-CMM: add Step 2.6 that launches each installed PC-DMIS
version once as admin before the PPKG locks the machine down. Also
adds PC-DMIS 2026.1 to the ACL directory list.
Controller credential: cmdkey /add under SYSTEM stored creds in the
wrong vault. Switch to a Register script (MarkerFile detection, runs
once) that creates an AtLogOn scheduled task under BUILTIN\Users so
cmdkey runs in the ShopFloor user's session.
IE compat: update test matrix hash for the new site list that adds
wjfms3.apps.wlm.geaerospace.net.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- gea-shopfloor-nocollections/02-MachineNumberACLs.ps1: gut to no-op
matching the collections variant. SYSTEM Apply task no longer needs
per-user ACLs on the eDNC reg key or UDC ProgramData dir.
- Configure-PC.ps1 item 6 (Machine number logon prompt toggle):
Stop duplicating Register-ScheduledTask logic inline. Call the
shared Register-CheckMachineNumberTask.ps1 registrar so both the
Prompt user-task and Apply SYSTEM-task are installed with matching
SDDL config. Existence check now treats EITHER the new "Prompt
Machine Number" task OR the legacy "Check Machine Number" task as
"ON" so old bays still register correctly. Toggle OFF unregisters
all three names (Prompt + Apply + legacy) for clean removal.
OLD design: a single 'Check Machine Number' scheduled task ran as the
logged-in user (BUILTIN\Users, Limited) on AtLogOn. It both showed the
InputBox AND tried to update HKLM\SOFTWARE\WOW6432Node\GE Aircraft
Engines\DNC\General + C:\ProgramData\UDC\udc_settings.json. To make
those non-admin writes possible, 02-MachineNumberACLs.ps1 pre-granted
BUILTIN\Users SetValue + Modify on those targets during imaging.
Three problems with that:
1. SECURITY: any logged-in user could overwrite the machine-identity
reg key.
2. FRAGILE: ACL grants raced with eDNC install timing on some bays
(eDNC reg key didn't exist yet when 02-MachineNumberACLs ran;
OpenSubKey returned null, ACL silently skipped, Check-MachineNumber
later failed with PermissionDenied).
3. SILENT-SUCCESS BUG: Update-MachineNumber's Set-ItemProperty calls
lacked -ErrorAction Stop. PermissionDenied is a non-terminating
error in PS5.1, so the try/catch never fired. The script set
$out.EdncUpdated=$true anyway and the dialog reported success
while the reg value stayed at 9999. WJF capture log on FGY07FZ3
shows this exact pattern.
NEW design - two scheduled tasks split by responsibility:
- "Prompt Machine Number" : AtLogOn trigger, BUILTIN\Users (Limited).
Reads current values (read-only). If 9999, shows InputBox. Writes
typed number to C:\Logs\SFLD\machine-number-request.txt. Triggers
SYSTEM Apply via schtasks /run. Polls for result JSON (60s timeout).
Shows result MessageBox with TopMost so it isn't hidden behind
other windows.
- "Apply Machine Number" : on-demand, SYSTEM (Highest). Reads the
request file, calls Update-MachineNumber (full HKLM + ProgramData
access from SYSTEM context). Pulls per-machine NTLARS .reg + UDC
settings JSON + UDC live data from the SFLD share if site-config
has share paths. Writes result JSON. Removes request file.
Unregisters the Prompt task on full success (Prompt itself can't
self-unregister - Limited users can't delete a SYSTEM-owned task).
- Default task SDDL only allows Admins + SYSTEM to read/run a
SYSTEM-owned task. Added BUILTIN\Users GR+GX ACE via COM
SetSecurityDescriptor so the Limited Prompt task can schtasks /run
Apply on demand. They can read + execute it; not modify or delete.
- Update-MachineNumber.ps1 writes now have -ErrorAction Stop so
PermissionDenied actually fires the catch block instead of being
swallowed.
- 02-MachineNumberACLs.ps1 gutted to a no-op (left in place for
Stage-Dispatcher discovery; no longer grants the ACLs). Old bays'
existing grants are harmless since SYSTEM ignores them.
- Register-CheckMachineNumberTask.ps1 now installs both tasks AND
unregisters the legacy 'Check Machine Number' task name on
re-imaging. Run-ShopfloorSetup.ps1's $skipInBaseline list now
includes Prompt-MachineNumber.ps1 + Apply-MachineNumber.ps1 so
they aren't auto-run during the baseline pass (only via the
scheduled tasks).
Smoke tested end-to-end on win11 VM with ShopFloor (Limited) logging in
interactively: AtLogOn trigger fired Prompt, dialog rendered, tech
typed 7777, schtasks /run succeeded (the SDDL fix lets Limited users
trigger SYSTEM tasks), Apply ran as SYSTEM, eDNC reg + machine-number.txt
both updated to 7777, result MessageBox shown, Prompt task auto-
unregistered by Apply's cleanup step. No ACL grants needed on any user.
Apply also re-tested with -ErrorAction Stop confirming non-terminating
PermissionDenied now properly throws into the catch + populates Errors[]
+ flips $out.EdncUpdated to false - so any future write failures will
report honestly instead of silently claiming success.
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).
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.
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
- Drop -Physical + MediaType filter from Get-NetAdapter; some OEM driver
stacks report HardwareInterface=False or localize MediaType, hiding the
Realtek controller NIC from the previous query.
- Refine corp-vs-controller classification: skip only if a gateway is set
AND it's not 192.168.1.x, OR if the IP looks corp (10.x / 172.16-31.x).
Keep candidates that are unconfigured, link-local, or 192.168.x.
- Disable DHCP in both PersistentStore and ActiveStore before New-NetIPAddress
to avoid "Inconsistent parameters PolicyStore PersistentStore and Dhcp
enabled" failures.
- Fall back to netsh interface ip set address when the PS cmdlets still
fight each other; netsh writes both stores cleanly.