Live kernel NetBIOS name instead of the PowerShell process-env cache.
$env:COMPUTERNAME is populated when PowerShell starts and does not
update if the PC gets renamed (common on Intune-managed Autopilot /
AADJ devices that come up with a DESKTOP-XXXXXXXX name and get
renamed by policy post-imaging). Until the next reboot, the env var
stays stale while 'hostname.exe' already reports the new name.
That mismatch showed up live on the first production retrofit: the
status.json was written under _outputs/logs/DESKTOP-XXXXXXXX/
instead of under the device's current name, and the
TargetHostnames filter and monitor drift-check would likewise see
the stale name.
[Environment]::MachineName reads from the kernel on each call, so
it always returns the current NetBIOS name. Swapped at all five
callsites in GE-Enforce.ps1, Register-GEEnforce.ps1, and
Install-FromManifest.ps1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds partial Stage 2b support for InUseCheck entries in manifests. When
an entry declares InUseCheck.Behavior = ForceClose or CloseAndReopen and
the listed processes are running at install time, the lib now:
1. Calls CloseMainWindow() on each matching Process handle (polite WM_CLOSE).
2. Waits GracefulCloseTimeoutSec (default 10) for exit.
3. Hard-kills the process if it did not exit gracefully.
4. Proceeds with the install.
"CloseAndReopen" is currently treated the same as ForceClose - no reopen
happens today. Stage 2b will add the user-session scheduled-task trick
to relaunch the closed app in the logged-in user's session. In practice
for the 24/7 ShopFloor persistent-user pattern the operator relaunches
the app manually (or the app is registered as Startup and reopens on
the next reboot), which is acceptable.
Concrete impact: the eDNC entry in standard-machine/manifest.json lists
InUseCheck.Processes = DncMain + NTLARS with Behavior=CloseAndReopen. On
a retrofit or upgrade cycle that finds eDNC 6.4.3 needs to go to 6.4.5,
the lib now force-closes DncMain and NTLARS before msiexec rather than
risking Restart Manager silently scheduling a pending-file-replace that
does not actually upgrade until the next reboot (which on a 24/7 PC
might be never).
Verified in the Win11 analyzer VM against manifests declaring InUseCheck
on eDNC - logs show "InUseCheck: DncMain (PID ...) asked to close"
followed by either graceful exit or the force-kill path, then install
proceeds without 3010.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Consolidates per-type enforcers (CMM, Keyence, Machine, Common, Acrobat)
into one dispatcher driven by pc-type.txt + site-config and a share-side
manifest layout. Same share is now the single source of truth for routine
software updates without re-imaging.
Runtime:
common/GE-Enforce.ps1 SYSTEM scheduled task. Reads
common/manifest.json plus optional
<pcType>/manifest.json and
<pcType-subType>/manifest.json.
Dispatches each entry through the lib.
Writes _outputs/logs/<hostname>/status.json
on the share after each cycle for fleet
monitoring.
common/Register-GEEnforce.ps1 Task registration. Triggers: AtLogOn +
every 5 min (jittered per-PC from
hostname hash) + daily at 05:45,
13:45, 21:45 EST shift windows.
Unregisters legacy per-type tasks on
install so the two coexist at most for
the duration of a single enforce cycle.
common/Deploy-GEEnforce.ps1 Retrofit helper for already-imaged PCs
(admin-run; copies runtime + registers
task + optional immediate trigger).
Library (common/lib/Install-FromManifest.ps1):
- New Type values: PS1, BAT, File, Registry, INF
- New DetectionMethod values: Always, MarkerFile, ValueMatches, pnputil
- TargetHostnames filter (exact + -like wildcards, ANDed with PCTypes)
- Schema version check (logs WARN on manifest newer than lib MAJOR)
- Auto-writes MarkerFile on successful one-shot PS1/BAT/CMD runs
- MSI log scan on failure surfaces meaningful install errors
- Lib version bumped 2.0 -> 2.1 for TargetHostnames
Observability:
common/monitor-fleet-status.py Scans _outputs/logs/*/status.json for
stale check-ins, failed scopes, and
version drift. Respects scope (dir-name),
PCTypes, and TargetHostnames filters so
entries excluded from a PC do not
false-flag as drift.
Regression harness:
common/test/ Parameterized VM harness + README
covering every action type plus
rollback, bad/missing SFLD creds, and
schema versioning.
Imaging integration:
Run-ShopfloorSetup.ps1 now stages GE-Enforce.ps1 and lib to
C:\Program Files\GE\Shopfloor\ and invokes Register-GEEnforce.ps1
at the end of setup. Legacy Register-CommonEnforce invocation is
kept for the transition; it and the legacy per-type enforcer files
are dead code once Register-GEEnforce runs and will be removed in a
dedicated cleanup pass.
Standard-Machine manifest:
eDNC entry bumped 6.4.3 -> 6.4.5. DetectionValue pinned to the
4-part FileVersion 6.4.5.0 verified against a fresh install in the
Win11 analyzer VM. UDC DetectionValue pinned to 1.0.34 (registry
stores 3-part for UDC; verified live).
scripts/mirror-from-gold.sh:
Restructured around share-root rsyncs (one pass per Samba share)
to close gaps in the prior per-subdir layout: winpeapps/_shared/
Applications (7.5 GB of Adobe + fonts + Java + Office + OpenText
+ printdrivers + wireless + Zscaler), additional winpeapps image
types, and enrollment flat-layout root files. Adds
--skip-clonezilla and --skip-reports.
Verified end-to-end in the Win11 analyzer VM:
- Every action Type and DetectionMethod round-tripped
- PCTypes filter (Oracle excluded on Shopfloor, Firefox included
on Shopfloor and DESKTOP-*, excluded elsewhere)
- TargetHostnames filter (exact, wildcard, no-match)
- Upgrade path: XML hash bump + fleet re-copy
- Rollback path: history-archive restore propagates via enforcer,
fleet converges back without per-PC intervention
- Status writeback + monitor script drift detection
- Graceful degradation on bad creds, missing creds, share
unreachable (all exit 0, log clearly, retry next cycle)
Not in this commit (follow-ups):
- Retire legacy per-type *-Enforce.ps1 files and simplify
09-Setup-*.ps1 scripts (coordinated multi-file cleanup)
- Stage 2b: InUseCheck close-and-reopen, ApplyMode gating,
UpdateWindow, .apply-now.txt sentinel, BITS pre-staging,
1618 mutex retry, PostInstallCheck, Uninstall action
- Management app (manifest CRUD + deploy + rollback + fleet view)
- ShopFloor autologon persistence bug (deferred for next imaging
attempt with live registry evidence)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
File-existence detection on NTLARS.exe couldn't tell eDNC 6.4.3 from 6.4.4
(both installers leave the same binary in place), so the enforcer skipped
upgrades. FileVersion compares the vendor-stamped FileVersion field on a
named binary against the manifest's DetectionValue with exact-string match.
Added to all three lib copies (common, Standard, CMM). Standard manifest
template flipped to FileVersion against DncMain.exe -- the eDNC main
binary is more reliably version-stamped than the bundled NTLARS sub-tool.
Update workflow now: drop the new vendor MSI on the SFLD share, bump
Installer + DetectionValue in machineapps-manifest.json, next user logon
runs Machine-Enforce which detects mismatch and installs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Needed for eMxInfo.txt (site-specific eDNC config). The file has no
DisplayVersion in the registry and no canonical MSI; we ship it as a
standalone secret on the SFLD share and key drift correction off its
SHA256. When the yearly replacement drops, bump the hash in
machineapps-manifest.json and every Standard-Machine PC catches up on
next logon.
Patched Install-FromManifest in all three copies (CMM, common, Standard)
for consistency. Also adds the eMxInfo.txt entry to the Standard
machineapps-manifest template and an Install-eMxInfo.cmd template that
copies the file into both 32/64-bit eDNC Program Files paths.
Acrobat Reader enforcement:
- playbook/shopfloor-setup/common/ is the cross-PC-type staging dir. Mirrors
CMM/ structure (enforce script + its Install-FromManifest copy + manifest
template + register script).
- Acrobat-Enforce.ps1 runs as SYSTEM on every logon, reads
acrobatSharePath from site-config.common, mounts the SFLD share with
the same HKLM-backed credential lookup CMM-Enforce uses, hands the
acrobat-manifest.json from the share to Install-FromManifest.
- Install-FromManifest extended with Type=CMD so it can invoke vendor-
supplied .cmd wrappers (Install-AcroReader.cmd does a two-step MSI+MSP
install that does not fit MSI/EXE types cleanly). cmd.exe /c wraps it
because UseShellExecute=false cannot launch .cmd directly.
- Register-AcrobatEnforce.ps1 stages scripts to C:\Program Files\GE\Acrobat
and registers "GE Acrobat Enforce" scheduled task. Called from
Run-ShopfloorSetup.ps1 right before the enrollment (PPKG) step so it
applies to every PC type, not just CMM.
- acrobat-manifest.template.json is the repo reference; the authoritative
copy lives on the SFLD share at
\\tsgwp00525.wjs.geaerospace.net\shared\dt\shopfloor\common\acrobat\
Bumping Acrobat updates = drop new MSP on share, bump DetectionValue in
manifest; enforcer catches every PC on next logon.
- site-config.json: add "common": { "acrobatSharePath": ... }. Uses a
new top-level block rather than a PC-type-specific one since Acrobat
applies everywhere.
Initial install still happens via the preinstall flow
(Install-AcroReader.cmd during WinPE). The enforcer is the ongoing-
updates side; on a freshly-imaged PC detection passes and it no-ops.
Also in this commit:
- run-enrollment.ps1: provtool.exe argument syntax fix. First test
returned 0x80004005 E_FAIL in 1s because /ppkg: and /log: are not
valid provtool flags; the cmdlet's internal call used positional
path + /quiet + /source. Switched to that syntax.