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>
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
<#
|
||||
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
|
||||
Reference in New Issue
Block a user