shopfloor: CMM PC-DMIS version gate, ShopDB reporter fixes, staging self-heal

- 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>
This commit is contained in:
cproudlock
2026-06-14 09:14:54 -04:00
parent c2538a05c5
commit e97e5bd049
10 changed files with 735 additions and 45 deletions

View File

@@ -38,6 +38,12 @@ $ErrorActionPreference = 'Continue'
# logged; manifests tagged with a newer MINOR are fine.
#
# Changelog:
# 2.6 - added _CmmVersion filter. Entry tagged _CmmVersion only applies when
# it equals C:\Enrollment\cmm\version.txt (the bay's resolved PC-DMIS
# version, written at imaging from cmm-bay-config.csv). Untagged entries
# always pass; missing/empty version file is a no-op (legacy install-all
# + non-CMM scopes unaffected). Lifted out of 09-Setup-CMM so the gate
# lives in one place both the imaging and enforce paths share.
# 2.5 - Type=EXE handler honors optional WaitTimeoutSec on the manifest
# entry. WiX Burn bootstrappers (UDC_Setup.exe) install the MSI
# successfully but the wrapper process never exits (waits on a
@@ -58,7 +64,7 @@ $ErrorActionPreference = 'Continue'
# 2.0 - initial Stage 2a: PS1/BAT/File/Registry/INF action types,
# Always/MarkerFile/ValueMatches/pnputil detection, PCTypes filter
$LIB_MANIFEST_MAJOR = 2
$LIB_MANIFEST_MINOR = 5
$LIB_MANIFEST_MINOR = 6
$logDir = Split-Path -Parent $LogFile
if (-not (Test-Path $logDir)) {
@@ -575,6 +581,42 @@ function Test-MachineNumberMatches {
return $false
}
# CMM PC-DMIS version filter. The bay's PC-DMIS version (2016/2019/2026) is
# resolved at imaging by resolve-cmm-bay-config.ps1 from cmm-bay-config.csv (the
# single bay -> version map) and persisted to C:\Enrollment\cmm\version.txt. An
# entry tagged _CmmVersion applies only when it equals that file; untagged
# entries (CLM, goCMM, Protect Viewer, DODA, the PDF converter) always pass.
# When the file is absent/empty - a bay imaged before the picker, or any
# non-CMM PC running a different scope - the filter is a no-op so every tagged
# entry passes. That preserves the legacy "install all versions" behavior for
# pre-picker bays and leaves non-CMM scopes untouched.
#
# This is the SINGLE place the version gate lives. Both the imaging path
# (09-Setup-CMM) and the runtime path (GE-Enforce) call this lib, so the gate
# cannot apply in one path and not the other. The 2016-installed-on-a-2019-bay
# bug was exactly that drift: the imaging path filtered by _CmmVersion but the
# enforce path did not, so enforce reinstalled every version it did not detect.
$script:_cachedCmmVersion = $null
$script:_cmmVersionRead = $false
function Get-CurrentCmmVersion {
if ($script:_cmmVersionRead) { return $script:_cachedCmmVersion }
$script:_cmmVersionRead = $true
$f = 'C:\Enrollment\cmm\version.txt'
if (Test-Path -LiteralPath $f) {
$v = (Get-Content -LiteralPath $f -First 1 -ErrorAction SilentlyContinue)
if ($v) { $script:_cachedCmmVersion = $v.Trim() }
}
return $script:_cachedCmmVersion
}
function Test-CmmVersionMatches {
param($App)
if (-not $App._CmmVersion) { return $true } # untagged entry always applies
$myVer = Get-CurrentCmmVersion
if (-not $myVer) { return $true } # no resolved version -> legacy install-all
return ([string]$App._CmmVersion -ieq $myVer)
}
# ---------------------------------------------------------------------------
# Main loop
# ---------------------------------------------------------------------------
@@ -614,6 +656,13 @@ foreach ($app in $config.Applications) {
continue
}
if (-not (Test-CmmVersionMatches -App $app)) {
$myVer = Get-CurrentCmmVersion
Write-InstallLog " _CmmVersion filter: entry targets $($app._CmmVersion) but bay version is $(if ($myVer) { $myVer } else { '(none)' }) - skipping"
$pcFiltered++
continue
}
if (Test-AppInstalled -App $app) {
Write-InstallLog ' Already installed at expected version - skipping'
$skipped++