Files
pxe-server/playbook/shopfloor-setup/gea-shopfloor-cmm/scripts/pcdmis-probe-debug.ps1
cproudlock 1d65103cc0 CMM: add PC-DMIS + combined CMM backup/restore + diagnostic scripts
Adds the PC-DMIS settings/probe backup-restore set alongside the existing
goCMM scripts, plus a single combined CMM backup and the diagnostics built
while debugging the live bays:

- Backup-PCDMISSettings / Install-PCDMISSettings: capture+restore PC-DMIS
  registry + data/probe/cal files per installed version (2016/2019/2026).
  Hardened from real-bay failures: detect install dir via Program Files
  fallback; capture compens.dat (not just comp.dat) + interfac.dll; identify
  the controller by hash-matching interfac.dll to its source DLL AND reading
  the PE OriginalFilename (covers rename-without-copy); EXCLUDE the whole
  Homepage state (Recent/Favorites/DetailsView) which null-refs PC-DMIS on
  launch via stale routine paths; restore routes HKCU into the target user's
  hive (-TargetUser ShopFloor), fails loud on a non-backup path, and applies
  the legacy->new FQDN rewrite across reg + data files incl .bas.
- Backup-CMM: one wrapper running goCMM + PC-DMIS (all versions) into one
  per-CMM folder + index, for staging on PXE and restore-by-machine-number.
- Clear-PCDMISRecent: fixes the Homepage recent-list NullReferenceException
  crash on an already-broken bay.
- pcdmis-probe-debug / Export-PCDMISCrashEvents: diagnostics for the
  custom-probe-not-showing and crash investigations.
- Modify-PCDMISRights / Grant-FullControl: grant the operator the registry +
  filesystem access PC-DMIS needs under lockdown.
- Install-goCMMSettings: add .bas to the FQDN-rewrite include list.

Not yet wired into 09-Setup-CMM auto-restore - staging + the gated restore
block come next.

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

155 lines
7.7 KiB
PowerShell

<#
pcdmis-probe-debug.ps1
Diagnose "custom probes don't show in PC-DMIS" on a locked-down Win11 bay.
RUN AS THE OPERATOR (the account that actually launches PC-DMIS), NOT elevated -
the probe search path is a PER-USER registry setting and the UAC VirtualStore is
per-user, so we must see THAT account's view. (Machine-wide ProgramData + ACLs
are read regardless.)
What it reports:
1. Installed PC-DMIS version(s) + install dir (HKLM)
2. The configured Probe Directory / search path (this user's HKCU + every
loaded user hive) - where PC-DMIS is actually looking
3. Probe files (*.prb, probe.dat, usrprobe.dat, probebuilder.dat) found under
ProgramData, Public Documents, and the install dir
4. ACL on C:\ProgramData\Hexagon\PC-DMIS\<ver> - can the operator WRITE
(needed to save/qualify custom probes)?
5. UAC VirtualStore shadow of those paths (probes silently redirected)
6. Version-folder match (probes in a subfolder the running build ignores)
Output: C:\Logs\CMM\pcdmis-probe-debug-<PC>-<timestamp>.txt
#>
$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 "pcdmis-probe-debug-$env:COMPUTERNAME-$ts.txt"
function W($m){ $m | Tee-Object -FilePath $log -Append }
W "================ PC-DMIS probe debug ================"
W "When : $(Get-Date)"
W "PC : $env:COMPUTERNAME"
W "User : $env:USERDOMAIN\$env:USERNAME (process $([IntPtr]::Size*8)-bit)"
$elev = (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
W "Elevated: $elev (run as the OPERATOR, not elevated, for the per-user view)"
W ""
# ---- 1. Installed PC-DMIS version(s) + install dir ----
W "================ 1. Installed PC-DMIS (HKLM) ================"
$instVers = @()
foreach ($root in 'HKLM:\SOFTWARE\WOW6432Node\Hexagon\PC-DMIS','HKLM:\SOFTWARE\WOW6432Node\Wai\PC-DMIS','HKLM:\SOFTWARE\Hexagon\PC-DMIS','HKLM:\SOFTWARE\Wai\PC-DMIS') {
if (Test-Path $root) {
Get-ChildItem $root -ErrorAction SilentlyContinue | ForEach-Object {
$v = $_.PSChildName; $instVers += $v
$p = (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue)
$exe = $p.Directory; if (-not $exe) { $exe = $p.InstallDir }
W (" $root\$v InstallDir=$exe")
}
}
}
$instVers = $instVers | Sort-Object -Unique
foreach ($d in 'C:\Program Files\Hexagon','C:\Program Files (x86)\Hexagon','C:\Program Files\WAI','C:\Program Files (x86)\WAI') {
if (Test-Path $d) { Get-ChildItem $d -Filter 'PC-DMIS*' -Directory -EA SilentlyContinue | ForEach-Object {
$exe = Get-ChildItem $_.FullName -Filter 'Pcdlrn.exe' -Recurse -EA SilentlyContinue | Select-Object -First 1
if (-not $exe) { $exe = Get-ChildItem $_.FullName -Filter 'PCDMIS.exe' -Recurse -EA SilentlyContinue | Select-Object -First 1 }
if ($exe) { W (" exe: $($exe.FullName) v$((Get-Item $exe.FullName).VersionInfo.FileVersion)") }
}}
}
if (-not $instVers) { W " (no PC-DMIS install keys found under Hexagon/Wai)" }
W ""
# ---- 2. Probe search path in the registry (this user + all loaded hives) ----
W "================ 2. Probe / search-path registry (per user) ================"
W "(values whose name or data mentions probe/search/path/dir - that's where PC-DMIS looks)"
New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS -ErrorAction SilentlyContinue | Out-Null
$userRoots = @('HKCU:\Software\Hexagon\PC-DMIS','HKCU:\Software\Wai\PC-DMIS')
Get-ChildItem 'HKU:\' -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^S-1-5-21' -and $_.PSChildName -notmatch '_Classes$' } | ForEach-Object {
$sid = $_.PSChildName
$userRoots += "HKU:\$sid\Software\Hexagon\PC-DMIS"
$userRoots += "HKU:\$sid\Software\Wai\PC-DMIS"
}
foreach ($ur in ($userRoots | Sort-Object -Unique)) {
if (-not (Test-Path $ur)) { continue }
Get-ChildItem $ur -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
$k = $_
$props = Get-ItemProperty $k.PSPath -ErrorAction SilentlyContinue
if (-not $props) { return }
foreach ($p in $props.PSObject.Properties) {
if ($p.Name -like 'PS*') { continue }
if ($p.Name -match 'probe|search|path|dir' -or "$($p.Value)" -match 'probe|Hexagon\\PC-DMIS|\\\\') {
W (" $($k.PSPath -replace '.*::','')")
W (" [$($p.Name)] = $($p.Value)")
}
}
}
}
W ""
# ---- 3. Probe files on disk ----
W "================ 3. Probe files on disk ================"
$bases = @(
"$env:ProgramData\Hexagon\PC-DMIS",
"$env:ProgramData\WAI\PC-DMIS",
"$env:PUBLIC\Documents\Hexagon\PC-DMIS",
"$env:PUBLIC\Documents\WAI\PC-DMIS",
"$env:APPDATA\Hexagon\PC-DMIS", # Roaming per-user
"$env:LOCALAPPDATA\Hexagon\PC-DMIS", # Local per-user
"$env:APPDATA\WAI\PC-DMIS",
"$env:LOCALAPPDATA\WAI\PC-DMIS",
"$env:USERPROFILE\Documents\Hexagon\PC-DMIS"
)
foreach ($d in 'C:\Program Files\Hexagon','C:\Program Files (x86)\Hexagon') { if (Test-Path $d) { $bases += (Get-ChildItem $d -Filter 'PC-DMIS*' -Directory -EA SilentlyContinue).FullName } }
foreach ($b in ($bases | Sort-Object -Unique)) {
if (-not (Test-Path $b)) { W " (absent) $b"; continue }
W " --- $b ---"
Get-ChildItem $b -Recurse -File -Include *.prb,probe.dat,usrprobe.dat,probebuilder.dat -ErrorAction SilentlyContinue |
ForEach-Object { W (" {0,10} {1:yyyy-MM-dd} {2}" -f $_.Length, $_.LastWriteTime, $_.FullName) }
}
W ""
# ---- 4. ACL on the ProgramData probe dir (can operator write?) ----
W "================ 4. ProgramData probe-dir ACL (write = save custom probes) ================"
$pdRoots = @("$env:ProgramData\Hexagon\PC-DMIS","$env:ProgramData\WAI\PC-DMIS")
foreach ($pr in $pdRoots) {
if (-not (Test-Path $pr)) { continue }
Get-ChildItem $pr -Directory -ErrorAction SilentlyContinue | ForEach-Object {
W " --- $($_.FullName) ---"
try {
(Get-Acl $_.FullName).Access | Where-Object { "$($_.IdentityReference)" -match 'Users|Everyone|Authenticated' } |
ForEach-Object { W (" {0,-30} {1,-24} {2}" -f $_.IdentityReference, $_.FileSystemRights, $_.AccessControlType) }
} catch { W " Get-Acl failed: $($_.Exception.Message)" }
}
}
W ""
# ---- 5. UAC VirtualStore shadow ----
W "================ 5. UAC VirtualStore shadow (probes silently redirected) ================"
$vs = "$env:LOCALAPPDATA\VirtualStore"
$found = $false
foreach ($sub in 'ProgramData\Hexagon\PC-DMIS','Program Files\Hexagon','Program Files (x86)\Hexagon','ProgramData\WAI\PC-DMIS') {
$p = Join-Path $vs $sub
if (Test-Path $p) {
$found = $true
Get-ChildItem $p -Recurse -File -Include *.prb,probe.dat,usrprobe.dat,probebuilder.dat -EA SilentlyContinue |
ForEach-Object { W (" SHADOW: $($_.FullName)") }
}
}
if (-not $found) { W " (no VirtualStore shadow for $env:USERNAME - good, or PC-DMIS runs under a different account)" }
W ""
# ---- 6. Version-folder match ----
W "================ 6. Version-folder match ================"
W (" installed versions: " + (($instVers -join ', ') | ForEach-Object { if($_){$_}else{'(unknown)'} }))
foreach ($b in "$env:ProgramData\Hexagon\PC-DMIS","$env:PUBLIC\Documents\Hexagon\PC-DMIS") {
if (Test-Path $b) { W (" data subfolders in $b : " + ((Get-ChildItem $b -Directory -EA SilentlyContinue).Name -join ', ')) }
}
W " >> if a data subfolder holding your .prb files does NOT match the running build's version, PC-DMIS ignores it."
W ""
W "================ DONE ================"
W "Log: $log"
Write-Host ""
Write-Host "Collected: $log" -ForegroundColor Green