From e6ed47c533a5b42e62f773ce6427d54c2dc96a80 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Sun, 12 Jul 2026 22:47:59 -0400 Subject: [PATCH] Fix 7 factual errors in GE-Enforce doc (Fable fact-check vs real source) Verified claim-by-claim against the engine/dispatcher/preinstall runner/manifests. Corrections (3 were ship-blocking): - Timeline (ship-blocking): identity files (pc-type/machine-number/cmm version/ site-config) are written in WinPE at the PXE menu BEFORE the image boots, not during a post-imaging 'enrollment' step; preinstall already reads them. Added a step [0]; enrollment is now only Intune + Azure DSC credential provisioning. - _CmmVersion (ship-blocking): a CMM bay with NO resolved version gets ALL PC-DMIS versions (legacy install-all), not none. - machine-number 9999 (ship-blocking): the enforcement engine does not special-case 9999; it is a placeholder that won't match real bay gates (the 9999-skip is status-write-back only). - Preinstall runner implements only MSI/EXE + Registry/File detection, not the full matrix (that is runtime-only). - Runtime processes up to three scopes: common, type, then optional type-subtype. - pc-subtype.txt is legacy (no longer written at imaging since 2026-05-04). - The collector ComputerType mapping lives at Settings > Collector PC Types, not the geenforce scope (scope computertypeid is a local reference field). - FileVersion is a raw string compare; 4-part is convention, not engine-enforced. Co-Authored-By: Claude Opus 4.8 --- docs/GE-ENFORCE.md | 77 +++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/docs/GE-ENFORCE.md b/docs/GE-ENFORCE.md index 80ba106..a584699 100644 --- a/docs/GE-ENFORCE.md +++ b/docs/GE-ENFORCE.md @@ -45,10 +45,13 @@ Every shopfloor PC is governed in two distinct phases: | Phase | When | Runs what | Purpose | |---|---|---|---| | **Preinstall** | ONCE, at imaging | `preinstall.json` (via the imaging `00-PreInstall` step) | Day-zero foundation: PowerShell 7, the VC++ redistributable matrix, Oracle Client, Adobe Reader, HostExplorer, serial drivers, etc. "Install once at imaging, no drift correction." | -| **Runtime** | EVERY logon + periodically | `common/manifest.json` then the PC's `gea-shopfloor-/manifest.json` | Ongoing enforcement + self-heal: app versions, config-file drift, registry drift, per-cycle scripts (asset report, VNC firewall, EventSaver), version-gated installs. | +| **Runtime** | EVERY logon + periodically | `common/manifest.json`, then `gea-shopfloor-/manifest.json`, then an optional `-` manifest | Ongoing enforcement + self-heal: app versions, config-file drift, registry drift, per-cycle scripts (asset report, VNC firewall, EventSaver), version-gated installs. | -The two phases share the SAME entry schema but are run by different runners. -Preinstall is a one-shot at imaging; runtime is the continuous enforcement loop. +The two phases share the same entry SHAPE (field names) but are run by different +runners with different capabilities. Preinstall is a one-shot at imaging that +implements only `Type=MSI` and `Type=EXE`, with only `Registry` / `File` +detection (other types/detections are skipped). Runtime is the continuous +enforcement loop and implements the full Type + DetectionMethod matrix below. ### 2.2 The runtime loop, step by step @@ -60,9 +63,9 @@ On each cycle (`GE-Enforce.ps1` on the PC): provisioned SFLD user - `net use W: ...`). If no credential yet, exit 0 and retry next cycle (Azure DSC has not provisioned it). 3. Run the engine (`Install-FromManifest.ps1`) against `common/manifest.json`, - then against `gea-shopfloor-/manifest.json`. Common runs first so - shared prerequisites (e.g. Oracle Client) land before type-specific apps that - depend on them. + then `gea-shopfloor-/manifest.json`, then a `-` + manifest if one exists. Common runs first so shared prerequisites (e.g. + Oracle Client) land before type-specific apps that depend on them. 4. Write a status file back to the share (and, in the shopdb model, POST a report - see 4.3). @@ -101,7 +104,7 @@ Every entry has a `DetectionMethod` that decides whether the action fires: |---|---| | Registry | the key/value exists (optionally equals a value) | | File | the file exists | -| FileVersion | the file's version equals an exact 4-part string | +| FileVersion | the file's version string matches exactly (fleet convention is a 4-part string like 6.4.5.0; the engine does a raw string compare, it does not enforce 4 parts) | | Hash | the file's SHA256 matches (case-insensitive) | | MarkerFile | a marker file exists (the engine writes it after a clean install) | | ValueMatches | a registry value equals the entry's target | @@ -122,8 +125,11 @@ An entry can be narrowed by any combination of: `collections`/`nocollections`/`common`). Fleet-wide `common` uses this heavily. - `TargetHostnames` - specific hostnames (supports `*` wildcards). - `TargetMachineNumbers` - specific bay machine numbers (e.g. Okuma bays). -- `_CmmVersion` - CMM PCs only: install only on bays resolved to that PC-DMIS - version (requires engine lib >= 2.6). +- `_CmmVersion` - CMM PCs only: a tagged entry applies when it equals the bay's + resolved PC-DMIS version (`C:\Enrollment\cmm\version.txt`). IMPORTANT: if no + version is resolved (file missing/empty - a pre-picker bay), ALL tagged + entries apply (deliberate legacy "install-all" behavior), so such a bay gets + every PC-DMIS version, not none. Requires engine lib >= 2.6. - `PCTypesStrict` - disables alias expansion (PREINSTALL runner only; the runtime engine ignores it). @@ -135,14 +141,24 @@ the gates a given scope actually uses (see 4.1). The runtime engine reads the PC's identity from `C:\Enrollment\`: -- `pc-type.txt` / `pc-subtype.txt` - the imaging PC type (which scope to run). -- `machine-number.txt` - the bay number (the eDNC/DNC registry value wins if - present; the txt is the fallback). `9999` = placeholder/skip. +- `pc-type.txt` - the imaging PC type (which scope to run). `pc-subtype.txt` is + LEGACY (no longer written at imaging since the 2026-05-04 rename reorg; the + dispatcher still honors it if present on older fleet PCs). +- `machine-number.txt` - the bay number FALLBACK; the eDNC/DNC registry + `MachineNo` value wins if present. `9999` is the imaging placeholder by + convention - the enforcement engine does NOT special-case it; it is simply a + value that won't match a real bay number in a `TargetMachineNumbers` gate. + (The 9999-skip you may see is only in the status write-back, not enforcement.) - `cmm/version.txt` - CMM bays only: the resolved PC-DMIS version for `_CmmVersion`. - `site-config.json` - the share root and site settings. - SFLD credentials at `HKLM:\SOFTWARE\GE\SFLD\Credentials` - provisioned by Azure DSC after enrollment (this is what gates the runtime phase starting). +Note: all of the identity files above (pc-type, machine-number, cmm version, +site-config) are written in WinPE at the PXE menu, BEFORE the image boots - the +preinstall phase already reads them. What happens post-imaging is only Intune +enrollment + the Azure DSC credential (see the timeline below). + --- ## 3. When GE-Enforce installs / takes over (the imaging timeline) @@ -150,29 +166,38 @@ The runtime engine reads the PC's identity from `C:\Enrollment\`: This is the "when to implement it during imaging" question. The order is: ``` -PXE image applied +[0] WinPE / PXE menu (BEFORE the image boots) + - identity written to C:\Enrollment: pc-type.txt, machine-number.txt, + cmm/version.txt, site-config.json (startnet.cmd). The PC already knows + what it is before Windows starts. | v -[1] PREINSTALL (00-PreInstall-* runs preinstall.json ONCE) - - foundational software: PowerShell 7, VC++ redists, Oracle Client, - Adobe Reader, HostExplorer, serial drivers, Display kiosk app, ... - - these are the things later runtime apps depend on + PXE image applied, Windows boots + | + v +[1] PREINSTALL (00-PreInstall runner runs preinstall.json ONCE) + - reads the step-0 identity files, then installs the foundation: + PowerShell 7, VC++ redists, Oracle Client, Adobe Reader, HostExplorer, + serial drivers, Display kiosk app, ... (things later runtime apps need) + - preinstall implements MSI/EXE + Registry/File detection only | v [2] GE-ENFORCE ITSELF is laid down during imaging - the dispatcher (GE-Enforce.ps1), the engine lib (Install-FromManifest.ps1), - and a scheduled task (at-logon + periodic) are placed on the PC as part - of the image / common bootstrap + and a scheduled task (at-logon + every ~5 min + shift windows) are + registered as part of the image / shopfloor setup | v -[3] ENROLLMENT - - C:\Enrollment\* written: pc-type, machine number, cmm version, site-config - - Azure DSC provisions the SFLD share credential in the registry +[3] ENROLLMENT (post-imaging) + - Intune / GCCH enrollment, THEN Azure DSC provisions the SFLD share + credential into HKLM:\SOFTWARE\GE\SFLD\Credentials + - (the identity files already exist from step 0 - enrollment adds only the + credential, which is what unblocks runtime) | v [4] FIRST LOGON -> RUNTIME ENFORCEMENT BEGINS - the scheduled task runs GE-Enforce.ps1: mount share, run common + the - PC-type manifest, install/self-heal, report + PC-type (+ subtype) manifests, install/self-heal, report - repeats every logon + periodically forever after ``` @@ -205,8 +230,10 @@ because it is a full management surface. ### 4.1 Manifests - authoring (GE-Enforce > Manifests) -- **PC Types (scopes):** each imaging PC type is a row; add/edit/delete. The - ComputerType mapping the collector uses lives here too. +- **PC Types (scopes):** each imaging PC type is a row; add/edit/delete. (The + scope carries an optional `computertypeid` reference field, but the collector's + imaging-pc-type -> ComputerType mapping is configured separately at + Settings > Collector PC Types.) - **Entries:** an ordered list (Up/Down = the execution-order contract). Add/Edit opens a typed form: the payload fields switch on `Type` (MSI shows Installer + InstallArgs, PS1 shows Script + Args, File shows Source + Destination, Registry