Fix 7 factual errors in GE-Enforce doc (Fable fact-check vs real source)
All checks were successful
CI / backend (push) Successful in 1m39s
CI / naming (push) Successful in 2s
CI / frontend (push) Successful in 8s

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 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-07-12 22:47:59 -04:00
parent ab0c9a454b
commit e6ed47c533

View File

@@ -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-<type>/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-<type>/manifest.json`, then an optional `<type>-<subtype>` 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-<pctype>/manifest.json`. Common runs first so
shared prerequisites (e.g. Oracle Client) land before type-specific apps that
depend on them.
then `gea-shopfloor-<pctype>/manifest.json`, then a `<pctype>-<subtype>`
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