CMM: subtype gating + relax exact-version + conditional cleanup + DODA placeholder

Carries over the lessons learned from wax/trace + Keyence imaging today
and threads the same pattern through the CMM path.

09-Setup-CMM.ps1:
- Pass PCType + PCSubType to Install-FromManifest so the manifest's
  per-entry PCTypes filter is honored. Without this every entry runs
  regardless of bay variant - the same bug Keyence had before per-model
  gating was added.
- Move bootstrap cleanup to a conditional that only deletes
  C:\CMM-Install once every (filter-applicable) manifest entry detects
  as installed. If a Hexagon installer forces an unplanned reboot
  mid-install, the new Run-ShopfloorSetup self-resume RunOnce fires on
  the next auto-login; the staging dir needs to still be on disk for
  the re-run to recover. Logs "retained ... not all entries installed
  yet - will retry on next self-resumed run" when partial.

cmm-manifest.json:
- Drop exact DetectionValue from PC-DMIS 2016, PC-DMIS 2019 R2, CLM
  1.8.73, and goCMM. Detection is now uninstall-key presence only, so
  a Hexagon security patch that bumps the DisplayVersion does not
  trigger a re-install loop with exit 1638 every GE-Enforce cycle.
  Bumping the installer in apps/ is the upgrade path - manifest engine
  detection should not also be a version drift catcher for vendor MSIs
  whose backward-compat is established by the vendor.
- Specific to goCMM: the installer filename version (1.1.6718.31289)
  does not match what the installer registers under its uninstall key.
  Dropping DetectionValue silences the false-mismatch loop the prior
  version would have triggered.
- Add DODA placeholder entry gated to PCTypes=["cmm-doda"]. Real
  Installer filename, args, and DetectionPath still TODO once the
  DODA binary is sourced + dropped at installers-post/cmm/.

startnet.cmd:
- Add :cmm_submenu after the user picks gea-shopfloor-cmm from the
  main menu. Two options: Standard (default PC-DMIS + CLM + goCMM
  + Protect Viewer) or With DODA. Mirrors :keyence_submenu pattern.
- Write CMMVARIANT to W:\Enrollment\pc-subtype.txt so Install-FromManifest
  on the bay can apply the PCTypes filter against gea-shopfloor-cmm-doda.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-05-22 09:48:16 -04:00
parent 45f39fd431
commit 548d85fed5
3 changed files with 89 additions and 23 deletions

View File

@@ -119,8 +119,16 @@ elseif (-not (Test-Path $libSource)) {
Write-CMMLog "Shared library not found at $libSource" "ERROR"
}
else {
Write-CMMLog "Running Install-FromManifest against $stagingRoot"
& $libSource -ManifestPath $stagingMani -InstallerRoot $stagingRoot -LogFile $logFile
# Pass PCType + PCSubType so cmm-manifest.json's PCTypes filter on
# subtype-specific entries (e.g. DODA gated to cmm-doda) is honored.
# Without this, ALL entries run regardless of subtype - same bug we
# had on Keyence before the per-model gating fix.
$pcType = ''
$pcSubType = ''
if (Test-Path 'C:\Enrollment\pc-type.txt') { $pcType = (Get-Content 'C:\Enrollment\pc-type.txt' -First 1 -EA 0).Trim() }
if (Test-Path 'C:\Enrollment\pc-subtype.txt') { $pcSubType = (Get-Content 'C:\Enrollment\pc-subtype.txt' -First 1 -EA 0).Trim() }
Write-CMMLog "Running Install-FromManifest against $stagingRoot (PCType=$pcType, PCSubType=$pcSubType)"
& $libSource -ManifestPath $stagingMani -InstallerRoot $stagingRoot -LogFile $logFile -PCType $pcType -PCSubType $pcSubType
$rc = $LASTEXITCODE
Write-CMMLog "Install-FromManifest returned $rc"
}
@@ -164,18 +172,52 @@ foreach ($dir in $pcdmisDirs) {
}
# ============================================================================
# Step 3: Clean up the bootstrap staging dir
# Step 3: Conditional cleanup of the bootstrap staging dir
# ============================================================================
# ~2 GB reclaimed. From here on, GE-Enforce takes over from the tsgwp00525
# share for ongoing updates.
if (Test-Path $stagingRoot) {
Write-CMMLog "Deleting bootstrap staging at $stagingRoot"
# Only delete C:\CMM-Install when EVERY manifest entry detected as installed.
# A vendor installer that forces an unplanned mid-install reboot would
# otherwise leave us with no recovery path on the self-resumed re-run
# (Run-ShopfloorSetup's new RunOnce would fire, but Step 2 would log
# "$stagingRoot does not exist" and bail). Leaving the staging dir in
# place until the manifest fully converges means a re-fire just re-runs
# the partial installs and completes.
$allDetected = $true
if (Test-Path $stagingMani) {
try {
$cfg = Get-Content $stagingMani -Raw | ConvertFrom-Json
foreach ($app in $cfg.Applications) {
if (-not $app.DetectionMethod -or -not $app.DetectionPath) { continue }
# Honor PCTypes filter when checking detection.
if ($app.PCTypes -and $app.PCTypes.Count -gt 0) {
$myNames = @($pcType)
if ($pcSubType) { $myNames += "$pcType-$pcSubType" }
$match = $false
foreach ($t in $app.PCTypes) { if ($myNames -contains $t) { $match = $true; break } }
if (-not $match) { continue } # not applicable to this PC, skip detection
}
if (-not (Test-Path $app.DetectionPath)) { $allDetected = $false; Write-CMMLog "Not installed: $($app.Name)"; break }
if ($app.DetectionName) {
$val = (Get-ItemProperty -Path $app.DetectionPath -Name $app.DetectionName -EA 0).$($app.DetectionName)
if (-not $val) { $allDetected = $false; Write-CMMLog "Not installed (no value): $($app.Name)"; break }
if ($app.DetectionValue -and $val -ne $app.DetectionValue) { $allDetected = $false; Write-CMMLog "Wrong version: $($app.Name) got $val expected $($app.DetectionValue)"; break }
}
}
} catch {
Write-CMMLog "Could not parse manifest for cleanup-gate check: $_" 'WARN'
$allDetected = $false
}
}
if ($allDetected -and (Test-Path $stagingRoot)) {
Write-CMMLog "All manifest entries installed. Deleting bootstrap staging at $stagingRoot"
try {
Remove-Item -LiteralPath $stagingRoot -Recurse -Force -ErrorAction Stop
Write-CMMLog "Bootstrap cleanup complete"
} catch {
Write-CMMLog "Failed to delete $stagingRoot : $_" "WARN"
}
} elseif (Test-Path $stagingRoot) {
Write-CMMLog "Bootstrap staging retained at $stagingRoot (not all entries installed yet - will retry on next self-resumed run)"
}
if (Get-Command Send-PxeStatus -ErrorAction SilentlyContinue) {