Under Intune-enforced LSA FIPS policy, Profilometer / VRAnalyzer /
VRInspection apps crash at device init when MD5CryptoServiceProvider's
ctor is called to verify the probe EEPROM calibration (see keyence3000.txt
+ .png in pxe-images for the dialog + stack).
Patch each .exe.config under C:\Program Files\KEYENCE\<model>\ with
<runtime><enforceFIPSPolicy enabled="false"/></runtime>. Scope is app-CLR
only; OS-wide Lsa FIPS policy stays enforced. CMMC posture: scoped
exception, non-CUI integrity hash, documented in SSP. Each affected bay's
hostname must be on InfoSec's FIPS-exception list before imaging.
09-Setup-Keyence.ps1 gates the patch behind model=vr3000 only. vr5000 /
vr6000 bays do not auto-apply. Verified on win11 VM via qga: 29 configs
across vr5000+vr6000 layouts (vr3000 install was incomplete on VM),
patched + idempotent on re-run, existing <runtime> children preserved.
Also verified on a real PC: 27 patched + 2 skipped (Keyence pre-shipped
the element in two configs), 0 errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
VM-test-confirmed root cause for the imaging "Setup wizard prompt"
hang. The bundled MSI has CustomAction caDriverInstall_x64 that
invokes dpinst.exe at install time:
caDriverInstall_x64 type=3666 (exe, deferred) Source=dpinst.exe
Condition: (Not Installed) And VersionNT64 And (VersionNT>=601)
Sequence: 6505
The bundled dpinst.xml is minimal (<dpInst><legacyMode/></dpInst>) -
no <quietInstall/> directive - so dpinst pops its wizard and waits
for operator click-through. /qn on the parent MSI does NOT propagate
into the dpinst child process. pnputil pre-staging the INF + cert
pre-trust to TrustedPublisher does NOT prevent the CA from firing
(the CA runs unconditionally on first install regardless of
DriverStore presence).
Fix: msibuild patch the MSI's InstallExecuteSequence to set the
action's Condition column from
"(Not Installed) And VersionNT64 And (VersionNT>=601)"
to
"0"
which evaluates false on every install attempt - the action never
fires, dpinst never runs, no wizard pops.
The driver itself is now installed exclusively by:
1. our pnputil pre-stage in 09-Setup-Keyence.ps1 (already there),
2. the manifest's separate "KEYENCE VR Series USB Driver" INF entry.
End-to-end VM test: 36s, exit 0, VR-6000 DisplayVersion 4.3.7
detected, zero dpinst processes at finish.
MSI size 1751552 -> 1744896 bytes (msibuild table rewrite).
md5: c6edcfc6c6808617598bcb7a15072a30.
Backups of original MSI on live PXE server enrollment share + local
SFLD share mirror as .bak-<TS>-orig.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Adds end-to-end progress tracking for PXE imaging sessions and surfaces
each Blancco report's BIOS serial in the report list.
webapp:
* services/imaging_status.py - JSON-per-serial state store under
IMAGING_DIR (default /var/log/pxe-imaging). Atomic write via
tempfile + rename. log_tail capped at 50 lines. Merges partial
updates so clients can post just the current_stage tick.
* config.py - new IMAGING_DIR env-overridable path.
* services/csrf.py - explicit exempt list for machine-to-machine
endpoints; /imaging/status is the first entry. Air-gapped LAN;
trust-by-network for client posts.
* app.py - four new routes:
GET /imaging dashboard (renders all sessions)
POST /imaging/status client status push (JSON body)
GET /imaging/<serial>.json raw session JSON for ad-hoc polling
POST /imaging/delete/<s> clear a session from the dashboard
Also parses each Blancco XML in the /reports list to surface
system.serial + system.model columns.
* templates/imaging.html - Bootstrap dashboard with per-session
cards (state badge, progress bar, stage idx/total, mac, elapsed,
log tail). meta http-equiv refresh=5 for auto-tick.
* templates/base.html - new "Imaging Progress" nav entry.
* templates/reports.html - Serial + Model columns added.
playbook:
* shopfloor-setup/Shopfloor/lib/Send-PxeStatus.ps1 - new helper.
Dot-source this then call Send-PxeStatus -Stage X -StageIndex N
-StageTotal M from any stage script. BIOS serial via CIM, MAC via
Get-NetAdapter, pctype + machinenumber from C:\Enrollment.
Failures are swallowed to a local log so a network blip doesn't
block imaging.
* shopfloor-setup/Run-ShopfloorSetup.ps1 - dot-sources helper +
posts at three coarse milestones (start, PPKG enrollment,
handoff to Monitor-IntuneProgress).
* shopfloor-setup/gea-shopfloor-keyence/09-Setup-Keyence.ps1 -
posts at session start + after Install-FromManifest with
succeeded/failed status derived from $rc. Other 09-Setup-*.ps1
scripts can follow the same pattern.
ID is BIOS serial (stable across WinPE -> Windows transition and
across reboots, unlike hostname which is random pre-PPKG). Operator
already knows the serial of the bay they imaged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
VR-6000 Series Software.msi is an InstallShield MSI that references
Data1.cab in the same directory for its compressed payload. The cab was
never staged into the repo's keyence installers/ dir, so msiexec exited
1603 with "SECREPAIR: Failed to open the file ... Data1.cab" on every
imaging run (see Logs/Keyence/install.log on a failed bay for the
canonical signature). Only the 1.75 MB MSI was committed; the 560 MB
cab lives on the GE-Enforce SFLD share at
tsgwp00525\sfld$\v2\shared\dt\shopfloor\gea-shopfloor-keyence\apps\.
This commit doesn't add the cab itself (560 MB; same gitignore convention
as PrinterInstallerMap.exe and other large binaries). Instead it pins the
staging requirement in two places:
* .gitignore: explicit entry with the SFLD share path so a future
operator wiring up a fresh PXE server build knows where to source it.
* keyence-manifest.json _comment: documents the dependency next to the
MSI declaration that needs it.
The local repo at /home/camp/projects/pxe now has the cab staged in
playbook/shopfloor-setup/gea-shopfloor-keyence/installers/ for the next
USB build. Rebuilding the Keyence image and re-imaging the failed bay
should now reach DisplayVersion 4.3.7 detection successfully.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>