CMM per-bay PC-DMIS version selection + DODA deploy

Add bay picker (same arrow-key pattern as waxtrace) that maps CMM1-12
to a PC-DMIS version (2016/2019/2026) and DODA flag via cmm-bay-config.csv.

startnet.cmd: replace Standard/DODA submenu with bay picker. Writes
CMMID (e.g. CMM4) to machine-number.txt so the existing
TargetMachineNumbers filter on the SFLD share manifest gates per-bay
entries with no lib changes.

09-Setup-CMM: reads resolved version.txt and filters cmm-manifest.json
by _CmmVersion tag at imaging time so only the matched PC-DMIS version
installs.

cmm-manifest.json: add PC-DMIS 2026.1 entry (patched MSI, product code
{81BACE1B-FB08-4DCF-8100-79911AD3EC1E}) and DODA entry (flat zip extract
to C:\Apps\DODA\). Existing 2016/2019 entries tagged with _CmmVersion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-05-27 12:01:27 -04:00
parent 55c1ab4814
commit 5e13d38512
7 changed files with 314 additions and 33 deletions

View File

@@ -119,14 +119,47 @@ elseif (-not (Test-Path $libSource)) {
Write-CMMLog "Shared library not found at $libSource" "ERROR" Write-CMMLog "Shared library not found at $libSource" "ERROR"
} }
else { else {
# 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 = '' $pcType = ''
$pcSubType = '' $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-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() } if (Test-Path 'C:\Enrollment\pc-subtype.txt') { $pcSubType = (Get-Content 'C:\Enrollment\pc-subtype.txt' -First 1 -EA 0).Trim() }
# Read resolved PC-DMIS version from bay-config (written by
# resolve-cmm-bay-config.ps1 via startnet.cmd). If missing, install all
# PC-DMIS versions (legacy behavior for bays imaged before the picker).
$cmmVersion = ''
$cmmVersionFile = 'C:\Enrollment\cmm\version.txt'
if (Test-Path -LiteralPath $cmmVersionFile) {
$cmmVersion = (Get-Content -LiteralPath $cmmVersionFile -First 1 -EA 0).Trim()
}
Write-CMMLog "Resolved CMM version: $(if ($cmmVersion) { $cmmVersion } else { '(none - installing all)' })"
# Filter manifest: drop entries whose _CmmVersion doesn't match the
# resolved version. Entries without _CmmVersion always pass (CLM, goCMM,
# Protect Viewer, DODA). Write a temp filtered manifest for the lib.
if ($cmmVersion) {
try {
$cfg = Get-Content $stagingMani -Raw | ConvertFrom-Json
$filtered = @($cfg.Applications | Where-Object {
if (-not $_._CmmVersion) { return $true }
return ($_._CmmVersion -ieq $cmmVersion)
})
$skipped = @($cfg.Applications | Where-Object {
$_._CmmVersion -and ($_._CmmVersion -ine $cmmVersion)
})
foreach ($s in $skipped) {
Write-CMMLog " Skipping $($s.Name) (_CmmVersion=$($_._CmmVersion) != $cmmVersion)"
}
$cfg.Applications = $filtered
$filteredMani = Join-Path $stagingRoot 'cmm-manifest-filtered.json'
$cfg | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath $filteredMani -Encoding UTF8
Write-CMMLog "Filtered manifest: $($filtered.Count) entries (from $($filtered.Count + $skipped.Count))"
$stagingMani = $filteredMani
} catch {
Write-CMMLog "Version filter failed: $_ - using unfiltered manifest" 'WARN'
}
}
Write-CMMLog "Running Install-FromManifest against $stagingRoot (PCType=$pcType, PCSubType=$pcSubType)" Write-CMMLog "Running Install-FromManifest against $stagingRoot (PCType=$pcType, PCSubType=$pcSubType)"
& $libSource -ManifestPath $stagingMani -InstallerRoot $stagingRoot -LogFile $logFile -PCType $pcType -PCSubType $pcSubType & $libSource -ManifestPath $stagingMani -InstallerRoot $stagingRoot -LogFile $logFile -PCType $pcType -PCSubType $pcSubType
$rc = $LASTEXITCODE $rc = $LASTEXITCODE

View File

@@ -0,0 +1,38 @@
# Install-DODA.ps1 - Extract DODA zip to C:\Apps\DODA\.
#
# Called by Install-FromManifest as a Type=PS1 entry. The zip is staged
# alongside this script in C:\CMM-Install\ by startnet.cmd.
$ErrorActionPreference = 'Continue'
$installDir = 'C:\Apps\DODA'
$zipPattern = 'doda_build*.zip'
$stagingRoot = Split-Path $PSScriptRoot -ErrorAction SilentlyContinue
if (-not $stagingRoot) { $stagingRoot = 'C:\CMM-Install' }
$zip = Get-ChildItem -Path $stagingRoot -Filter $zipPattern -File -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $zip) {
Write-Host "DODA zip not found in $stagingRoot (pattern: $zipPattern)"
exit 1
}
if (-not (Test-Path $installDir)) {
New-Item -Path $installDir -ItemType Directory -Force | Out-Null
}
Write-Host "Extracting $($zip.Name) to $installDir..."
try {
Expand-Archive -LiteralPath $zip.FullName -DestinationPath $installDir -Force -ErrorAction Stop
Write-Host "DODA extracted to $installDir"
} catch {
Write-Host "ERROR: Extract failed - $_"
exit 1
}
if (Test-Path (Join-Path $installDir 'DovetailAnalysis.exe')) {
Write-Host "DovetailAnalysis.exe verified present"
exit 0
} else {
Write-Host "ERROR: DovetailAnalysis.exe not found after extract"
exit 1
}

View File

@@ -0,0 +1,13 @@
cmm_id,pcdmis_version,doda
CMM1,2019,no
CMM2,2019,no
CMM3,2019,no
CMM4,2016,no
CMM5,2019,no
CMM6,2019,no
CMM7,2019,no
CMM8,2019,no
CMM9,2019,no
CMM10,2016,no
CMM11,2026,no
CMM12,2026,no
1 cmm_id pcdmis_version doda
2 CMM1 2019 no
3 CMM2 2019 no
4 CMM3 2019 no
5 CMM4 2016 no
6 CMM5 2019 no
7 CMM6 2019 no
8 CMM7 2019 no
9 CMM8 2019 no
10 CMM9 2019 no
11 CMM10 2016 no
12 CMM11 2026 no
13 CMM12 2026 no

View File

@@ -1,10 +1,10 @@
{ {
"Version": "2.0", "Version": "2.0",
"_comment": "CMM machine-app manifest, imaging-time only. Consumed by 09-Setup-CMM.ps1 reading from C:\\CMM-Install\\. Ongoing enforcement is handled separately by GE-Enforce reading cmm/manifest.json from the tsgwp00525 share. Option 3 (patched-MSI) install strategy: we bypass Hexagon's Burn bundle entirely for PC-DMIS 2016 and 2019 R2. The main PC-DMIS MSIs have been patched via COM SQL UPDATE (msibuild-style) to force the Condition column to '0' for two custom actions: ProcessLicensingFromBundle (which would otherwise spin for ~13 minutes trying to activate against licensing.wilcoxassoc.com with empty credentials) and IsLicenseDateValid (which would fail the install with 'no valid license'). With both CAs disabled, the MSI installs cleanly with no license present; PCDLRN.exe installs and loads at runtime and the tech activates a real license via clmadmin.exe after imaging. VS 2010/2012 x64 runtime prereqs are handled by the shared preinstall.json VC++ x64 entries (which run before this manifest). CLM Tools 1.5/1.7 chained MSIs from the original bundles are intentionally SKIPPED; CLM 1.8.73 standalone provides the admin + runtime interfaces. Protect Viewer is kept because it's useful alongside PC-DMIS 2019 R2.", "_comment": "CMM machine-app manifest, imaging-time only. Consumed by 09-Setup-CMM.ps1 reading from C:\\CMM-Install\\. 09-Setup reads C:\\Enrollment\\cmm\\version.txt (written by resolve-cmm-bay-config.ps1) and filters PC-DMIS entries by the _CmmVersion tag before passing to Install-FromManifest. Entries without _CmmVersion are always installed (CLM, goCMM, DODA). Ongoing enforcement is handled separately by GE-Enforce reading cmm/manifest.json from the tsgwp00525 share. Patched-MSI install strategy: we bypass Hexagon's Burn bundle entirely. The main PC-DMIS MSIs have been patched via COM SQL UPDATE to force the Condition column to '0' for licensing custom actions (ProcessLicensingFromBundle, IsLicenseDateValid, IsLicenseExpired, IsLmsLicenseServerConnectionError, IsLmsLicenseError). With CAs disabled, the MSI installs cleanly with no license present; the tech activates a real license via clmadmin.exe after imaging.",
"Applications": [ "Applications": [
{ {
"_comment": "PC-DMIS 2016 main MSI (PATCHED). ProcessLicensingFromBundle + IsLicenseDateValid custom actions have been pre-disabled by SQL UPDATE of InstallExecuteSequence.Condition to '0'. Install args: INSTALLFOLDER/APPLICATIONFOLDER paths have embedded double quotes to survive the runner's command-line concatenation when the path contains spaces. USINGWPFINSTALLER=1 mirrors the Burn bundle default and ensures HandleLicenseChoice CA (seq 783) stays skipped. HEIP=0 disables Hexagon telemetry. INSTALLPDFCONVERTER=0 skips the Nitro PDF converter. The patched MSI has a HashMismatch signature, which is expected and accepted by Windows Installer in /qn mode. Detection by uninstall-key presence (no DetectionValue) so a Hexagon security patch that bumps the DisplayVersion does not trigger a re-install loop with exit 1638; bumping the MSI in apps/ is the upgrade path, not version drift-catching.",
"Name": "PC-DMIS 2016", "Name": "PC-DMIS 2016",
"_CmmVersion": "2016",
"Installer": "pcdmis2016-main-patched.msi", "Installer": "pcdmis2016-main-patched.msi",
"Type": "MSI", "Type": "MSI",
"InstallArgs": "/qn /norestart ALLUSERS=1 MSIFASTINSTALL=7 INSTALLFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2016.0 64-bit\" APPLICATIONFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2016.0 64-bit\" USINGWPFINSTALLER=1 HEIP=0 INSTALLPDFCONVERTER=0 REBOOT=ReallySuppress LICENSETYPE=LMSEntitlement", "InstallArgs": "/qn /norestart ALLUSERS=1 MSIFASTINSTALL=7 INSTALLFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2016.0 64-bit\" APPLICATIONFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2016.0 64-bit\" USINGWPFINSTALLER=1 HEIP=0 INSTALLPDFCONVERTER=0 REBOOT=ReallySuppress LICENSETYPE=LMSEntitlement",
@@ -12,8 +12,8 @@
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{5389B196-81F0-44A9-A073-4C1D72041F09}" "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{5389B196-81F0-44A9-A073-4C1D72041F09}"
}, },
{ {
"_comment": "PC-DMIS 2019 R2 main MSI (PATCHED). Same patch strategy as 2016. Adds INSTALLOFFLINEHELP=0 (saves ~1.5 GB) and INSTALLUNIVERSALUPDATER=0 (disables Hexagon's auto-updater which we do not want on air-gapped shopfloor machines). Protect Viewer is a separate MSI installed next. Detection by uninstall-key presence only - see PC-DMIS 2016 entry for reasoning.",
"Name": "PC-DMIS 2019 R2", "Name": "PC-DMIS 2019 R2",
"_CmmVersion": "2019",
"Installer": "pcdmis2019-main-patched.msi", "Installer": "pcdmis2019-main-patched.msi",
"Type": "MSI", "Type": "MSI",
"InstallArgs": "/qn /norestart ALLUSERS=1 MSIFASTINSTALL=7 INSTALLFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2019 R2 64-bit\" APPLICATIONFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2019 R2 64-bit\" USINGWPFINSTALLER=1 HEIP=0 INSTALLPDFCONVERTER=0 INSTALLOFFLINEHELP=0 INSTALLUNIVERSALUPDATER=0 REBOOT=ReallySuppress LICENSETYPE=LMSEntitlement", "InstallArgs": "/qn /norestart ALLUSERS=1 MSIFASTINSTALL=7 INSTALLFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2019 R2 64-bit\" APPLICATIONFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2019 R2 64-bit\" USINGWPFINSTALLER=1 HEIP=0 INSTALLPDFCONVERTER=0 INSTALLOFFLINEHELP=0 INSTALLUNIVERSALUPDATER=0 REBOOT=ReallySuppress LICENSETYPE=LMSEntitlement",
@@ -21,7 +21,16 @@
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{49DBE7F9-228A-4E66-8BB5-DB5A446DCAE7}" "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{49DBE7F9-228A-4E66-8BB5-DB5A446DCAE7}"
}, },
{ {
"_comment": "Protect Viewer - companion tool bundled with PC-DMIS 2019 R2. Separate MSI with no license check of its own. Dark-extracted from the 2019 R2 Burn bundle and shipped as-is.", "Name": "PC-DMIS 2026.1",
"_CmmVersion": "2026",
"Installer": "pcdmis2026-main-patched.msi",
"Type": "MSI",
"InstallArgs": "/qn /norestart ALLUSERS=1 MSIFASTINSTALL=7 INSTALLFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2026.1 64-bit\" APPLICATIONFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2026.1 64-bit\" USINGWPFINSTALLER=1 HEIP=0 INSTALLPDFCONVERTER=0 INSTALLOFFLINEHELP=0 INSTALLUNIVERSALUPDATER=0 REBOOT=ReallySuppress LICENSETYPE=LMSEntitlement",
"DetectionMethod": "Registry",
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{81BACE1B-FB08-4DCF-8100-79911AD3EC1E}"
},
{
"_comment": "Protect Viewer - companion tool. Install for all versions.",
"Name": "Protect Viewer", "Name": "Protect Viewer",
"Installer": "ProtectViewer.msi", "Installer": "ProtectViewer.msi",
"Type": "MSI", "Type": "MSI",
@@ -30,7 +39,7 @@
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{7DE6B8AF-F580-4CDE-845F-FBE46C1FCF69}" "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{7DE6B8AF-F580-4CDE-845F-FBE46C1FCF69}"
}, },
{ {
"_comment": "CLM 1.8.73 standalone bundle - provides clmadmin.exe and the runtime licensing libraries that both PC-DMIS 2016 and 2019 R2 use. Unlike the PC-DMIS bundles, CLM's WiX Burn bundle has no install-time license check (it IS the license tool), so we run it via its original EXE with no patches. The tech uses clmadmin.exe to activate a real license post-imaging, which unlocks both PC-DMIS versions. Detection by uninstall-key presence only - bumping the EXE is the upgrade path.", "_comment": "CLM 1.8.73 standalone - provides clmadmin.exe for license activation. Install for all versions.",
"Name": "CLM 1.8.73", "Name": "CLM 1.8.73",
"Installer": "CLM_1.8.73.0_x64.exe", "Installer": "CLM_1.8.73.0_x64.exe",
"Type": "EXE", "Type": "EXE",
@@ -40,7 +49,7 @@
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{a55fecde-0776-474e-a5b3-d57ea93d6a9f}" "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{a55fecde-0776-474e-a5b3-d57ea93d6a9f}"
}, },
{ {
"_comment": "goCMM - Hexagon's CMM job launcher utility. No license check. Unpatched bundle EXE runs as-is. Note: the installer filename version (1.1.6718.31289) does not match the DisplayVersion the installer registers (it stamps an internal-build version under the uninstall key). Detection by uninstall-key presence avoids that mismatch + future version bumps.", "_comment": "goCMM - Hexagon CMM job launcher. Install for all versions.",
"Name": "goCMM", "Name": "goCMM",
"Installer": "goCMM_1.1.6718.31289.exe", "Installer": "goCMM_1.1.6718.31289.exe",
"Type": "EXE", "Type": "EXE",
@@ -48,16 +57,15 @@
"LogFile": "C:\\Logs\\CMM\\goCMM.log", "LogFile": "C:\\Logs\\CMM\\goCMM.log",
"DetectionMethod": "Registry", "DetectionMethod": "Registry",
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{94f02b85-bbca-422e-9b8b-0c16a769eced}" "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{94f02b85-bbca-422e-9b8b-0c16a769eced}"
},
{
"_comment": "DODA - Dovetail Digital Analysis. Deployed as a flat file extract to C:\\Apps\\DODA\\. Only installed when doda.txt=yes (pc-subtype.txt=doda gates this via PCTypes).",
"Name": "DODA",
"PCTypes": ["cmm-doda"],
"Type": "PS1",
"Script": "Install-DODA.ps1",
"DetectionMethod": "File",
"DetectionPath": "C:\\Apps\\DODA\\DovetailAnalysis.exe"
} }
], ]
"_pending_doda_entry": {
"_comment": "DODA wiring is pending the binary. When DODA installer is sourced, add the entry below to the Applications array above. The startnet.cmd submenu + 09-Setup-CMM.ps1 PCSubType pass-through are already wired - a bay imaged with the 'With DODA' submenu choice today gets pc-subtype.txt=doda but no DODA install happens (no entry matches the cmm-doda PCTypes filter). When ready, fill in Installer + InstallArgs + DetectionPath and move under Applications.",
"Name": "DODA",
"PCTypes": ["cmm-doda"],
"Installer": "DODA-TBD.exe",
"Type": "EXE",
"InstallArgs": "/quiet /norestart",
"DetectionMethod": "Registry",
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DODA-PRODUCT-CODE-TBD}"
}
} }

View File

@@ -0,0 +1,50 @@
# resolve-cmm-bay-config.ps1 - Resolve CMM bay config from cmm-bay-config.csv.
#
# Called by startnet.cmd after the bay picker. Reads the CSV from the PXE
# enrollment share, looks up the selected CMM ID, and writes:
# W:\Enrollment\cmm\version.txt (e.g. "2019")
# W:\Enrollment\cmm\doda.txt (e.g. "yes" or "no")
#
# 09-Setup-CMM.ps1 reads these at install time to gate which PC-DMIS
# version gets installed and whether DODA is deployed.
param(
[Parameter(Mandatory=$true)][string]$ConfigPath,
[Parameter(Mandatory=$true)][string]$CmmId,
[Parameter(Mandatory=$true)][string]$OutDir
)
$ErrorActionPreference = 'Continue'
if (-not (Test-Path -LiteralPath $ConfigPath)) {
Write-Host "ERROR: CSV not found at $ConfigPath"
exit 1
}
try {
$bays = Import-Csv -LiteralPath $ConfigPath
} catch {
Write-Host "ERROR: Failed to parse $ConfigPath - $_"
exit 1
}
$match = $bays | Where-Object { $_.cmm_id -ieq $CmmId }
if (-not $match) {
Write-Host "WARNING: $CmmId not found in bay-config. No version/doda resolution."
exit 0
}
if (-not (Test-Path $OutDir)) {
New-Item -Path $OutDir -ItemType Directory -Force | Out-Null
}
$version = $match.pcdmis_version.Trim()
$doda = $match.doda.Trim().ToLower()
[System.IO.File]::WriteAllText((Join-Path $OutDir 'version.txt'), $version)
[System.IO.File]::WriteAllText((Join-Path $OutDir 'doda.txt'), $doda)
Write-Host "Resolved $CmmId -> PC-DMIS $version, DODA=$doda"
Write-Host " version.txt -> $OutDir\version.txt"
Write-Host " doda.txt -> $OutDir\doda.txt"
exit 0

View File

@@ -0,0 +1,110 @@
# select-cmm-bay.ps1 - Arrow-key CMM bay picker for imaging.
#
# Reads cmm-bay-config.csv from the PXE enrollment share and presents
# a menu of CMM1-CMM12 with their PC-DMIS version and DODA flag.
# Writes the selected CMM ID to $OutFile for startnet.cmd to read back.
#
# Also writes resolved config files so 09-Setup-CMM.ps1 can gate installs:
# C:\Enrollment\cmm\version.txt (e.g. "2019")
# C:\Enrollment\cmm\doda.txt (e.g. "yes" or "no")
#
# Exit codes:
# 0 = CMM ID written to $OutFile
# 1 = user cancelled (Esc)
# 2 = CSV unreadable AND no fallback entered
param(
[string]$ConfigPath = 'Y:\installers-post\cmm\cmm-bay-config.csv',
[Parameter(Mandatory=$true)][string]$OutFile
)
$ErrorActionPreference = 'Continue'
function Read-BayList {
param([string]$Path)
if (-not (Test-Path -LiteralPath $Path)) { return @() }
try {
return Import-Csv -LiteralPath $Path | Sort-Object {
if ($_.cmm_id -match '(\d+)$') { [int]$Matches[1] } else { 999 }
}
} catch {
return @()
}
}
function Show-Menu {
param(
[object[]]$Items,
[int]$Selected,
[string]$Title
)
Clear-Host
Write-Host ""
Write-Host " ========================================"
Write-Host " $Title"
Write-Host " ========================================"
Write-Host ""
Write-Host " Up / Down arrows = navigate, Enter = select, Esc = cancel"
Write-Host ""
for ($i = 0; $i -lt $Items.Count; $i++) {
$item = $Items[$i]
if ($item -is [string]) {
$line = $item
} else {
$dodaLabel = if ($item.doda -ieq 'yes') { '+ DODA' } else { '' }
$line = "{0,-8} PC-DMIS {1,-6} {2}" -f $item.cmm_id, $item.pcdmis_version, $dodaLabel
}
if ($i -eq $Selected) {
Write-Host (" > " + $line) -ForegroundColor Black -BackgroundColor White
} else {
Write-Host (" " + $line)
}
}
}
$bays = @(Read-BayList -Path $ConfigPath)
if ($bays.Count -eq 0) {
Write-Host "WARNING: Could not read $ConfigPath"
}
$menuItems = @($bays) + @("Other (manual entry)")
$selected = 0
while ($true) {
Show-Menu -Items $menuItems -Selected $selected -Title "Select CMM Bay"
$key = [System.Console]::ReadKey($true)
switch ($key.Key) {
'UpArrow' { if ($selected -gt 0) { $selected-- } }
'DownArrow' { if ($selected -lt ($menuItems.Count - 1)) { $selected++ } }
'Enter' { break }
'Escape' { Write-Host "`n Cancelled."; exit 1 }
}
if ($key.Key -eq 'Enter') { break }
}
$chosen = $menuItems[$selected]
if ($chosen -is [string]) {
Write-Host ""
$manual = Read-Host " Enter CMM ID (e.g. CMM1)"
if (-not $manual) {
Write-Host " No CMM ID entered."
exit 2
}
$cmmId = $manual.Trim().ToUpper()
$match = $bays | Where-Object { $_.cmm_id -ieq $cmmId }
if ($match) {
$chosen = $match
} else {
Write-Host " $cmmId not in bay-config. Writing ID only (no version/doda resolution)."
[System.IO.File]::WriteAllText($OutFile, $cmmId)
exit 0
}
}
$cmmId = $chosen.cmm_id.Trim().ToUpper()
[System.IO.File]::WriteAllText($OutFile, $cmmId)
Write-Host ""
Write-Host " Selected: $cmmId (PC-DMIS $($chosen.pcdmis_version), DODA=$($chosen.doda))"
exit 0

View File

@@ -114,18 +114,32 @@ goto enroll_menu
cls cls
echo. echo.
echo ======================================== echo ========================================
echo CMM Variant echo CMM Bay Selection
echo ======================================== echo ========================================
echo. echo.
echo 1. Standard PC-DMIS 2016/2019 R2 + CLM + goCMM + Protect Viewer echo Loading CMM bay list from PXE share...
echo 2. With DODA Standard set plus DODA shopfloor add-on REM Mount enrollment share early so the picker can read the CSV.
net use Y: \\172.16.9.1\enrollment /user:pxe-upload pxe /persistent:no >NUL 2>NUL
del X:\cmm-bay.txt 2>NUL
set CMMID=
set CMMVARIANT=standard
if not exist "Y:\installers-post\cmm\select-cmm-bay.ps1" goto cmm_picker_skip
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "Y:\installers-post\cmm\select-cmm-bay.ps1" -ConfigPath "Y:\installers-post\cmm\cmm-bay-config.csv" -OutFile "X:\cmm-bay.txt"
:cmm_picker_skip
if exist X:\cmm-bay.txt set /p CMMID=<X:\cmm-bay.txt
if not "%CMMID%"=="" goto cmm_have_bay
echo. echo.
set CMMVARIANT= echo Picker unavailable or cancelled. Falling back to manual entry.
set /p cmm_choice=Enter your choice (1-2): set /p CMMID=Enter CMM ID (e.g. CMM1):
if "%cmm_choice%"=="1" set CMMVARIANT=standard :cmm_have_bay
if "%cmm_choice%"=="2" set CMMVARIANT=doda if "%CMMID%"=="" (
if "%CMMVARIANT%"=="" goto cmm_submenu echo WARNING: no CMM ID entered. Defaulting to standard variant.
echo CMM variant: %CMMVARIANT% goto enroll_menu
)
echo CMM bay: %CMMID%
REM Resolve bay config (writes version.txt + doda.txt to W:\Enrollment\cmm\
REM after W: appears). Resolution deferred to after imaging starts - store
REM the CMMID for now and resolve in the post-imaging copy block below.
goto enroll_menu goto enroll_menu
:display_submenu :display_submenu
@@ -199,6 +213,7 @@ set MACHINENUM=9999
if /i "%PCTYPE%"=="gea-shopfloor-collections" goto prompt_machinenum if /i "%PCTYPE%"=="gea-shopfloor-collections" goto prompt_machinenum
if /i "%PCTYPE%"=="gea-shopfloor-nocollections" goto prompt_machinenum if /i "%PCTYPE%"=="gea-shopfloor-nocollections" goto prompt_machinenum
if /i "%PCTYPE%"=="gea-shopfloor-waxtrace" goto prompt_waxtrace_asset if /i "%PCTYPE%"=="gea-shopfloor-waxtrace" goto prompt_waxtrace_asset
if /i "%PCTYPE%"=="gea-shopfloor-cmm" goto skip_machinenum
goto skip_machinenum goto skip_machinenum
:prompt_machinenum :prompt_machinenum
echo. echo.
@@ -391,9 +406,23 @@ if not "%KEYENCEMODEL%"=="" (
echo %KEYENCEMODEL%> W:\Enrollment\keyence-model.txt echo %KEYENCEMODEL%> W:\Enrollment\keyence-model.txt
echo %KEYENCEMODEL%> W:\Enrollment\pc-subtype.txt echo %KEYENCEMODEL%> W:\Enrollment\pc-subtype.txt
) )
REM CMM variant goes to pc-subtype.txt (read by 09-Setup-CMM and the REM CMM bay ID + resolved config. CMMID comes from the bay picker (e.g. CMM4).
REM Install-FromManifest PCTypes filter to gate the DODA app entry). REM Written to machine-number.txt (same field collections/waxtrace use) so
if not "%CMMVARIANT%"=="" echo %CMMVARIANT%> W:\Enrollment\pc-subtype.txt REM TargetMachineNumbers on the SFLD share manifest gates per-bay entries.
REM resolve-cmm-bay-config.ps1 reads the CSV and writes version.txt + doda.txt
REM to W:\Enrollment\cmm\ for 09-Setup-CMM.ps1 to consume.
if "%CMMID%"=="" goto cmm_id_done
echo %CMMID%> W:\Enrollment\machine-number.txt
mkdir W:\Enrollment\cmm 2>NUL
if exist "Y:\installers-post\cmm\resolve-cmm-bay-config.ps1" (
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "Y:\installers-post\cmm\resolve-cmm-bay-config.ps1" -ConfigPath "Y:\installers-post\cmm\cmm-bay-config.csv" -CmmId "%CMMID%" -OutDir "W:\Enrollment\cmm"
)
REM Read doda flag to set pc-subtype.txt for GE-Enforce manifest gating.
REM goto-flow avoids CMD variable scoping issues inside parens blocks.
if not exist W:\Enrollment\cmm\doda.txt goto cmm_id_done
set /p CMMDODA=<W:\Enrollment\cmm\doda.txt
if /i "%CMMDODA%"=="yes" echo doda> W:\Enrollment\pc-subtype.txt
:cmm_id_done
copy /Y "Y:\shopfloor-setup\Run-ShopfloorSetup.ps1" "W:\Enrollment\Run-ShopfloorSetup.ps1" copy /Y "Y:\shopfloor-setup\Run-ShopfloorSetup.ps1" "W:\Enrollment\Run-ShopfloorSetup.ps1"
REM --- Always copy Shopfloor baseline scripts --- REM --- Always copy Shopfloor baseline scripts ---
mkdir W:\Enrollment\shopfloor-setup 2>NUL mkdir W:\Enrollment\shopfloor-setup 2>NUL