CMM: seed goCMM Shared Data Directory per bay + grant Users write

goCMM (.NET x86) stores its program-source path in HKLM\SOFTWARE\
WOW6432Node\General Electric\goCMM value 'Shared Data Directory'. Being
HKLM, a non-admin shopfloor user cannot set it via goCMM's UI (nor save a
Selected Part Group switch). 09-Setup-CMM Step 2.7 now seeds the per-bay
path (admin context at imaging) and grants BUILTIN\Users write on the key,
mirroring the existing Step 2.5 install-dir ACL grant.

- cmm-bay-config.csv: add shared_data_dir column (per-bay paths, CMM1-12).
- resolve-cmm-bay-config.ps1: write C:\Enrollment\cmm\shareddatadir.txt
  (space-safe; e.g. CMM8 'Venture CMM8').
- 09-Setup-CMM.ps1: Step 2.7 reg seed + Users ACL on the goCMM key.

Not yet deployed to the live server (held).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-06-01 10:59:55 -04:00
parent 59b1a9fb65
commit f6d970c08d
3 changed files with 89 additions and 16 deletions

View File

@@ -237,6 +237,69 @@ foreach ($exe in $pcdmisExes) {
} }
} }
# ============================================================================
# Step 2.7: Seed goCMM Shared Data Directory + grant Users write on the key
# ============================================================================
# goCMM (.NET x86 WPF app) stores its program-source path in the registry at
# HKLM\SOFTWARE\WOW6432Node\General Electric\goCMM, value "Shared Data
# Directory" (the folder it browses for *.prg PC-DMIS measurement routines).
# It is a 32-bit MSI / 32-bit process, so both the install seed and runtime
# reads land in the WOW6432Node view. Because the value lives in HKLM, a
# non-admin shopfloor user cannot set it via goCMM's settings UI - and cannot
# save a "Selected Part Group" switch either (same key). So we do two things
# here in admin context:
# 1. Seed "Shared Data Directory" to the per-bay path resolved by
# resolve-cmm-bay-config.ps1 (C:\Enrollment\cmm\shareddatadir.txt).
# 2. Grant BUILTIN\Users write on the key so runtime writes (part-group
# switching, or a deliberate path change) succeed without elevation.
# This mirrors Step 2.5, which grants Users Modify on the install dirs.
$goCmmKey = 'HKLM:\SOFTWARE\WOW6432Node\General Electric\goCMM'
# Path may contain internal spaces (e.g. CMM8 "Venture CMM8"). Get-Content
# + Trim keeps internal spaces; the value is passed as a single -Value arg,
# never through a command line, so the space cannot split the path.
$sharedDataDir = ''
$sddFile = 'C:\Enrollment\cmm\shareddatadir.txt'
if (Test-Path -LiteralPath $sddFile) {
$sharedDataDir = (Get-Content -LiteralPath $sddFile -First 1 -EA 0).Trim()
}
if (-not (Test-Path $goCmmKey)) {
Write-CMMLog "goCMM key absent ($goCmmKey) - goCMM not installed or install failed; creating key so the seed/ACL still land" 'WARN'
try { New-Item -Path $goCmmKey -Force | Out-Null } catch { Write-CMMLog "Could not create $goCmmKey : $_" 'WARN' }
}
if ($sharedDataDir) {
try {
New-ItemProperty -Path $goCmmKey -Name 'Shared Data Directory' -Value $sharedDataDir -PropertyType String -Force | Out-Null
Write-CMMLog "Set goCMM 'Shared Data Directory' = $sharedDataDir"
} catch {
Write-CMMLog "Failed to set goCMM 'Shared Data Directory': $_" 'WARN'
}
} else {
Write-CMMLog "No shareddatadir.txt (bay not in bay-config, or manual CMM ID) - leaving goCMM path unset" 'WARN'
}
# Grant BUILTIN\Users ReadKey+WriteKey (WriteKey = SetValue + CreateSubKey).
# Registry ACEs use ContainerInherit only (no leaf objects in the registry).
if (Test-Path $goCmmKey) {
try {
$racl = Get-Acl -Path $goCmmKey
$rrule = New-Object System.Security.AccessControl.RegistryAccessRule(
'BUILTIN\Users',
'ReadKey,WriteKey',
'ContainerInherit',
'None',
'Allow'
)
$racl.AddAccessRule($rrule)
Set-Acl -Path $goCmmKey -AclObject $racl -ErrorAction Stop
Write-CMMLog "Granted BUILTIN\Users write on $goCmmKey"
} catch {
Write-CMMLog "Failed to set ACL on $goCmmKey : $_" 'WARN'
}
}
# ============================================================================ # ============================================================================
# Step 3: Conditional cleanup of the bootstrap staging dir # Step 3: Conditional cleanup of the bootstrap staging dir
# ============================================================================ # ============================================================================

View File

@@ -1,13 +1,13 @@
cmm_id,pcdmis_version,doda cmm_id,pcdmis_version,doda,shared_data_dir
CMM1,2019,no CMM1,2019,no,S:\CMM\CMM1\HPTCMM1
CMM2,2019,no CMM2,2019,no,S:\CMM\CMM2\HPT
CMM3,2019,no CMM3,2019,no,S:\CMM\CMM3\VENTURE_CMM3
CMM4,2016,no CMM4,2016,no,S:\CMM\CMM4\Spool
CMM5,2019,no CMM5,2019,no,S:\CMM\CMM5\BLISKCMM5
CMM6,2019,no CMM6,2019,no,S:\CMM\CMM6\BLISKCMM6
CMM7,2019,no CMM7,2019,no,S:\CMM\CMM7\VENTURE_CMM7
CMM8,2019,no CMM8,2019,no,S:\CMM\CMM8\Venture CMM8
CMM9,2019,no CMM9,2019,no,S:\CMM\CMM9\BLISKCMM9
CMM10,2016,no CMM10,2016,no,S:\CMM\CMM10\Spool
CMM11,2026,no CMM11,2026,no,S:\CMM\CMM11\Spool
CMM12,2026,no CMM12,2026,no,S:\CMM\CMM12\Spool
1 cmm_id pcdmis_version doda shared_data_dir
2 CMM1 2019 no S:\CMM\CMM1\HPTCMM1
3 CMM2 2019 no S:\CMM\CMM2\HPT
4 CMM3 2019 no S:\CMM\CMM3\VENTURE_CMM3
5 CMM4 2016 no S:\CMM\CMM4\Spool
6 CMM5 2019 no S:\CMM\CMM5\BLISKCMM5
7 CMM6 2019 no S:\CMM\CMM6\BLISKCMM6
8 CMM7 2019 no S:\CMM\CMM7\VENTURE_CMM7
9 CMM8 2019 no S:\CMM\CMM8\Venture CMM8
10 CMM9 2019 no S:\CMM\CMM9\BLISKCMM9
11 CMM10 2016 no S:\CMM\CMM10\Spool
12 CMM11 2026 no S:\CMM\CMM11\Spool
13 CMM12 2026 no S:\CMM\CMM12\Spool

View File

@@ -40,11 +40,21 @@ if (-not (Test-Path $OutDir)) {
$version = $match.pcdmis_version.Trim() $version = $match.pcdmis_version.Trim()
$doda = $match.doda.Trim().ToLower() $doda = $match.doda.Trim().ToLower()
# shared_data_dir may legitimately contain spaces (e.g. CMM8 "Venture CMM8").
# Trim() strips only leading/trailing whitespace, never internal spaces.
$sharedDataDir = ''
if ($match.PSObject.Properties['shared_data_dir'] -and $match.shared_data_dir) {
$sharedDataDir = $match.shared_data_dir.Trim()
}
[System.IO.File]::WriteAllText((Join-Path $OutDir 'version.txt'), $version) [System.IO.File]::WriteAllText((Join-Path $OutDir 'version.txt'), $version)
[System.IO.File]::WriteAllText((Join-Path $OutDir 'doda.txt'), $doda) [System.IO.File]::WriteAllText((Join-Path $OutDir 'doda.txt'), $doda)
if ($sharedDataDir) {
[System.IO.File]::WriteAllText((Join-Path $OutDir 'shareddatadir.txt'), $sharedDataDir)
}
Write-Host "Resolved $CmmId -> PC-DMIS $version, DODA=$doda" Write-Host "Resolved $CmmId -> PC-DMIS $version, DODA=$doda, SharedDataDir=$(if ($sharedDataDir) { $sharedDataDir } else { '(none)' })"
Write-Host " version.txt -> $OutDir\version.txt" Write-Host " version.txt -> $OutDir\version.txt"
Write-Host " doda.txt -> $OutDir\doda.txt" Write-Host " doda.txt -> $OutDir\doda.txt"
if ($sharedDataDir) { Write-Host " shareddatadir.txt -> $OutDir\shareddatadir.txt" }
exit 0 exit 0