CMM: wire per-bay settings restore into the imaging flow
Restore-CMM.ps1 (new) restores a CMM's PC-DMIS + goCMM settings at imaging from
its staged backup. Self-gating: reads C:\Enrollment\cmm\{cmmid,version,doda,
partgroup}.txt, skips DODA bays and bays with no staged backup, and restores
ONLY the config-version PC-DMIS zip via the existing Install-*Settings scripts.
Same-bay restore (cmmid match) so the backed-up controller CommPort is this
bay's own value - no cross-bay clobber.
Version selection matches the VERSION FIELD of the zip name, anchored on the
trailing timestamp, so version=2026 does not false-match a 2019/2016 zip whose
backup timestamp (20260612...) merely contains "2026".
09-Setup-CMM.ps1: new Step 2.8 calls Restore-CMM after app install + first-run
init (so a restored config is not clobbered by PC-DMIS defaults) and before the
C:\CMM-Install cleanup (the backup set lives under <stagingRoot>\backups\<cmmid>).
Best-effort: Restore-CMM always exits 0, imaging never fails on a restore.
startnet.cmd: stage ONLY the picked bay's backup into C:\CMM-Install\backups\
%CMMID% (the bulk robocopy now /XD-excludes the backups tree, which holds every
bay's backup - some 240 MB each - to avoid copying GBs to every imaged CMM).
Also bump the PPKG to v4.16 (the live boot.wim was already v4.16; the repo had
drifted to v4.14).
sync-cmm-backups.sh: source the backups from pxe-images/cmm/backups (where
Backup-CMM writes via the pulled-down copies), not the old cmm-bk path.
Smoke tested on the win11 VM against CMM3's real backup: version=2019 restored
the 2019 R2 zip (not 2016.0), imported HKLM+HKCU reg, converted the part-group
S:\ path to the tsgwp00525 UNC, created C:\geaofi, exit 0; version=2026 correctly
found no matching zip (anchor works).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -321,6 +321,28 @@ if (Test-Path $goCmmKey) {
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Step 2.8: Restore this bay's PC-DMIS + goCMM settings from its backup
|
||||
# ============================================================================
|
||||
# Runs AFTER app install + first-run-init (so a restored config is not clobbered
|
||||
# by PC-DMIS's first-launch defaults) and BEFORE the Step 3 cleanup (the backup
|
||||
# set lives under $stagingRoot\backups\<cmmid>, deleted by cleanup). Restore-CMM
|
||||
# self-gates: it skips DODA bays and bays with no staged backup, and restores
|
||||
# ONLY the config-version PC-DMIS zip. Same-bay restore -> no CommPort clobber.
|
||||
# Best-effort: Restore-CMM always exits 0, so imaging never fails on a restore.
|
||||
$restoreScript = Join-Path $PSScriptRoot 'scripts\Restore-CMM.ps1'
|
||||
if (Test-Path -LiteralPath $restoreScript) {
|
||||
Write-CMMLog "Running per-bay settings restore (Restore-CMM.ps1)"
|
||||
try {
|
||||
& $restoreScript -BackupRoot (Join-Path $stagingRoot 'backups') *>&1 | ForEach-Object { Write-CMMLog " $_" }
|
||||
Write-CMMLog "Restore-CMM returned $LASTEXITCODE"
|
||||
} catch {
|
||||
Write-CMMLog "Restore-CMM threw (non-fatal): $_" 'WARN'
|
||||
}
|
||||
} else {
|
||||
Write-CMMLog "Restore-CMM.ps1 not found at $restoreScript - skipping settings restore" 'WARN'
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Step 3: Conditional cleanup of the bootstrap staging dir
|
||||
# ============================================================================
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
<#
|
||||
Restore-CMM.ps1
|
||||
|
||||
Imaging-time per-bay settings restore. Called by 09-Setup-CMM after app install,
|
||||
before the C:\CMM-Install cleanup (it reads the staged backup from there).
|
||||
|
||||
Reads the resolved bay identity from C:\Enrollment\cmm\ (written by
|
||||
resolve-cmm-bay-config.ps1 at the WinPE picker):
|
||||
cmmid.txt - which staged backup set to use (e.g. CMM3)
|
||||
version.txt - which PC-DMIS version to restore. A bay's backup holds every
|
||||
version it ever had (2016.0 + 2019 R2); we restore ONLY the
|
||||
one the bay-config pins, matched by substring (2019 -> the
|
||||
'2019 R2' zip, 2016 -> the '2016.0' zip).
|
||||
doda.txt - 'no' to proceed; anything else SKIPS restore (DODA bays are
|
||||
handled separately and must not get a settings overlay).
|
||||
partgroup.txt - optional goCMM Selected Part Group (friendly S:\ form), used
|
||||
as the authoritative per-bay override even if the backup is stale.
|
||||
|
||||
Finds the backup set at <BackupRoot>\<cmmid>\ (default C:\CMM-Install\backups,
|
||||
robocopied there from the PXE share by startnet) and restores via the sibling
|
||||
Install-PCDMISSettings.ps1 + Install-goCMMSettings.ps1.
|
||||
|
||||
SAME-BAY restore by design (cmmid match), so the backed-up controller CommPort
|
||||
is this bay's own value - no cross-bay CommPort clobber. (The clobber problem is
|
||||
only when one bay's settings are pushed onto a different bay.)
|
||||
|
||||
Best-effort: always exits 0. Imaging must never fail because a restore step
|
||||
could not find a backup or hit a non-fatal error - those are logged.
|
||||
#>
|
||||
param(
|
||||
[string]$EnrollDir = 'C:\Enrollment\cmm',
|
||||
[string]$BackupRoot = 'C:\CMM-Install\backups',
|
||||
[string]$TargetUser = 'ShopFloor',
|
||||
[string]$PartGroupShareRoot = '\\tsgwp00525.wjs.geaerospace.net\SHARED',
|
||||
[string]$OutDir = 'C:\Logs\CMM'
|
||||
)
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
New-Item -ItemType Directory -Path $OutDir -Force -EA SilentlyContinue | Out-Null
|
||||
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$log = Join-Path $OutDir "restore-cmm-$ts.log"
|
||||
function Log($m){ $line = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $m"; Write-Host $line; $line | Out-File -FilePath $log -Append -Encoding ascii }
|
||||
function ReadTxt($n){ $p = Join-Path $EnrollDir $n; if (Test-Path -LiteralPath $p) { (Get-Content -LiteralPath $p -First 1 -EA 0).Trim() } else { '' } }
|
||||
|
||||
Log "==== CMM settings restore on $env:COMPUTERNAME ===="
|
||||
|
||||
$cmmid = ReadTxt 'cmmid.txt'
|
||||
$ver = ReadTxt 'version.txt'
|
||||
$doda = (ReadTxt 'doda.txt').ToLower()
|
||||
$pgRaw = ReadTxt 'partgroup.txt'
|
||||
|
||||
if (-not $cmmid) { Log "no cmmid.txt (manual CMM id, or not a bay-config bay) - nothing to restore. Skipping."; exit 0 }
|
||||
if ($doda -eq 'yes') { Log "DODA bay ($cmmid) - skipping settings restore by policy."; exit 0 }
|
||||
|
||||
$bdir = Join-Path $BackupRoot $cmmid
|
||||
if (-not (Test-Path -LiteralPath $bdir)) { Log "no staged backup at $bdir - skipping (stage it with sync-cmm-backups.sh)."; exit 0 }
|
||||
Log "bay=$cmmid version=$ver doda=$doda backupDir=$bdir"
|
||||
|
||||
# --- PC-DMIS: restore ONLY the config-version zip ---
|
||||
# A bay's folder holds every version it ever had (e.g. 2016.0 + 2019 R2). Match
|
||||
# the VERSION FIELD of the name, not a loose substring: filenames are
|
||||
# pcdmis_backup_<PC>_<VER>_<YYYYMMDD-HHMMSS>.zip
|
||||
# A loose "*2026*" would wrongly match a 2019 zip whose TIMESTAMP starts 2026
|
||||
# (e.g. 20260612). Anchor on the trailing timestamp so only the real version
|
||||
# field (2019 -> '2019 R2', 2016 -> '2016.0', 2026 -> '2026.1') matches.
|
||||
$pcZip = $null
|
||||
if ($ver) {
|
||||
$verRx = '^pcdmis_backup_.+_' + [regex]::Escape($ver) + '[^_]*_\d{8}-\d{6}\.zip$'
|
||||
$pcZip = Get-ChildItem -LiteralPath $bdir -Filter 'pcdmis_backup_*.zip' -File -EA 0 |
|
||||
Where-Object { $_.Name -match $verRx } | Sort-Object LastWriteTime | Select-Object -Last 1
|
||||
}
|
||||
$pcScript = Join-Path $here 'Install-PCDMISSettings.ps1'
|
||||
if (-not $pcZip) {
|
||||
Log "WARN: no PC-DMIS backup zip matching version '$ver' in $bdir - PC-DMIS settings NOT restored."
|
||||
} elseif (-not (Test-Path -LiteralPath $pcScript)) {
|
||||
Log "WARN: Install-PCDMISSettings.ps1 not found at $pcScript - PC-DMIS settings NOT restored."
|
||||
} else {
|
||||
Log "restoring PC-DMIS $ver from $($pcZip.Name) (TargetUser=$TargetUser)"
|
||||
try { & $pcScript -BackupPath $pcZip.FullName -TargetUser $TargetUser *>&1 | ForEach-Object { Log " $_" } }
|
||||
catch { Log " ERROR in Install-PCDMISSettings: $($_.Exception.Message)" }
|
||||
}
|
||||
|
||||
# --- goCMM: restore the bay's settings; force the authoritative part group ---
|
||||
$goZip = Get-ChildItem -LiteralPath $bdir -Filter 'gocmm_backup_*.zip' -File -EA 0 | Sort-Object LastWriteTime | Select-Object -Last 1
|
||||
$goScript = Join-Path $here 'Install-goCMMSettings.ps1'
|
||||
if (-not $goZip) {
|
||||
Log "WARN: no goCMM backup zip in $bdir - goCMM settings NOT restored."
|
||||
} elseif (-not (Test-Path -LiteralPath $goScript)) {
|
||||
Log "WARN: Install-goCMMSettings.ps1 not found at $goScript - goCMM settings NOT restored."
|
||||
} else {
|
||||
# partgroup.txt is the friendly S:\... form; convert the S: prefix to the UNC
|
||||
# share root the same way 09-Setup-CMM does, and pass it so the restored
|
||||
# Selected Part Group matches the CURRENT bay-config even if the backup is stale.
|
||||
$goArgs = @{ BackupPath = $goZip.FullName }
|
||||
if ($pgRaw) {
|
||||
$pg = $pgRaw -replace '(?i)^S:\\', "$PartGroupShareRoot\"
|
||||
$goArgs.SelectedPartGroup = $pg
|
||||
Log "restoring goCMM from $($goZip.Name) (SelectedPartGroup=$pg)"
|
||||
} else {
|
||||
Log "restoring goCMM from $($goZip.Name) (no partgroup override - using backup's own value)"
|
||||
}
|
||||
try { & $goScript @goArgs *>&1 | ForEach-Object { Log " $_" } }
|
||||
catch { Log " ERROR in Install-goCMMSettings: $($_.Exception.Message)" }
|
||||
}
|
||||
|
||||
Log "==== restore complete for $cmmid ===="
|
||||
exit 0
|
||||
@@ -181,8 +181,8 @@ REM --- PPKG configuration (constructed at menu time, see docs) ---
|
||||
REM Vendor ships one source PPKG; we construct the BPRT-tagged filename
|
||||
REM by filling in Office, Region, Expiry, Version on the target copy.
|
||||
REM Update SOURCE_PPKG + PPKG_VER when a new PPKG is released.
|
||||
set SOURCE_PPKG=GCCH_Prod_SFLD_v4.14.ppkg
|
||||
set PPKG_VER=v4.14
|
||||
set SOURCE_PPKG=GCCH_Prod_SFLD_v4.16.ppkg
|
||||
set PPKG_VER=v4.16
|
||||
set PPKG_EXP=20260831
|
||||
set REGION=US
|
||||
|
||||
@@ -524,13 +524,24 @@ REM unified GE-Enforce dispatcher takes over from the share for ongoing updates.
|
||||
if /i not "%PCTYPE%"=="gea-shopfloor-cmm" goto skip_cmm_stage
|
||||
if exist "Y:\installers-post\cmm\cmm-manifest.json" (
|
||||
mkdir W:\CMM-Install 2>NUL
|
||||
robocopy "Y:\installers-post\cmm" "W:\CMM-Install" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
||||
REM /XD the backups tree: it holds EVERY bay's settings backup (some 240 MB
|
||||
REM each). Copying all of it to every imaged CMM would waste GBs. The bulk
|
||||
REM copy excludes it; the selected bay's backup is staged separately below.
|
||||
robocopy "Y:\installers-post\cmm" "W:\CMM-Install" /E /XD "Y:\installers-post\cmm\backups" /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
||||
if errorlevel 8 echo WARNING: cmm robocopy exit %ERRORLEVEL%
|
||||
echo Staged CMM bootstrap to W:\CMM-Install.
|
||||
echo [%TIME%] Staged CMM bootstrap >> "%STAGELOG%"
|
||||
) else (
|
||||
echo WARNING: Y:\cmm-installers not found - CMM PC cannot install Hexagon apps at imaging time.
|
||||
)
|
||||
REM Stage ONLY the selected bay's settings backup. 09-Setup-CMM's Restore-CMM
|
||||
REM reads W:\CMM-Install\backups\%CMMID%\ to restore PC-DMIS + goCMM settings.
|
||||
if not defined CMMID goto skip_cmm_stage
|
||||
if exist "Y:\installers-post\cmm\backups\%CMMID%" (
|
||||
robocopy "Y:\installers-post\cmm\backups\%CMMID%" "W:\CMM-Install\backups\%CMMID%" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
||||
echo Staged %CMMID% settings backup for restore.
|
||||
echo [%TIME%] Staged %CMMID% backup >> "%STAGELOG%"
|
||||
)
|
||||
:skip_cmm_stage
|
||||
|
||||
REM --- Stage Keyence per-model bootstrap bundle (Keyence PCs only) ---
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#
|
||||
# Source layout - one folder per CMM, named by the cmm_id in cmm-bay-config.csv,
|
||||
# produced by Backup-CMM.ps1 and mirrored here from the live bays:
|
||||
# /home/camp/pxe-images/cmm-bk/<cmm_id>/
|
||||
# /home/camp/pxe-images/cmm/backups/<cmm_id>/
|
||||
# gocmm_backup_<PC>_<ts>.zip
|
||||
# pcdmis_backup_<PC>_<ver>_<ts>.zip (one per installed PC-DMIS version)
|
||||
# cmm-backup-index.json
|
||||
@@ -23,7 +23,7 @@ set -euo pipefail
|
||||
PXE_HOST="${PXE_HOST:-172.16.9.1}"
|
||||
PXE_USER="${PXE_USER:-pxe}"
|
||||
PXE_PASS="${PXE_PASS:-pxe}"
|
||||
BACKUP_SRC_DIR="${CMM_BACKUP_DIR:-/home/camp/pxe-images/cmm-bk}"
|
||||
BACKUP_SRC_DIR="${CMM_BACKUP_DIR:-/home/camp/pxe-images/cmm/backups}"
|
||||
REMOTE_BASE="/srv/samba/enrollment/installers-post/cmm/backups"
|
||||
ONLY_ID="${CMM_ID:-}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user