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,115 @@
|
||||
# gocmm-debug.ps1 - diagnose goCMM "Requested registry access is not allowed" post-lockdown.
|
||||
#
|
||||
# RUN AS THE OPERATOR (the locked-down shop-floor user), NOT elevated / not "Run as administrator".
|
||||
# Elevation would falsely succeed (admins have write) and hide the bug.
|
||||
#
|
||||
# Root cause being tested: goCMM's GEA_OFI_Common.RegistrySettings.GetRegistryString opens
|
||||
# HKLM\Software\General Electric\goCMM with writable:TRUE even to READ a value. goCMM is
|
||||
# 32-bit, so that redirects to HKLM\SOFTWARE\WOW6432Node\General Electric\goCMM. If the
|
||||
# operator lacks WRITE on that key (lockdown stripped the BUILTIN\Users grant), the open throws.
|
||||
#
|
||||
# Output: C:\Logs\CMM\gocmm-debug-<PC>-<timestamp>.txt (pull this back for review)
|
||||
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$dir = 'C:\Logs\CMM'
|
||||
New-Item -ItemType Directory -Path $dir -Force -ErrorAction SilentlyContinue | Out-Null
|
||||
$log = Join-Path $dir "gocmm-debug-$env:COMPUTERNAME-$ts.txt"
|
||||
function W($m){ $m | Tee-Object -FilePath $log -Append }
|
||||
|
||||
$key32native = 'SOFTWARE\General Electric\goCMM' # path under the 32-bit (Registry32) base
|
||||
$keyWow = 'HKLM:\SOFTWARE\WOW6432Node\General Electric\goCMM'
|
||||
|
||||
W "================ goCMM debug ================"
|
||||
W "When : $(Get-Date)"
|
||||
W "PC : $env:COMPUTERNAME"
|
||||
W "User : $env:USERDOMAIN\$env:USERNAME"
|
||||
W "PS : $($PSVersionTable.PSVersion) (process is $([IntPtr]::Size*8)-bit)"
|
||||
W "Elevated: $((New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))"
|
||||
W ""
|
||||
|
||||
W "================ whoami /all (identity + groups + privileges) ================"
|
||||
(whoami /all 2>&1 | Out-String) | W
|
||||
W ""
|
||||
|
||||
W "================ goCMM key values (32-bit view, read-only open) ================"
|
||||
try {
|
||||
$base32 = [Microsoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine','Registry32')
|
||||
$kr = $base32.OpenSubKey($key32native, $false)
|
||||
if ($kr) {
|
||||
foreach ($n in $kr.GetValueNames()) { W (" {0} = {1}" -f $n, $kr.GetValue($n)) }
|
||||
$kr.Close()
|
||||
} else { W " (key NOT found in 32-bit view)" }
|
||||
} catch { W " ERROR reading values: $($_.Exception.Message)" }
|
||||
W ""
|
||||
|
||||
W "================ PROBE 1: mimic goCMM GetRegistryString -> OpenSubKey(writable:TRUE), 32-bit view ================"
|
||||
W "(this is the exact call that throws in the app)"
|
||||
try {
|
||||
$base32 = [Microsoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine','Registry32')
|
||||
$kw = $base32.OpenSubKey($key32native, $true)
|
||||
if ($kw) { W " RESULT: SUCCESS - opened goCMM key WRITABLE. (operator HAS write; settings should work)"; $kw.Close() }
|
||||
else { W " RESULT: NULL - key missing; app would attempt CreateSubKey (also needs write)" }
|
||||
} catch [System.Security.SecurityException] {
|
||||
W " RESULT: *** REPRODUCED *** SecurityException: $($_.Exception.Message)"
|
||||
W " -> operator lacks WRITE on the goCMM key. Lockdown stripped the BUILTIN\Users grant, or a Deny applies."
|
||||
} catch {
|
||||
W " RESULT: OTHER $($_.Exception.GetType().FullName): $($_.Exception.Message)"
|
||||
}
|
||||
W ""
|
||||
|
||||
W "================ PROBE 2: read-only open (writable:FALSE) - does the operator at least READ? ================"
|
||||
try {
|
||||
$base32 = [Microsoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine','Registry32')
|
||||
$kr2 = $base32.OpenSubKey($key32native, $false)
|
||||
if ($kr2) { W " read-only open OK (read works; only WRITE-open is denied -> confirms the writable:true bug)"; $kr2.Close() }
|
||||
else { W " read-only open returned NULL (key missing)" }
|
||||
} catch { W " read-only open FAILED: $($_.Exception.Message)" }
|
||||
W ""
|
||||
|
||||
W "================ ACL on goCMM key (the smoking gun) ================"
|
||||
try {
|
||||
$acl = Get-Acl -Path $keyWow
|
||||
W (" Owner : " + $acl.Owner)
|
||||
W (" SDDL : " + $acl.Sddl)
|
||||
W " Access rules:"
|
||||
$acl.Access | ForEach-Object {
|
||||
W (" {0,-30} {1,-22} {2,-6} Inherited={3}" -f $_.IdentityReference, $_.RegistryRights, $_.AccessControlType, $_.IsInherited)
|
||||
}
|
||||
$usersWrite = $acl.Access | Where-Object {
|
||||
$_.AccessControlType -eq 'Allow' -and
|
||||
"$($_.IdentityReference)" -match 'Users' -and
|
||||
("$($_.RegistryRights)" -match 'WriteKey|SetValue|FullControl')
|
||||
}
|
||||
if ($usersWrite) { W " >> BUILTIN\Users WRITE ACE present (grant survived). Failure is elsewhere - check for a Deny ACE or wrong view." }
|
||||
else { W " >> NO BUILTIN\Users WRITE ACE. Confirms lockdown removed the grant. <<" }
|
||||
} catch { W " Get-Acl failed: $($_.Exception.Message)" }
|
||||
W ""
|
||||
|
||||
W "================ raw reg export of the key (for record) ================"
|
||||
$regOut = Join-Path $dir "gocmm-key-$env:COMPUTERNAME-$ts.reg"
|
||||
reg export "HKLM\SOFTWARE\WOW6432Node\General Electric\goCMM" "$regOut" /y 2>&1 | Out-String | W
|
||||
W " exported -> $regOut"
|
||||
W ""
|
||||
|
||||
W "================ goCMM version + install ================"
|
||||
foreach ($p in @(
|
||||
'C:\Program Files (x86)\General Electric\goCMM\GEAOperatorFriendlyInterface.exe',
|
||||
'C:\Program Files (x86)\General Electric\goCMM\GEA_OFI_Common.dll')) {
|
||||
if (Test-Path $p) { $vi = (Get-Item $p).VersionInfo; W (" {0} FileVer={1} ProductVer={2}" -f (Split-Path $p -Leaf), $vi.FileVersion, $vi.ProductVersion) }
|
||||
else { W " MISSING: $p" }
|
||||
}
|
||||
W ""
|
||||
|
||||
W "================ UAC / registry virtualization ================"
|
||||
(reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /v EnableLUA 2>&1 | Out-String) | W
|
||||
(reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /v EnableVirtualization 2>&1 | Out-String) | W
|
||||
W ""
|
||||
|
||||
W "================ DONE ================"
|
||||
W "Log : $log"
|
||||
W "Reg : $regOut"
|
||||
Write-Host ""
|
||||
Write-Host "Done. Collected:" -ForegroundColor Green
|
||||
Write-Host " $log"
|
||||
Write-Host " $regOut"
|
||||
Reference in New Issue
Block a user