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>
This commit is contained in:
@@ -0,0 +1,19 @@
|
|||||||
|
@echo off
|
||||||
|
REM Backup-CMM.bat - ONE backup for a whole CMM bay (goCMM + PC-DMIS, all versions).
|
||||||
|
REM
|
||||||
|
REM Run AS ADMINISTRATOR on the live CMM. Do NOT run on DODA bays.
|
||||||
|
REM
|
||||||
|
REM Backup-CMM.bat -CmmId CMM3 (names the folder by CMM #)
|
||||||
|
REM Backup-CMM.bat (uses the computer name)
|
||||||
|
REM
|
||||||
|
REM Output: C:\Logs\CMM\cmm-backup\<CmmId>\ (gocmm + pcdmis zips + index)
|
||||||
|
REM Copy that whole folder to the PXE staging area for restore-by-machine-#.
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
set "HERE=%~dp0"
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%HERE%Backup-CMM.ps1" %*
|
||||||
|
echo.
|
||||||
|
echo ---------------------------------------------------------------
|
||||||
|
echo Backup folder is under C:\Logs\CMM\cmm-backup\
|
||||||
|
echo ---------------------------------------------------------------
|
||||||
|
pause
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<#
|
||||||
|
Backup-CMM.ps1
|
||||||
|
|
||||||
|
ONE backup for a whole CMM bay - runs both:
|
||||||
|
- Backup-goCMMSettings.ps1 (HKLM goCMM key + C:\geaofi, minus LocalProgramCopies/logs)
|
||||||
|
- Backup-PCDMISSettings.ps1 (PC-DMIS registry + data/probe/cal + interfac.dll,
|
||||||
|
every installed version; Homepage state excluded)
|
||||||
|
|
||||||
|
All zips land together in one per-CMM folder so they can be staged on PXE and
|
||||||
|
restored by CMM machine-# at imaging.
|
||||||
|
|
||||||
|
Run as ADMINISTRATOR on the live CMM. Do NOT run on DODA bays (handled separately).
|
||||||
|
|
||||||
|
Output: C:\Logs\CMM\cmm-backup\<CmmId>\
|
||||||
|
gocmm_backup_<PC>_<ts>.zip
|
||||||
|
pcdmis_backup_<PC>_<ver>_<ts>.zip (one per PC-DMIS version)
|
||||||
|
cmm-backup-index.json
|
||||||
|
|
||||||
|
Params:
|
||||||
|
-CmmId <id> e.g. CMM3 - names the folder + index (default: computer name)
|
||||||
|
-OutDir <p> base output folder (default C:\Logs\CMM\cmm-backup)
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[string]$CmmId,
|
||||||
|
[string]$OutDir = 'C:\Logs\CMM\cmm-backup'
|
||||||
|
)
|
||||||
|
$ErrorActionPreference = 'Continue'
|
||||||
|
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||||
|
if (-not $CmmId) { $CmmId = $env:COMPUTERNAME }
|
||||||
|
$dest = Join-Path $OutDir $CmmId
|
||||||
|
New-Item -ItemType Directory -Path $dest -Force -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
$log = Join-Path $dest "cmm-backup-$ts.log"
|
||||||
|
function Log($m){ Write-Host $m; $m | Out-File -FilePath $log -Append }
|
||||||
|
|
||||||
|
Log "================ CMM backup: $CmmId on $env:COMPUTERNAME at $(Get-Date) ================"
|
||||||
|
|
||||||
|
foreach ($s in 'Backup-goCMMSettings.ps1','Backup-PCDMISSettings.ps1') {
|
||||||
|
$p = Join-Path $here $s
|
||||||
|
if (-not (Test-Path $p)) { Log "MISSING sibling script: $p - skipping"; continue }
|
||||||
|
Log "---- running $s ----"
|
||||||
|
try { & $p -OutDir $dest *>&1 | ForEach-Object { Log " $_" } }
|
||||||
|
catch { Log " ERROR in $s : $($_.Exception.Message)" }
|
||||||
|
}
|
||||||
|
|
||||||
|
# index of what we captured
|
||||||
|
$zips = Get-ChildItem $dest -Filter '*.zip' -File -ErrorAction SilentlyContinue
|
||||||
|
[pscustomobject]@{
|
||||||
|
CmmId = $CmmId
|
||||||
|
Computer = $env:COMPUTERNAME
|
||||||
|
Timestamp = (Get-Date -Format o)
|
||||||
|
goCMM = @($zips | Where-Object { $_.Name -like 'gocmm_backup_*' } | Select-Object -Expand Name)
|
||||||
|
PCDMIS = @($zips | Where-Object { $_.Name -like 'pcdmis_backup_*' } | Select-Object -Expand Name)
|
||||||
|
} | ConvertTo-Json | Out-File (Join-Path $dest 'cmm-backup-index.json') -Encoding ascii
|
||||||
|
|
||||||
|
Log "================ DONE ================"
|
||||||
|
Log "Folder: $dest"
|
||||||
|
$zips | ForEach-Object { Log (" {0} ({1} KB)" -f $_.Name, [math]::Round($_.Length/1KB)) }
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "CMM backup for $CmmId complete:" -ForegroundColor Green
|
||||||
|
Write-Host " $dest"
|
||||||
|
$zips | ForEach-Object { Write-Host " $($_.Name)" }
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
@echo off
|
||||||
|
REM Backup-PCDMISSettings.bat - capture PC-DMIS settings / probes / calibration
|
||||||
|
REM for every installed version (2016 / 2019 / 2026), headless.
|
||||||
|
REM
|
||||||
|
REM Run on a LIVE bay AS ADMINISTRATOR (reg export of HKLM + read of install dir).
|
||||||
|
REM
|
||||||
|
REM Backup-PCDMISSettings.bat (all detected versions)
|
||||||
|
REM Backup-PCDMISSettings.bat -Version 2026.1 (one version)
|
||||||
|
REM
|
||||||
|
REM Output: C:\Logs\CMM\pcdmis-backup\pcdmis_backup_<PC>_<ver>_<ts>.zip
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
set "HERE=%~dp0"
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%HERE%Backup-PCDMISSettings.ps1" %*
|
||||||
|
echo.
|
||||||
|
echo ---------------------------------------------------------------
|
||||||
|
echo Backups under C:\Logs\CMM\pcdmis-backup\ (one zip per version)
|
||||||
|
echo ---------------------------------------------------------------
|
||||||
|
pause
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
<#
|
||||||
|
Backup-PCDMISSettings.ps1
|
||||||
|
|
||||||
|
Manual PC-DMIS settings/probe/calibration backup - replicates what the Settings
|
||||||
|
Editor captures (registry + data/probe files), but headless and scriptable,
|
||||||
|
because SettingsEditor.exe /b only works through the GUI and fails non-interactively.
|
||||||
|
|
||||||
|
Works across PC-DMIS 2016 / 2019 / 2026 (auto-detects version + vendor hive:
|
||||||
|
'Hexagon' on 2019/2026, 'Wai' on older 2016 builds).
|
||||||
|
|
||||||
|
Captures, per installed version, into one zip:
|
||||||
|
- registry: HKLM + HKCU <vendor>\PC-DMIS\<ver> (settings, probe search paths)
|
||||||
|
- install-dir probe/cal master files: PROBE.DAT, usrprobe.dat, comp.dat,
|
||||||
|
tool.dat, *.prb (top level + Configuration\)
|
||||||
|
- the per-version data folders under ProgramData, Public\Documents, and
|
||||||
|
per-user AppData (Roaming + Local)
|
||||||
|
|
||||||
|
Run as administrator on a LIVE bay. One zip per installed version.
|
||||||
|
Output: C:\Logs\CMM\pcdmis-backup\pcdmis_backup_<PC>_<ver>_<ts>.zip
|
||||||
|
|
||||||
|
Params:
|
||||||
|
-Version <x> back up only this version (e.g. 2026.1). Default: every detected.
|
||||||
|
-OutDir <p> output folder (default C:\Logs\CMM\pcdmis-backup)
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[string]$Version,
|
||||||
|
[string]$OutDir = 'C:\Logs\CMM\pcdmis-backup'
|
||||||
|
)
|
||||||
|
$ErrorActionPreference = 'Continue'
|
||||||
|
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||||
|
New-Item -ItemType Directory -Path $OutDir -Force -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
$log = Join-Path $OutDir "pcdmis-backup-$ts.log"
|
||||||
|
function Log($m){ Write-Host $m; $m | Out-File -FilePath $log -Append }
|
||||||
|
|
||||||
|
# --- discover installed PC-DMIS versions: vendor (Hexagon/Wai), version, install dir ---
|
||||||
|
function Get-PCDMISInstalls {
|
||||||
|
$found = @()
|
||||||
|
$roots = @(
|
||||||
|
@{ Path='HKLM:\SOFTWARE\WOW6432Node\Hexagon\PC-DMIS'; Vendor='Hexagon' },
|
||||||
|
@{ Path='HKLM:\SOFTWARE\Hexagon\PC-DMIS'; Vendor='Hexagon' },
|
||||||
|
@{ Path='HKLM:\SOFTWARE\WOW6432Node\Wai\PC-DMIS'; Vendor='Wai' },
|
||||||
|
@{ Path='HKLM:\SOFTWARE\Wai\PC-DMIS'; Vendor='Wai' }
|
||||||
|
)
|
||||||
|
foreach ($r in $roots) {
|
||||||
|
if (-not (Test-Path $r.Path)) { continue }
|
||||||
|
Get-ChildItem $r.Path -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^\d' } | ForEach-Object {
|
||||||
|
$p = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
|
||||||
|
$ver = $_.PSChildName
|
||||||
|
$instDir = $p.Directory; if (-not $instDir) { $instDir = $p.InstallDir }
|
||||||
|
# Fallback: the registry Directory value is often blank - find the install dir on disk
|
||||||
|
if (-not $instDir) {
|
||||||
|
foreach ($pf in "$env:ProgramFiles\$($r.Vendor)","${env:ProgramFiles(x86)}\$($r.Vendor)") {
|
||||||
|
if (-not (Test-Path $pf)) { continue }
|
||||||
|
$cand = Get-ChildItem $pf -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "PC-DMIS*$ver*" -and (Test-Path (Join-Path $_.FullName 'PCDLRN.exe')) } | Select-Object -First 1
|
||||||
|
if ($cand) { $instDir = $cand.FullName; break }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$found += [pscustomobject]@{ Vendor=$r.Vendor; Version=$ver; HiveRoot=$r.Path; InstallDir=$instDir }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$found
|
||||||
|
}
|
||||||
|
|
||||||
|
function Backup-OneVersion($inst) {
|
||||||
|
$ver = $inst.Version; $vendor = $inst.Vendor
|
||||||
|
Log "==== Backing up PC-DMIS $vendor $ver ===="
|
||||||
|
$stage = Join-Path $env:TEMP "pcd-bk-$ver-$ts"
|
||||||
|
New-Item -ItemType Directory -Path $stage,"$stage\registry","$stage\install","$stage\ProgramData","$stage\PublicDocs","$stage\AppData" -Force | Out-Null
|
||||||
|
|
||||||
|
# registry: HKLM + HKCU under both Hexagon and Wai (export whichever exists)
|
||||||
|
foreach ($hk in @('HKLM','HKCU')) {
|
||||||
|
foreach ($v in @('Hexagon','Wai')) {
|
||||||
|
$regPath = "$hk\SOFTWARE\$(if($hk -eq 'HKLM'){'WOW6432Node\'} )$v\PC-DMIS\$ver"
|
||||||
|
$regPathNative = "$hk\SOFTWARE\$v\PC-DMIS\$ver"
|
||||||
|
foreach ($rp in @($regPath,$regPathNative)) {
|
||||||
|
$test = $rp -replace '^HKLM','HKLM:' -replace '^HKCU','HKCU:'
|
||||||
|
if (Test-Path $test) {
|
||||||
|
$f = "$stage\registry\$hk-$v-$ver.reg"
|
||||||
|
reg export $rp "$f" /y 2>&1 | Out-Null
|
||||||
|
if (Test-Path $f) { Log " reg export $rp" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# install-dir master probe/cal files
|
||||||
|
if ($inst.InstallDir -and (Test-Path $inst.InstallDir)) {
|
||||||
|
# interfac.dll = the active controller's interface DLL, renamed to interfac.dll
|
||||||
|
# by PC-DMIS per the machine's controller. Machine-specific - capture it.
|
||||||
|
foreach ($pat in 'PROBE.DAT','usrprobe.dat','comp.dat','compens.dat','tool.dat','machine.dat','interfac.dll') {
|
||||||
|
Get-ChildItem $inst.InstallDir -Filter $pat -ErrorAction SilentlyContinue | ForEach-Object { Copy-Item $_.FullName "$stage\install\" -Force }
|
||||||
|
}
|
||||||
|
Get-ChildItem $inst.InstallDir -Filter '*.prb' -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
|
$rel = $_.FullName.Substring($inst.InstallDir.TrimEnd('\').Length).TrimStart('\')
|
||||||
|
$dst = Join-Path "$stage\install" $rel; New-Item -ItemType Directory -Path (Split-Path $dst) -Force -EA SilentlyContinue | Out-Null
|
||||||
|
Copy-Item $_.FullName $dst -Force
|
||||||
|
}
|
||||||
|
Log " copied install-dir probe/cal files"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Identify the controller: which DLL became interfac.dll ---
|
||||||
|
# PC-DMIS makes the active controller's interface DLL into interfac.dll. If it
|
||||||
|
# was COPIED, an identical sibling .dll still exists -> hash match names it. If
|
||||||
|
# it was RENAMED (no copy), no sibling matches - so we also read the PE version
|
||||||
|
# resource's OriginalFilename, which survives a rename and names the source.
|
||||||
|
$controllerInfo = $null
|
||||||
|
$ifPath = if ($inst.InstallDir) { Join-Path $inst.InstallDir 'interfac.dll' } else { $null }
|
||||||
|
if ($ifPath -and (Test-Path $ifPath)) {
|
||||||
|
try {
|
||||||
|
$ifItem = Get-Item $ifPath
|
||||||
|
$ifHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $ifPath).Hash
|
||||||
|
$vi = $ifItem.VersionInfo
|
||||||
|
# size pre-filter so we don't hash every DLL in the install dir
|
||||||
|
$match = Get-ChildItem $inst.InstallDir -Filter '*.dll' -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.Name -ne 'interfac.dll' -and $_.Length -eq $ifItem.Length } |
|
||||||
|
Where-Object { try { (Get-FileHash -Algorithm SHA256 -LiteralPath $_.FullName).Hash -eq $ifHash } catch { $false } } |
|
||||||
|
Select-Object -First 1
|
||||||
|
$controllerInfo = [pscustomobject]@{
|
||||||
|
InterfacSha256 = $ifHash
|
||||||
|
MatchedSourceDll = if ($match) { $match.Name } else { $null } # null = renamed, no copy
|
||||||
|
OriginalFilename = $vi.OriginalFilename
|
||||||
|
FileDescription = $vi.FileDescription
|
||||||
|
ProductName = $vi.ProductName
|
||||||
|
FileVersion = $vi.FileVersion
|
||||||
|
}
|
||||||
|
Log (" controller: interfac.dll source=" + $(if ($match) { $match.Name } else { '(renamed, no copy)' }) +
|
||||||
|
" origName=$($vi.OriginalFilename) desc=$($vi.FileDescription)")
|
||||||
|
} catch { Log " WARN: controller identification failed: $($_.Exception.Message)" }
|
||||||
|
} else { Log " (no interfac.dll in install dir - controller not identified)" }
|
||||||
|
|
||||||
|
# per-version data folders
|
||||||
|
$dataMap = @(
|
||||||
|
@{ Src="$env:ProgramData\$vendor\PC-DMIS\$ver"; Dst="$stage\ProgramData" },
|
||||||
|
@{ Src="$env:PUBLIC\Documents\$vendor\PC-DMIS\$ver"; Dst="$stage\PublicDocs" },
|
||||||
|
@{ Src="$env:APPDATA\$vendor\PC-DMIS\$ver"; Dst="$stage\AppData\Roaming" },
|
||||||
|
@{ Src="$env:LOCALAPPDATA\$vendor\PC-DMIS\$ver"; Dst="$stage\AppData\Local" }
|
||||||
|
)
|
||||||
|
foreach ($d in $dataMap) {
|
||||||
|
if (Test-Path $d.Src) {
|
||||||
|
New-Item -ItemType Directory -Path $d.Dst -Force | Out-Null
|
||||||
|
# Exclude bay/path-specific Homepage state. Recent + Favorites store
|
||||||
|
# absolute routine paths (S:\..., C:\geaofi\LocalProgramCopies\...).
|
||||||
|
# Restoring them onto another bay makes PC-DMIS null-ref on launch
|
||||||
|
# (RecentExecutedItem.LoadRealNode) trying to resolve missing paths.
|
||||||
|
# Exclude the whole Homepage start-screen state (Recent, Favorites,
|
||||||
|
# DetailsView) - it stores absolute routine paths (S:\..., C:\geaofi\...)
|
||||||
|
# and PC-DMIS null-refs on launch resolving them (LoadRealNode). Rebuilt
|
||||||
|
# on use. Also skip regenerable caches/logs.
|
||||||
|
robocopy $d.Src $d.Dst /E /XD Cache Caches Temp logs Logs Homepage /R:1 /W:1 /NFL /NDL /NJH /NJS | Out-Null
|
||||||
|
Log " copied $($d.Src)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# manifest
|
||||||
|
[pscustomobject]@{
|
||||||
|
Computer=$env:COMPUTERNAME; Timestamp=(Get-Date -Format o)
|
||||||
|
Vendor=$vendor; Version=$ver; InstallDir=$inst.InstallDir
|
||||||
|
ControllerInterface=$controllerInfo
|
||||||
|
} | ConvertTo-Json -Depth 4 | Out-File "$stage\manifest.json" -Encoding ascii
|
||||||
|
|
||||||
|
# zip
|
||||||
|
$zip = Join-Path $OutDir "pcdmis_backup_${env:COMPUTERNAME}_${ver}_$ts.zip"
|
||||||
|
if (Test-Path $zip) { Remove-Item $zip -Force }
|
||||||
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||||
|
[System.IO.Compression.ZipFile]::CreateFromDirectory($stage,$zip)
|
||||||
|
Remove-Item $stage -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
Log "==== DONE: $zip ===="
|
||||||
|
return $zip
|
||||||
|
}
|
||||||
|
|
||||||
|
Log "PC-DMIS backup on $env:COMPUTERNAME at $(Get-Date)"
|
||||||
|
$installs = Get-PCDMISInstalls | Where-Object { $_.Version -match '^\d' } | Sort-Object Version -Unique
|
||||||
|
if ($Version) { $installs = $installs | Where-Object { $_.Version -eq $Version } }
|
||||||
|
if (-not $installs) { Log "No PC-DMIS installs detected (Hexagon/Wai). Nothing to back up."; return }
|
||||||
|
|
||||||
|
$made = @()
|
||||||
|
foreach ($inst in $installs) { $made += (Backup-OneVersion $inst) }
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "PC-DMIS backups written:" -ForegroundColor Green
|
||||||
|
$made | ForEach-Object { Write-Host " $_" }
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
@echo off
|
||||||
|
REM Clear-PCDMISRecent.bat - fix the PC-DMIS startup crash (NullReferenceException
|
||||||
|
REM in RecentExecutedItem.LoadRealNode) caused by a stale Homepage "Recent
|
||||||
|
REM Executed Files" list pointing at routine paths that don't resolve on this bay.
|
||||||
|
REM
|
||||||
|
REM Deletes the Recent (and Favorites) Homepage state for every user + PC-DMIS
|
||||||
|
REM version; PC-DMIS rebuilds an empty list on next launch.
|
||||||
|
REM
|
||||||
|
REM Run AS ADMINISTRATOR.
|
||||||
|
REM
|
||||||
|
REM Clear-PCDMISRecent.bat (all users, Recent + Favorites)
|
||||||
|
REM Clear-PCDMISRecent.bat -RecentOnly (keep Favorites)
|
||||||
|
REM Clear-PCDMISRecent.bat -User ShopFloor
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
set "HERE=%~dp0"
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%HERE%Clear-PCDMISRecent.ps1" %*
|
||||||
|
echo.
|
||||||
|
echo ---------------------------------------------------------------
|
||||||
|
echo Done. Relaunch PC-DMIS - the recent-list crash should be gone.
|
||||||
|
echo Log: C:\Logs\CMM\pcdmis-clearrecent-*.log
|
||||||
|
echo ---------------------------------------------------------------
|
||||||
|
pause
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
<#
|
||||||
|
Clear-PCDMISRecent.ps1
|
||||||
|
|
||||||
|
Fixes the PC-DMIS startup crash:
|
||||||
|
System.NullReferenceException
|
||||||
|
at Adapter.Service.Recent.Models.RecentExecutedItem.LoadRealNode()
|
||||||
|
at Adapter.Service.Recent.Models.RecentExecutedFiles.LoadAllWhenReady()
|
||||||
|
|
||||||
|
Cause: the Homepage "Recent Executed Files" list contains absolute routine
|
||||||
|
paths (S:\..., C:\geaofi\LocalProgramCopies\...). When a path does not resolve
|
||||||
|
in the running user's context (drive not visible, cache not yet rebuilt, file
|
||||||
|
gone), PC-DMIS dereferences a null while async-loading the list and crashes on
|
||||||
|
launch. A list carried over from another bay (e.g. a settings restore) is the
|
||||||
|
common trigger.
|
||||||
|
|
||||||
|
Fix: delete the Recent (and Favorites) Homepage state for every user profile
|
||||||
|
and every PC-DMIS version. PC-DMIS rebuilds an empty list on next start.
|
||||||
|
|
||||||
|
Run as ADMINISTRATOR (to reach all user profiles).
|
||||||
|
Output: C:\Logs\CMM\pcdmis-clearrecent-<PC>-<ts>.log
|
||||||
|
|
||||||
|
Params:
|
||||||
|
-RecentOnly only clear the Recent list, keep Favorites
|
||||||
|
-User <name> only this user's profile (default: all profiles)
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[switch]$RecentOnly,
|
||||||
|
[string]$User
|
||||||
|
)
|
||||||
|
$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-clearrecent-$env:COMPUTERNAME-$ts.log"
|
||||||
|
function Log($m){ Write-Host $m; $m | Out-File -FilePath $log -Append }
|
||||||
|
|
||||||
|
Log "==== Clear PC-DMIS Recent/Favorites on $env:COMPUTERNAME at $(Get-Date) ===="
|
||||||
|
|
||||||
|
# which user profiles
|
||||||
|
$userDirs = @()
|
||||||
|
if ($User) {
|
||||||
|
if (Test-Path "C:\Users\$User") { $userDirs += "C:\Users\$User" } else { Log "User profile C:\Users\$User not found" }
|
||||||
|
} else {
|
||||||
|
$userDirs = (Get-ChildItem 'C:\Users' -Directory -ErrorAction SilentlyContinue).FullName
|
||||||
|
}
|
||||||
|
|
||||||
|
$targets = @('Homepage\Recent\RecentExecutedFiles.xml')
|
||||||
|
if (-not $RecentOnly) { $targets += 'Homepage\Favorites\Favorites.xml' }
|
||||||
|
|
||||||
|
$deleted = 0; $scanned = 0
|
||||||
|
foreach ($u in $userDirs) {
|
||||||
|
foreach ($vendor in 'Hexagon','WAI') {
|
||||||
|
$base = Join-Path $u "AppData\Local\$vendor\PC-DMIS"
|
||||||
|
if (-not (Test-Path $base)) { continue }
|
||||||
|
foreach ($vdir in (Get-ChildItem $base -Directory -ErrorAction SilentlyContinue)) {
|
||||||
|
$scanned++
|
||||||
|
foreach ($rel in $targets) {
|
||||||
|
$f = Join-Path $vdir.FullName $rel
|
||||||
|
if (Test-Path $f) {
|
||||||
|
try { Remove-Item $f -Force -ErrorAction Stop; $deleted++
|
||||||
|
Log " DELETED $f"
|
||||||
|
} catch { Log " FAILED $f : $($_.Exception.Message)" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log ""
|
||||||
|
Log "Scanned $scanned PC-DMIS version folder(s) across $($userDirs.Count) profile(s); deleted $deleted file(s)."
|
||||||
|
Log "PC-DMIS will rebuild an empty recent list on next launch."
|
||||||
|
Write-Host ""
|
||||||
|
if ($deleted -gt 0) { Write-Host "Cleared $deleted stale Homepage file(s). Relaunch PC-DMIS - the crash should be gone." -ForegroundColor Green }
|
||||||
|
else { Write-Host "Nothing to clear (no RecentExecutedFiles.xml found). If it still crashes, the cause is elsewhere - grab the event log." -ForegroundColor Yellow }
|
||||||
|
Log "Log: $log"
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
@echo off
|
||||||
|
REM Export-PCDMISCrashEvents.bat - pull the Windows event-log entries that
|
||||||
|
REM explain the PC-DMIS crash (the full .NET exception + stack, which the
|
||||||
|
REM crash minidump does NOT contain).
|
||||||
|
REM
|
||||||
|
REM Run AS ADMINISTRATOR on the bay that crashed, soon after the crash.
|
||||||
|
REM
|
||||||
|
REM Export-PCDMISCrashEvents.bat (last 72 hours)
|
||||||
|
REM Export-PCDMISCrashEvents.bat -Hours 12 (narrower window)
|
||||||
|
REM
|
||||||
|
REM Output: C:\Logs\CMM\pcdmis-crash-events-<PC>-<ts>.txt
|
||||||
|
REM Send that file back - the first .NET Runtime (ID 1026) event is the answer.
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
set "HERE=%~dp0"
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%HERE%Export-PCDMISCrashEvents.ps1" %*
|
||||||
|
echo.
|
||||||
|
echo ---------------------------------------------------------------
|
||||||
|
echo Wrote C:\Logs\CMM\pcdmis-crash-events-*.txt - send it back.
|
||||||
|
echo ---------------------------------------------------------------
|
||||||
|
pause
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<#
|
||||||
|
Export-PCDMISCrashEvents.ps1
|
||||||
|
|
||||||
|
Pull the Windows event-log entries that explain a PC-DMIS crash. The crash
|
||||||
|
minidump has no symbols, but Windows logs the full .NET exception (type +
|
||||||
|
message + stack) in the Application log. This grabs those.
|
||||||
|
|
||||||
|
Run as administrator on the bay that crashed, soon after the crash.
|
||||||
|
|
||||||
|
Collects from the Application log (default last 72 hours):
|
||||||
|
- Event ID 1026 (.NET Runtime) <- the FULL managed exception + stack
|
||||||
|
- Event ID 1000 (Application Error) <- faulting module/offset for PCDLRN.exe
|
||||||
|
- Event ID 1001 (Windows Error Reporting) <- crash bucket / report path
|
||||||
|
|
||||||
|
Output: C:\Logs\CMM\pcdmis-crash-events-<PC>-<ts>.txt
|
||||||
|
|
||||||
|
Params:
|
||||||
|
-Hours <n> look-back window in hours (default 72)
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[int]$Hours = 72,
|
||||||
|
[string]$OutDir = 'C:\Logs\CMM'
|
||||||
|
)
|
||||||
|
$ErrorActionPreference = 'Continue'
|
||||||
|
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||||
|
New-Item -ItemType Directory -Path $OutDir -Force -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
$out = Join-Path $OutDir "pcdmis-crash-events-$env:COMPUTERNAME-$ts.txt"
|
||||||
|
function W($m){ $m | Out-File -FilePath $out -Append -Encoding utf8 }
|
||||||
|
|
||||||
|
$since = (Get-Date).AddHours(-$Hours)
|
||||||
|
W "==== PC-DMIS crash events on $env:COMPUTERNAME ===="
|
||||||
|
W "Generated : $(Get-Date)"
|
||||||
|
W "Window : since $since (last $Hours h)"
|
||||||
|
W ""
|
||||||
|
|
||||||
|
# Pull the candidate events
|
||||||
|
$events = @()
|
||||||
|
try {
|
||||||
|
$events = Get-WinEvent -FilterHashtable @{ LogName='Application'; Id=1000,1001,1026; StartTime=$since } -ErrorAction SilentlyContinue
|
||||||
|
} catch { W "Get-WinEvent failed: $($_.Exception.Message)" }
|
||||||
|
|
||||||
|
if (-not $events) { W "No Application 1000/1001/1026 events in the window."; W "Widen with -Hours, or the crash logged elsewhere."; Write-Host "Wrote $out"; return }
|
||||||
|
|
||||||
|
# Most relevant first: anything mentioning PCDLRN / PC-DMIS / a .NET exception
|
||||||
|
$relevant = $events | Where-Object { $_.Message -match 'PCDLRN|PC-DMIS|Hexagon|\.NET|System\.[A-Za-z.]+Exception|Qdas|QDAS|Report|Blade' }
|
||||||
|
|
||||||
|
W "================ RELEVANT (PC-DMIS / .NET) - $($relevant.Count) event(s) ================"
|
||||||
|
foreach ($e in ($relevant | Sort-Object TimeCreated -Descending)) {
|
||||||
|
W "-------------------------------------------------------------"
|
||||||
|
W ("Time : {0}" -f $e.TimeCreated)
|
||||||
|
W ("EventID : {0} Provider: {1} Level: {2}" -f $e.Id, $e.ProviderName, $e.LevelDisplayName)
|
||||||
|
W "Message :"
|
||||||
|
W ($e.Message)
|
||||||
|
W ""
|
||||||
|
}
|
||||||
|
|
||||||
|
W ""
|
||||||
|
W "================ ALL 1000/1001/1026 in window ($($events.Count)) - summary ================"
|
||||||
|
$events | Sort-Object TimeCreated -Descending | ForEach-Object {
|
||||||
|
$firstLine = ($_.Message -split "`r?`n" | Where-Object { $_.Trim() } | Select-Object -First 1)
|
||||||
|
W ("{0} ID={1,-4} {2,-26} {3}" -f $_.TimeCreated, $_.Id, $_.ProviderName, $firstLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Also note where PC-DMIS drops its own crash zips (CrashRpt)
|
||||||
|
W ""
|
||||||
|
W "================ PC-DMIS CrashRpt zips on disk ================"
|
||||||
|
foreach ($d in "$env:LOCALAPPDATA\CrashRpt","$env:TEMP","$env:ProgramData\Hexagon") {
|
||||||
|
if (Test-Path $d) {
|
||||||
|
Get-ChildItem $d -Recurse -Filter '*.zip' -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.LastWriteTime -gt $since } |
|
||||||
|
ForEach-Object { W (" {0} {1}" -f $_.LastWriteTime, $_.FullName) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Wrote: $out" -ForegroundColor Green
|
||||||
|
Write-Host "Open it and look at the first RELEVANT 1026 (.NET Runtime) event - that has the exact exception + stack."
|
||||||
10
playbook/shopfloor-setup/gea-shopfloor-cmm/scripts/Grant-FullControl.ps1
Executable file
10
playbook/shopfloor-setup/gea-shopfloor-cmm/scripts/Grant-FullControl.ps1
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
$Folders = @(
|
||||||
|
"C:\Apps\"
|
||||||
|
"C:\BladeRunner"
|
||||||
|
"C:\Users\Public"
|
||||||
|
"C:\Program Files\Hexagon"
|
||||||
|
"C:\ProgramData\Hexagon"
|
||||||
|
)
|
||||||
|
foreach ($Folder in $Folders) {
|
||||||
|
icacls $Folder /grant "*S-1-5-32-545:(OI)(CI)F" /T
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
@echo off
|
||||||
|
REM Install-PCDMISSettings.bat - restore a PC-DMIS backup (SAME version).
|
||||||
|
REM
|
||||||
|
REM Run AS ADMINISTRATOR / at imaging. Imports the registry hive + data/probe
|
||||||
|
REM files, grants the operator write on the data dir, and auto-applies the
|
||||||
|
REM legacy->new FQDN rewrite (rd.ds.ge.com -> wjs.geaerospace.net).
|
||||||
|
REM
|
||||||
|
REM Install-PCDMISSettings.bat "<zip>"
|
||||||
|
REM Install-PCDMISSettings.bat "<zip>" /replace <from> <to>
|
||||||
|
REM
|
||||||
|
REM CROSS-VERSION upgrade (e.g. 2016 backup -> 2026 bay): do NOT use this -
|
||||||
|
REM use the 2026 Settings Editor IMPORT feature, which remaps the older layout.
|
||||||
|
REM This script does a verbatim same-version restore.
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
set "HERE=%~dp0"
|
||||||
|
if "%~1"=="" (
|
||||||
|
echo Usage: %~nx0 "^<zip^>" [/replace ^<from^> ^<to^>]
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
set "ZIP=%~1"
|
||||||
|
set "PS=powershell.exe -NoProfile -ExecutionPolicy Bypass -File ""%HERE%Install-PCDMISSettings.ps1"" -BackupPath ""%ZIP%"""
|
||||||
|
|
||||||
|
if /i "%~2"=="/replace" (
|
||||||
|
if "%~4"=="" ( echo /replace needs ^<from^> ^<to^> & pause & exit /b 1 )
|
||||||
|
%PS% -ReplaceFrom "%~3" -ReplaceTo "%~4"
|
||||||
|
) else (
|
||||||
|
%PS%
|
||||||
|
)
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
<#
|
||||||
|
Install-PCDMISSettings.ps1
|
||||||
|
|
||||||
|
Restore a PC-DMIS settings/probe backup made by Backup-PCDMISSettings.ps1.
|
||||||
|
Imports the registry hive + lays the install/ProgramData/Public/AppData files
|
||||||
|
back, grants the operator write on the ProgramData data dir (so custom probes
|
||||||
|
can be saved under lockdown), and auto-applies the legacy->new FQDN rewrite.
|
||||||
|
|
||||||
|
SAME-VERSION restore only (e.g. 2026.1 backup -> 2026.1 bay). To migrate a bay
|
||||||
|
to a NEWER PC-DMIS (e.g. 2016 -> 2026), use the 2026 Settings Editor's IMPORT
|
||||||
|
feature instead - it remaps the older registry/data layout. This script does a
|
||||||
|
verbatim restore and does not remap versions.
|
||||||
|
|
||||||
|
Run as administrator / at imaging.
|
||||||
|
|
||||||
|
Params:
|
||||||
|
-BackupPath <zip|dir> required
|
||||||
|
-ReplaceFrom/-ReplaceTo extra find/replace pair (case-insensitive)
|
||||||
|
-NoDefaultRewrite skip the built-in legacy->new FQDN swaps
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)][string]$BackupPath,
|
||||||
|
[string]$TargetUser = 'ShopFloor', # account that RUNS PC-DMIS; HKCU settings (probe search paths) land in ITS hive
|
||||||
|
[string]$ReplaceFrom,
|
||||||
|
[string]$ReplaceTo,
|
||||||
|
[switch]$NoDefaultRewrite
|
||||||
|
)
|
||||||
|
|
||||||
|
# Built-in FQDN migration (same as the goCMM restore). Add pairs as domains retire.
|
||||||
|
$DefaultRewrites = @(
|
||||||
|
@{ From = 'rd.ds.ge.com'; To = 'wjs.geaerospace.net' }
|
||||||
|
)
|
||||||
|
|
||||||
|
$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 "pcdmis-restore-$ts.log"
|
||||||
|
function Log($m){ Write-Host $m; $m | Out-File -FilePath $log -Append }
|
||||||
|
|
||||||
|
Log "==== PC-DMIS restore on $env:COMPUTERNAME from $BackupPath ===="
|
||||||
|
|
||||||
|
# resolve backup to a dir
|
||||||
|
$src = $BackupPath; $extracted = $false
|
||||||
|
if ($BackupPath -match '\.zip$') {
|
||||||
|
$src = Join-Path $env:TEMP "pcd-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 }
|
||||||
|
|
||||||
|
# If pointed at a FOLDER that merely contains the backup zip (common mistake), use the zip
|
||||||
|
if ((Test-Path $src -PathType Container) -and -not (Test-Path (Join-Path $src 'manifest.json'))) {
|
||||||
|
$z = Get-ChildItem $src -Filter 'pcdmis_backup_*.zip' -File -ErrorAction SilentlyContinue | Sort-Object LastWriteTime | Select-Object -Last 1
|
||||||
|
if ($z) {
|
||||||
|
Log "BackupPath was a folder; using the zip inside it: $($z.Name)"
|
||||||
|
$src = Join-Path $env:TEMP "pcd-rs-$ts"
|
||||||
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||||
|
[System.IO.Compression.ZipFile]::ExtractToDirectory($z.FullName, $src); $extracted = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# manifest
|
||||||
|
$vendor='Hexagon'; $ver=''; $installDir=''
|
||||||
|
$mani = Join-Path $src 'manifest.json'
|
||||||
|
if (Test-Path $mani) {
|
||||||
|
try { $m = Get-Content $mani -Raw | ConvertFrom-Json
|
||||||
|
$vendor=$m.Vendor; $ver=$m.Version; $installDir=$m.InstallDir
|
||||||
|
Log "manifest: $vendor PC-DMIS $ver install=$installDir" } catch { Log "WARN: manifest parse: $($_.Exception.Message)" }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fail LOUD if this isn't actually a PC-DMIS backup (don't silently "succeed")
|
||||||
|
$regDir = Join-Path $src 'registry'
|
||||||
|
$haveReg = (Test-Path $regDir) -and @(Get-ChildItem $regDir -Filter '*.reg' -ErrorAction SilentlyContinue).Count -gt 0
|
||||||
|
if (-not (Test-Path $mani) -and -not $haveReg) {
|
||||||
|
Log "ERROR: '$BackupPath' is not a PC-DMIS backup - no manifest.json and no registry\*.reg found."
|
||||||
|
Log " Point -BackupPath at the pcdmis_backup_<PC>_<ver>_<ts>.zip file (or its extracted folder), NOT a parent dir like the Desktop."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if (-not $ver) { Log "ERROR: manifest has no Version - cannot place per-version data. Aborting (bad/empty backup)."; exit 1 }
|
||||||
|
|
||||||
|
# --- resolve the target user's hive so HKCU settings (probe search paths) land in ITS profile ---
|
||||||
|
$targetHiveReg = $null; $unloadHive = $false
|
||||||
|
if ($TargetUser) {
|
||||||
|
$tsid = $null
|
||||||
|
try { $tsid = (New-Object System.Security.Principal.NTAccount($TargetUser)).Translate([System.Security.Principal.SecurityIdentifier]).Value } catch {}
|
||||||
|
if ($tsid -and (Test-Path "Registry::HKEY_USERS\$tsid")) {
|
||||||
|
$targetHiveReg = "HKEY_USERS\$tsid"; Log "Target user $TargetUser is logged in - HKCU settings -> $targetHiveReg"
|
||||||
|
} else {
|
||||||
|
$ntuser = "C:\Users\$TargetUser\NTUSER.DAT"
|
||||||
|
if (Test-Path $ntuser) {
|
||||||
|
reg load "HKU\PCDTGT" "$ntuser" 2>&1 | Out-Null
|
||||||
|
if (Test-Path 'Registry::HKEY_USERS\PCDTGT') { $targetHiveReg = 'HKEY_USERS\PCDTGT'; $unloadHive = $true; Log "Loaded $TargetUser NTUSER.DAT - HKCU settings -> $targetHiveReg" }
|
||||||
|
else { Log "WARN: failed to load $ntuser - HKCU settings will go to the CURRENT user, not $TargetUser" }
|
||||||
|
} else { Log "WARN: $ntuser not found ($TargetUser may not have logged in yet) - HKCU settings go to CURRENT user" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# registry import - HKCU files routed into the target user's hive when resolved
|
||||||
|
Get-ChildItem $regDir -Filter '*.reg' -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
|
$f = $_.FullName; $n = $_.Name
|
||||||
|
if (($n -like 'HKCU-*') -and $targetHiveReg) {
|
||||||
|
$txt = [System.IO.File]::ReadAllText($f) -replace 'HKEY_CURRENT_USER', $targetHiveReg
|
||||||
|
$tmp = Join-Path $env:TEMP "tgt-$n"
|
||||||
|
[System.IO.File]::WriteAllText($tmp, $txt, [System.Text.Encoding]::Unicode)
|
||||||
|
reg import $tmp 2>&1 | Out-Null; Remove-Item $tmp -Force -ErrorAction SilentlyContinue
|
||||||
|
Log " reg import $n -> $TargetUser ($targetHiveReg)"
|
||||||
|
} else {
|
||||||
|
reg import $f 2>&1 | Out-Null; Log " reg import $n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# install-dir files back
|
||||||
|
$instSrc = Join-Path $src 'install'
|
||||||
|
if ((Test-Path $instSrc) -and $installDir) {
|
||||||
|
if (-not (Test-Path $installDir)) { Log "WARN: install dir $installDir absent - skipping install-file restore" }
|
||||||
|
else { robocopy $instSrc $installDir /E /R:1 /W:1 /NFL /NDL /NJH /NJS | Out-Null; Log " restored install-dir probe/cal files -> $installDir" }
|
||||||
|
}
|
||||||
|
|
||||||
|
# data folders back
|
||||||
|
$dataMap = @(
|
||||||
|
@{ Src=(Join-Path $src 'ProgramData'); Dst="$env:ProgramData\$vendor\PC-DMIS\$ver" },
|
||||||
|
@{ Src=(Join-Path $src 'PublicDocs'); Dst="$env:PUBLIC\Documents\$vendor\PC-DMIS\$ver" },
|
||||||
|
@{ Src=(Join-Path $src 'AppData\Roaming'); Dst="$env:APPDATA\$vendor\PC-DMIS\$ver" },
|
||||||
|
@{ Src=(Join-Path $src 'AppData\Local'); Dst="$env:LOCALAPPDATA\$vendor\PC-DMIS\$ver" }
|
||||||
|
)
|
||||||
|
foreach ($d in $dataMap) {
|
||||||
|
if (Test-Path $d.Src) {
|
||||||
|
New-Item -ItemType Directory -Path $d.Dst -Force -EA SilentlyContinue | Out-Null
|
||||||
|
# /XD Homepage: never restore the Homepage start-screen state (Recent,
|
||||||
|
# Favorites, DetailsView - absolute S:\ / C:\geaofi paths) - it null-refs
|
||||||
|
# PC-DMIS on launch. Also protects against OLD backups that still contain it.
|
||||||
|
robocopy $d.Src $d.Dst /E /XD Homepage /R:1 /W:1 /NFL /NDL /NJH /NJS | Out-Null
|
||||||
|
Log " restored -> $($d.Dst)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Defensive: strip any pre-existing Homepage recent/favorites in BOTH the running
|
||||||
|
# user's and the target user's profile, so a stale list can't crash PC-DMIS.
|
||||||
|
$profiles = @($env:LOCALAPPDATA)
|
||||||
|
if ($TargetUser -and (Test-Path "C:\Users\$TargetUser\AppData\Local")) { $profiles += "C:\Users\$TargetUser\AppData\Local" }
|
||||||
|
foreach ($la in ($profiles | Sort-Object -Unique)) {
|
||||||
|
foreach ($f in "$la\$vendor\PC-DMIS\$ver\Homepage\Recent\RecentExecutedFiles.xml",
|
||||||
|
"$la\$vendor\PC-DMIS\$ver\Homepage\Favorites\Favorites.xml") {
|
||||||
|
if (Test-Path $f) { Remove-Item $f -Force -ErrorAction SilentlyContinue; Log " cleared stale Homepage state: $f" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# grant operator Modify on the ProgramData data dir (save custom probes under lockdown)
|
||||||
|
$pdDir = "$env:ProgramData\$vendor\PC-DMIS\$ver"
|
||||||
|
if (Test-Path $pdDir) { & icacls $pdDir /grant 'BUILTIN\Users:(OI)(CI)M' /T /C 2>&1 | Out-Null; Log " granted BUILTIN\Users Modify on $pdDir" }
|
||||||
|
|
||||||
|
# --- find/replace (default legacy->new FQDN + optional extra) across reg values + data files ---
|
||||||
|
$rewrites = @()
|
||||||
|
if (-not $NoDefaultRewrite) { $rewrites += $DefaultRewrites }
|
||||||
|
if ($ReplaceFrom -and $ReplaceTo) { $rewrites += @{ From=$ReplaceFrom; To=$ReplaceTo } }
|
||||||
|
if ($rewrites.Count -gt 0) {
|
||||||
|
$utf8 = New-Object System.Text.UTF8Encoding($false)
|
||||||
|
$regKeys = @("HKLM:\SOFTWARE\WOW6432Node\$vendor\PC-DMIS\$ver","HKCU:\SOFTWARE\$vendor\PC-DMIS\$ver")
|
||||||
|
if ($targetHiveReg) { $regKeys += "Registry::$targetHiveReg\SOFTWARE\$vendor\PC-DMIS\$ver" } # also the ShopFloor hive we imported into
|
||||||
|
$fileDirs = @($pdDir, "$env:PUBLIC\Documents\$vendor\PC-DMIS\$ver", "$env:APPDATA\$vendor\PC-DMIS\$ver", $installDir) | Where-Object { $_ -and (Test-Path $_) }
|
||||||
|
foreach ($rw in $rewrites) {
|
||||||
|
$from=$rw.From; $to=$rw.To; if (-not $from) { continue }
|
||||||
|
Log "Find/replace: '$from' -> '$to' (case-insensitive)"
|
||||||
|
$rx = [regex]::Escape($from)
|
||||||
|
foreach ($rk in $regKeys) {
|
||||||
|
if (-not (Test-Path $rk)) { continue }
|
||||||
|
Get-ChildItem $rk -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
|
$props = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
|
||||||
|
if (-not $props) { return }
|
||||||
|
foreach ($p in $props.PSObject.Properties) {
|
||||||
|
if ($p.Name -like 'PS*') { continue }
|
||||||
|
if (($p.Value -is [string]) -and [regex]::IsMatch($p.Value,$rx,'IgnoreCase')) {
|
||||||
|
Set-ItemProperty $_.PSPath -Name $p.Name -Value ([regex]::Replace($p.Value,$rx,$to,'IgnoreCase'))
|
||||||
|
Log " reg [$($p.Name)]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($fd in $fileDirs) {
|
||||||
|
Get-ChildItem $fd -Recurse -File -Include *.dat,*.prb,*.xml,*.txt,*.cfg,*.ini,*.bas -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
|
try { $c=[System.IO.File]::ReadAllText($_.FullName)
|
||||||
|
if ([regex]::IsMatch($c,$rx,'IgnoreCase')) { [System.IO.File]::WriteAllText($_.FullName,[regex]::Replace($c,$rx,$to,'IgnoreCase'),$utf8); Log " file [$($_.Name)]" }
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($unloadHive) { [gc]::Collect(); [gc]::WaitForPendingFinalizers(); Start-Sleep 1; reg unload 'HKU\PCDTGT' 2>&1 | Out-Null; Log "unloaded $TargetUser hive" }
|
||||||
|
if ($extracted) { Remove-Item $src -Recurse -Force -ErrorAction SilentlyContinue }
|
||||||
|
Log "==== DONE ===="
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "PC-DMIS restore complete ($vendor $ver). Log: $log" -ForegroundColor Green
|
||||||
@@ -134,7 +134,7 @@ if ($rewrites.Count -gt 0) {
|
|||||||
|
|
||||||
# files: every text file under the Shared Data Directory
|
# files: every text file under the Shared Data Directory
|
||||||
if (Test-Path $sharedDir) {
|
if (Test-Path $sharedDir) {
|
||||||
Get-ChildItem -Path $sharedDir -Recurse -File -Include *.xml,*.txt,*.csv,*.config,*.ini -ErrorAction SilentlyContinue | ForEach-Object {
|
Get-ChildItem -Path $sharedDir -Recurse -File -Include *.xml,*.txt,*.csv,*.config,*.ini,*.bas -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
try {
|
try {
|
||||||
$c = [System.IO.File]::ReadAllText($_.FullName)
|
$c = [System.IO.File]::ReadAllText($_.FullName)
|
||||||
if ([regex]::IsMatch($c, $rxFrom, 'IgnoreCase')) {
|
if ([regex]::IsMatch($c, $rxFrom, 'IgnoreCase')) {
|
||||||
|
|||||||
110
playbook/shopfloor-setup/gea-shopfloor-cmm/scripts/Modify-PCDMISRights.ps1
Executable file
110
playbook/shopfloor-setup/gea-shopfloor-cmm/scripts/Modify-PCDMISRights.ps1
Executable file
@@ -0,0 +1,110 @@
|
|||||||
|
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
|
||||||
|
|
||||||
|
Start-Transcript -Path "C:\Logs\PC-DMISrights.txt" -Append
|
||||||
|
|
||||||
|
# 1. Define the authorized username
|
||||||
|
$authorizedUser = "SupportUser"
|
||||||
|
|
||||||
|
# 2. Check if the current environment user matches
|
||||||
|
if ($env:USERNAME -ne $authorizedUser) {
|
||||||
|
Write-Warning "Unauthorized user detected. Run as SupportUser instead."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# 3. Access granted for SupportUser
|
||||||
|
Write-Host "Welcome, $authorizedUser. Access granted."
|
||||||
|
|
||||||
|
|
||||||
|
# 4. Define the list of registry keys to modify
|
||||||
|
$registryKeys = @(
|
||||||
|
"HKLM:\SOFTWARE\Classes\PCDLRN.Application",
|
||||||
|
"HKCU:\SOFTWARE\Hexagon"
|
||||||
|
"HKCU:\SOFTWARE\WAI"
|
||||||
|
"HKLM:\SOFTWARE\Hexagon"
|
||||||
|
"HKLM:\SOFTWARE\WAI"
|
||||||
|
"HKLM:\SOFTWARE\Wow6432Node\Hexagon"
|
||||||
|
"HKLM:\SOFTWARE\Wow6432Node\WAI"
|
||||||
|
"Registry::HKU\.DEFAULT\SOFTWARE\Hexagon"
|
||||||
|
"Registry::HKU\.DEFAULT\SOFTWARE\WAI"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 5. Define the permission rule details
|
||||||
|
$identity = "BUILTIN\Users" # The target group
|
||||||
|
$rights = "FullControl" # Permission level
|
||||||
|
$inheritance = "ContainerInherit, ObjectInherit" # Applies to subkeys and values
|
||||||
|
$propagation = "None"
|
||||||
|
$type = "Allow"
|
||||||
|
|
||||||
|
# 6. Create the Access Rule object
|
||||||
|
$accessRule = New-Object System.Security.AccessControl.RegistryAccessRule($identity, $rights, $inheritance, $propagation, $type)
|
||||||
|
|
||||||
|
# 7. Loop through each key and apply the new rule
|
||||||
|
foreach ($keyPath in $registryKeys) {
|
||||||
|
try {
|
||||||
|
if (Test-Path $keyPath) {
|
||||||
|
Write-Host "Applying permissions to: $keyPath" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Get existing ACL (Access Control List)
|
||||||
|
$acl = Get-Acl -Path $keyPath
|
||||||
|
|
||||||
|
# Add the new rule to the existing ACL
|
||||||
|
$acl.SetAccessRule($accessRule)
|
||||||
|
|
||||||
|
# Apply the updated ACL back to the registry key
|
||||||
|
Set-Acl -Path $keyPath -AclObject $acl
|
||||||
|
|
||||||
|
Write-Host "Success!" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
Write-Warning "Registry key not found: $keyPath"
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Error "Failed to update $keyPath. Error: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 8. Define the list of root folders to modify
|
||||||
|
$folderPaths = @(
|
||||||
|
"C:\Program Files\Hexagon",
|
||||||
|
"C:\Program Files\WAI",
|
||||||
|
"C:\Program Files (x86)\Hexagon"
|
||||||
|
"C:\Program Files (x86)\WAI"
|
||||||
|
"C:\ProgramData\Hexagon"
|
||||||
|
"C:\ProgramData\WAI"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 9. Define the permission rule details
|
||||||
|
$identity = "BUILTIN\Users" # The target group
|
||||||
|
$rights = "FullControl" # Permission level
|
||||||
|
$inheritance = "ContainerInherit, ObjectInherit" # Applies to subfolders and files
|
||||||
|
$propagation = "None"
|
||||||
|
$type = "Allow"
|
||||||
|
|
||||||
|
# 10. Create the Access Rule object
|
||||||
|
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($identity, $rights, $inheritance, $propagation, $type)
|
||||||
|
|
||||||
|
# 11. Loop through each folder path and apply the new rule
|
||||||
|
foreach ($path in $folderPaths) {
|
||||||
|
try {
|
||||||
|
if (Test-Path $path) {
|
||||||
|
Write-Host "Applying permissions to: $path" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Get existing ACL (Access Control List)
|
||||||
|
$acl = Get-Acl -Path $path
|
||||||
|
|
||||||
|
# Add the new rule to the existing ACL
|
||||||
|
$acl.SetAccessRule($accessRule)
|
||||||
|
|
||||||
|
# Apply the updated ACL back to the folder
|
||||||
|
Set-Acl -Path $path -AclObject $acl
|
||||||
|
|
||||||
|
Write-Host "Success!" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
Write-Warning "Folder not found: $path"
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Error "Failed to update $keyPath. Error: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pause
|
||||||
|
exit 1
|
||||||
|
Stop-Transcript
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
@echo off
|
||||||
|
REM pcdmis-probe-debug.bat - find why custom probes don't show in PC-DMIS.
|
||||||
|
REM
|
||||||
|
REM *** RUN AS THE OPERATOR (the account that launches PC-DMIS), NOT elevated. ***
|
||||||
|
REM The probe search path + VirtualStore are per-user, so it must run in that
|
||||||
|
REM account to see the right view. Machine-wide ProgramData/ACLs are read anyway.
|
||||||
|
REM
|
||||||
|
REM Output: C:\Logs\CMM\pcdmis-probe-debug-<PC>-<timestamp>.txt
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
set "HERE=%~dp0"
|
||||||
|
echo.
|
||||||
|
echo Running PC-DMIS probe debug as %USERDOMAIN%\%USERNAME% ...
|
||||||
|
echo (If the title bar says Administrator, STOP - run as the operator instead.)
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%HERE%pcdmis-probe-debug.ps1"
|
||||||
|
echo.
|
||||||
|
echo ---------------------------------------------------------------
|
||||||
|
echo Done. Collect C:\Logs\CMM\pcdmis-probe-debug-*.txt
|
||||||
|
echo ---------------------------------------------------------------
|
||||||
|
pause
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
<#
|
||||||
|
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
|
||||||
Reference in New Issue
Block a user