Files
pxe-server/playbook/shopfloor-setup/gea-shopfloor-cmm/scripts/Install-goCMMSettings.ps1
cproudlock bfe17fe123 CMM: add goCMM settings backup/restore + debug scripts
goCMM settings live in two places: 3 pointer values at
HKLM\SOFTWARE\WOW6432Node\General Electric\goCMM, and the real content of all
7 Settings tabs (PC-DMIS, Quindos, Modus, Machine Definition, User Input,
Notifications, Part Groups) in C:\geaofi\ApplicationSettings.xml. Capture-replay
pair, mirroring the Wax/Trace Backup/Install scripts:

- Backup-goCMMSettings.ps1/.bat: on a live legacy bay (admin), zips the registry
  key + the C:\geaofi tree (minus transient LocalProgramCopies/logs) to
  gocmm_backup_<PC>_<ts>.zip.
- Install-goCMMSettings.ps1/.bat: restore at imaging (admin). Imports the key +
  lays down C:\geaofi, then grants BUILTIN\Users WriteKey on the reg key and
  Modify on C:\geaofi - goCMM's RegistrySettings.GetRegistryString opens the key
  with writable:true even to READ, so a locked-down operator throws a
  SecurityException without the grant (the post-lockdown 'registry access not
  allowed' error). Applies a built-in legacy->new FQDN rewrite
  (rd.ds.ge.com -> wjs.geaerospace.net) automatically across the registry values
  and ApplicationSettings.xml (incl PartGroup FullName); -NoDefaultRewrite skips
  it, /replace adds an extra pair, -SelectedPartGroup overrides per bay.
- gocmm-debug.ps1/.bat: run as the operator to reproduce the SecurityException
  and dump the goCMM key ACL (confirms whether lockdown stripped the grant).

All round-trip + FQDN-rewrite verified on the win11 VM. NOTE: covers goCMM only;
PC-DMIS probe calibrations / custom tip angles / machine comp are owned by
PC-DMIS (Hexagon) and not captured here. Not yet wired into 09-Setup-CMM
auto-discovery.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 08:27:30 -04:00

173 lines
8.0 KiB
PowerShell

<#
Install-goCMMSettings.ps1
Restore a goCMM bay's settings from a zip produced by Backup-goCMMSettings.ps1.
Mirrors Install-FormtracepakSettings.ps1.
Lays back both halves:
1. Registry pointers -> HKLM\SOFTWARE\WOW6432Node\General Electric\goCMM
2. Shared Data Directory (C:\geaofi\, incl ApplicationSettings.xml = all 7
Settings tabs: PC-DMIS, Quindos, Modus, Machine Definition, User Input,
Notifications, Part Groups).
Then grants the access goCMM needs so it works under lockdown:
- BUILTIN\Users ReadKey+WriteKey on the goCMM reg key. goCMM's
RegistrySettings.GetRegistryString opens that key with writable:true even
to READ, so a read-only operator hits a SecurityException without this.
- BUILTIN\Users Modify on the Shared Data Directory (goCMM writes
ApplicationSettings.xml back there when settings are saved).
Run as administrator / SYSTEM (imaging context). If the lockdown pass strips
the registry ACE, re-run this (or just its ACL section) AFTER lockdown.
NOTE: this restores goCMM only. PC-DMIS probe calibrations / custom tip angles /
machine comp are owned by PC-DMIS (Hexagon) and are NOT in this backup.
#>
param(
[Parameter(Mandatory=$true)][string]$BackupPath, # zip or already-extracted dir
[string]$SelectedPartGroup, # optional per-bay override of the part-group UNC
[string]$ReplaceFrom, # optional EXTRA find/replace across reg + xml
[string]$ReplaceTo, # ... replacement. Case-insensitive.
[switch]$NoDefaultRewrite # skip the built-in legacy->new FQDN swaps below
)
# ============================================================================
# Built-in FQDN migration - applied AUTOMATICALLY on every restore (no flag).
# Add pairs here as more legacy domains retire. -NoDefaultRewrite disables them.
# ============================================================================
$DefaultRewrites = @(
@{ From = 'rd.ds.ge.com'; To = 'wjs.geaerospace.net' } # WJ legacy domain -> new domain
)
$ErrorActionPreference = 'Continue'
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
$logDir = 'C:\Logs\CMM'
New-Item -ItemType Directory -Path $logDir -Force -ErrorAction SilentlyContinue | Out-Null
$log = Join-Path $logDir "gocmm-restore-$ts.log"
function Log($m){ Write-Host $m; $m | Out-File -FilePath $log -Append }
$goCmmKey = 'HKLM:\SOFTWARE\WOW6432Node\General Electric\goCMM'
Log "==== goCMM restore on $env:COMPUTERNAME from $BackupPath ===="
# --- Resolve the backup to a directory ---
$src = $BackupPath
$extracted = $false
if ($BackupPath -match '\.zip$') {
$src = Join-Path $env:TEMP "gocmm-rs-$ts"
Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::ExtractToDirectory($BackupPath, $src)
$extracted = $true
}
if (-not (Test-Path $src)) { Log "ERROR: backup path not found: $src"; exit 1 }
# --- Read manifest for the shared-dir target ---
$sharedDir = 'C:\geaofi'
$mani = Join-Path $src 'manifest.json'
if (Test-Path $mani) {
try {
$m = Get-Content $mani -Raw | ConvertFrom-Json
if ($m.SharedDataDirectory) { $sharedDir = $m.SharedDataDirectory }
Log "manifest: shared=$sharedDir partGroup=$($m.SelectedPartGroup) ver=$($m.goCMMVersion)"
} catch { Log "WARN: could not parse manifest.json: $($_.Exception.Message)" }
}
# --- Import the registry pointers ---
$reg = Join-Path $src 'registry\goCMM.reg'
if (Test-Path $reg) {
reg import "$reg" 2>&1 | Out-Null
Log "Imported registry key from goCMM.reg"
} else {
Log "WARN: registry\goCMM.reg missing in backup - creating an empty key so the ACL still lands"
if (-not (Test-Path $goCmmKey)) { New-Item -Path $goCmmKey -Force | Out-Null }
}
# --- Optional per-bay Selected Part Group override (use when restoring to a different bay) ---
if ($SelectedPartGroup) {
if (-not (Test-Path $goCmmKey)) { New-Item -Path $goCmmKey -Force | Out-Null }
New-ItemProperty -Path $goCmmKey -Name 'Selected Part Group' -Value $SelectedPartGroup -PropertyType String -Force | Out-Null
Log "Override Selected Part Group = $SelectedPartGroup"
}
# --- Lay down the Shared Data Directory (ApplicationSettings.xml = all tabs) ---
$geaofiSrc = Join-Path $src 'geaofi'
if (Test-Path $geaofiSrc) {
New-Item -ItemType Directory -Path $sharedDir -Force -ErrorAction SilentlyContinue | Out-Null
robocopy $geaofiSrc $sharedDir /E /R:1 /W:1 /NFL /NDL /NJH /NJS | Out-Null
Log "Restored Shared Data Directory -> $sharedDir"
if (Test-Path (Join-Path $sharedDir 'ApplicationSettings.xml')) {
Log "ApplicationSettings.xml in place (PC-DMIS + all Settings tabs)"
} else {
Log "WARN: ApplicationSettings.xml not present after restore"
}
} else {
Log "WARN: geaofi payload missing in backup - settings tabs NOT restored"
}
# --- Find/replace across ALL restored data (registry values + every text file
# under the Shared Data Directory). The built-in legacy->new FQDN swaps run
# AUTOMATICALLY; -ReplaceFrom/-ReplaceTo adds one more; case-insensitive. ---
$rewrites = @()
if (-not $NoDefaultRewrite) { $rewrites += $DefaultRewrites }
if ($ReplaceFrom -and $ReplaceTo) { $rewrites += @{ From = $ReplaceFrom; To = $ReplaceTo } }
if ($rewrites.Count -gt 0) {
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
foreach ($rw in $rewrites) {
$from = $rw.From; $to = $rw.To
if (-not $from) { continue }
Log "Find/replace: '$from' -> '$to' (case-insensitive)"
$rxFrom = [regex]::Escape($from)
# registry: every string value under the goCMM key
if (Test-Path $goCmmKey) {
try {
$props = Get-ItemProperty -Path $goCmmKey
foreach ($p in $props.PSObject.Properties) {
if ($p.Name -like 'PS*') { continue }
if (($p.Value -is [string]) -and ([regex]::IsMatch($p.Value, $rxFrom, 'IgnoreCase'))) {
$new = [regex]::Replace($p.Value, $rxFrom, $to, 'IgnoreCase')
Set-ItemProperty -Path $goCmmKey -Name $p.Name -Value $new
Log " reg [$($p.Name)] -> $new"
}
}
} catch { Log " WARN: registry rewrite failed: $($_.Exception.Message)" }
}
# files: every text file under the Shared Data Directory
if (Test-Path $sharedDir) {
Get-ChildItem -Path $sharedDir -Recurse -File -Include *.xml,*.txt,*.csv,*.config,*.ini -ErrorAction SilentlyContinue | ForEach-Object {
try {
$c = [System.IO.File]::ReadAllText($_.FullName)
if ([regex]::IsMatch($c, $rxFrom, 'IgnoreCase')) {
$nc = [regex]::Replace($c, $rxFrom, $to, 'IgnoreCase')
[System.IO.File]::WriteAllText($_.FullName, $nc, $utf8NoBom)
Log " file [$($_.Name)] rewritten"
}
} catch { Log " WARN: file rewrite $($_.FullName): $($_.Exception.Message)" }
}
}
}
}
# --- Grant BUILTIN\Users ReadKey+WriteKey on the reg key (goCMM opens it writable:true to read) ---
if (Test-Path $goCmmKey) {
try {
$acl = Get-Acl -Path $goCmmKey
$rule = New-Object System.Security.AccessControl.RegistryAccessRule(
'BUILTIN\Users','ReadKey,WriteKey','ContainerInherit','None','Allow')
$acl.AddAccessRule($rule)
Set-Acl -Path $goCmmKey -AclObject $acl -ErrorAction Stop
Log "Granted BUILTIN\Users ReadKey,WriteKey on $goCmmKey"
} catch { Log "WARN: registry ACL grant failed: $($_.Exception.Message)" }
}
# --- Grant BUILTIN\Users Modify on the Shared Data Directory (goCMM saves settings there) ---
if (Test-Path $sharedDir) {
& icacls $sharedDir /grant 'BUILTIN\Users:(OI)(CI)M' /T /C 2>&1 | Out-Null
Log "Granted BUILTIN\Users Modify on $sharedDir"
}
if ($extracted) { Remove-Item $src -Recurse -Force -ErrorAction SilentlyContinue }
Log "==== DONE ===="
Write-Host ""
Write-Host "goCMM restore complete. Log: $log" -ForegroundColor Green