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>
155 lines
7.7 KiB
PowerShell
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
|