Wax/Trace triad: fix registry corruption + cover v6.213 vendor install path
Three fixes in Backup / Export / Install, validated end-to-end on the win11 VM
against a seeded HKCU\SOFTWARE\Mitutoyo\Formtracepak key carrying all five
registry value types (String, DWord, ExpandString, MultiString, Binary).
1. Registry corruption on REG_BINARY / REG_MULTI_SZ restore
Backup wrote those values to registry_values.csv via [string]$val, which
lossily coerces a byte[] to "System.Byte[]" and a string[] to a
space-joined scalar. Install's CSV restore loop runs AFTER the .reg file
import (which is lossless), so the CSV pass overwrites the good values
with corrupted strings. Two-part fix:
- Backup: skip Binary / MultiString / None / Unknown when writing the CSV.
Only String, ExpandString, DWord, QWord roundtrip cleanly through
New-ItemProperty -PropertyType, so capture only those. The .reg file
remains authoritative for the rest.
- Install: defensive filter on the CSV restore loop that skips any row
whose Type is not in {String, ExpandString, DWord, QWord}. This catches
legacy CSVs already on the share that were taken before this fix.
2. v6.213 vendor install path not scanned / not restored to
The per-bay FormTracePak install (commit 54dddaa) lands under
C:\Program Files (x86)\MitutoyoApp\Formtracepak, but the search-path
lists in Backup + Export only covered C:\...\Mitutoyo (no MitutoyoApp).
Result: a backup taken on a freshly imaged v6.213 bay produced Config
Files = 0 because the script never looked at the actual install dir.
Added MitutoyoApp (x86 + native ProgramFiles) ahead of the legacy
paths in all three scripts.
3. Install $DefaultAppTargets fallback didn't include MitutoyoApp either,
so a restore from an OLDER bay (source path C:\Mitutoyo\...) onto a
freshly imaged v6.213 bay would fall back to ProgramFiles\Mitutoyo
(does not exist), miss the MitutoyoApp\Formtracepak tree, and write
the restored files into the first existing legacy path. Added the
MitutoyoApp entries at the top of the ordered fallback table.
Smoke tested on win11 VM: backup of all 5 reg types, then corrupt every
value, then Install -RestoreAll restores all 5 byte-exact (incl. REG_BINARY
DE-AD-BE-EF-CA-FE-BA-BE-01-02-03-04 and REG_MULTI_SZ alpha.smp/beta.smp/
gamma.smp). Verified legacy poison-CSV path triggers the defensive filter
and the .reg-imported values survive untouched. -DryRun confirmed
non-mutating. Idempotency confirmed via hash-skip.
This commit is contained in:
@@ -84,6 +84,9 @@ $ErrorActionPreference = 'Continue'
|
|||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
$ApplicationPaths = @(
|
$ApplicationPaths = @(
|
||||||
|
# v6.213 vendor MSI layout (the path the per-bay install lands on today).
|
||||||
|
"${env:ProgramFiles(x86)}\MitutoyoApp"
|
||||||
|
"${env:ProgramFiles}\MitutoyoApp"
|
||||||
"${env:ProgramFiles}\Mitutoyo"
|
"${env:ProgramFiles}\Mitutoyo"
|
||||||
"${env:ProgramFiles(x86)}\Mitutoyo"
|
"${env:ProgramFiles(x86)}\Mitutoyo"
|
||||||
"${env:ProgramFiles}\FORMTRACEPAK"
|
"${env:ProgramFiles}\FORMTRACEPAK"
|
||||||
@@ -280,15 +283,28 @@ foreach ($root in $RegistryRoots) {
|
|||||||
Write-Warning " reg.exe export failed for ${root}: $_"
|
Write-Warning " reg.exe export failed for ${root}: $_"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Also capture as CSV for granular restore
|
# Also capture as CSV for granular restore.
|
||||||
|
#
|
||||||
|
# CSV path only round-trips cleanly for String / ExpandString / DWord /
|
||||||
|
# QWord. Binary and MultiString lossily coerce through [string] (Binary
|
||||||
|
# becomes "System.Byte[]" literal; MultiString becomes space-joined),
|
||||||
|
# which then corrupts the registry if the CSV restore overwrites the
|
||||||
|
# .reg-import result. Skip those types in the CSV (the .reg file is
|
||||||
|
# authoritative for them).
|
||||||
|
$csvSafeTypes = @('String', 'ExpandString', 'DWord', 'QWord')
|
||||||
try {
|
try {
|
||||||
$allKeys = @(Get-Item -Path $root -ErrorAction SilentlyContinue)
|
$allKeys = @(Get-Item -Path $root -ErrorAction SilentlyContinue)
|
||||||
$allKeys += Get-ChildItem -Path $root -Recurse -ErrorAction SilentlyContinue
|
$allKeys += Get-ChildItem -Path $root -Recurse -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
foreach ($key in $allKeys) {
|
foreach ($key in $allKeys) {
|
||||||
foreach ($valName in $key.GetValueNames()) {
|
foreach ($valName in $key.GetValueNames()) {
|
||||||
$val = $key.GetValue($valName)
|
|
||||||
$kind = $key.GetValueKind($valName)
|
$kind = $key.GetValueKind($valName)
|
||||||
|
if ($csvSafeTypes -notcontains [string]$kind) {
|
||||||
|
# Skip Binary / MultiString / None / Unknown. The .reg
|
||||||
|
# export already captured them losslessly.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
$val = $key.GetValue($valName)
|
||||||
$regCsvRows.Add([PSCustomObject]@{
|
$regCsvRows.Add([PSCustomObject]@{
|
||||||
Path = $key.PSPath
|
Path = $key.PSPath
|
||||||
Name = $valName
|
Name = $valName
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ $ErrorActionPreference = 'Continue'
|
|||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
$ApplicationSearchPaths = @(
|
$ApplicationSearchPaths = @(
|
||||||
|
# v6.213 vendor MSI layout (the path the per-bay install lands on today).
|
||||||
|
"${env:ProgramFiles(x86)}\MitutoyoApp"
|
||||||
|
"${env:ProgramFiles}\MitutoyoApp"
|
||||||
"${env:ProgramFiles}\Mitutoyo"
|
"${env:ProgramFiles}\Mitutoyo"
|
||||||
"${env:ProgramFiles(x86)}\Mitutoyo"
|
"${env:ProgramFiles(x86)}\Mitutoyo"
|
||||||
"${env:ProgramFiles}\FORMTRACEPAK"
|
"${env:ProgramFiles}\FORMTRACEPAK"
|
||||||
|
|||||||
@@ -91,6 +91,11 @@ $ErrorActionPreference = 'Continue'
|
|||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
$DefaultAppTargets = [ordered]@{
|
$DefaultAppTargets = [ordered]@{
|
||||||
|
# v6.213 vendor MSI installs under MitutoyoApp\Formtracepak\. Order this
|
||||||
|
# first so restored config under e.g. C:\Mitutoyo\Formtracepak\ from an
|
||||||
|
# older bay lands in the right tree on a freshly imaged v6.213 bay.
|
||||||
|
'MitutoyoAppX86' = "${env:ProgramFiles(x86)}\MitutoyoApp"
|
||||||
|
'MitutoyoApp' = "${env:ProgramFiles}\MitutoyoApp"
|
||||||
'ProgramFiles' = "${env:ProgramFiles}\Mitutoyo"
|
'ProgramFiles' = "${env:ProgramFiles}\Mitutoyo"
|
||||||
'ProgramFilesX86' = "${env:ProgramFiles(x86)}\Mitutoyo"
|
'ProgramFilesX86' = "${env:ProgramFiles(x86)}\Mitutoyo"
|
||||||
'CMitutoyo' = 'C:\Mitutoyo'
|
'CMitutoyo' = 'C:\Mitutoyo'
|
||||||
@@ -347,7 +352,13 @@ if ($RestoreRegistry) {
|
|||||||
$counters.RegistryKeys++
|
$counters.RegistryKeys++
|
||||||
}
|
}
|
||||||
|
|
||||||
# Method 2: CSV-based key-by-key restore
|
# Method 2: CSV-based key-by-key restore. CSV captures String /
|
||||||
|
# ExpandString / DWord / QWord only (Backup-FormtracepakSettings.ps1
|
||||||
|
# skips Binary + MultiString because [string] coercion corrupts them).
|
||||||
|
# The .reg file import above is authoritative for those types. Defend
|
||||||
|
# against older CSVs (pre-fix) that carry corrupt Binary/MultiString
|
||||||
|
# rows by skipping anything that is not a CSV-safe type.
|
||||||
|
$csvSafeTypes = @('String', 'ExpandString', 'DWord', 'QWord')
|
||||||
$regCsv = Join-Path $regDir 'registry_values.csv'
|
$regCsv = Join-Path $regDir 'registry_values.csv'
|
||||||
if (Test-Path $regCsv) {
|
if (Test-Path $regCsv) {
|
||||||
$regEntries = Import-Csv $regCsv
|
$regEntries = Import-Csv $regCsv
|
||||||
@@ -357,6 +368,12 @@ if ($RestoreRegistry) {
|
|||||||
$regValue = $re.Value
|
$regValue = $re.Value
|
||||||
$regType = $re.Type
|
$regType = $re.Type
|
||||||
|
|
||||||
|
if ($regType -and ($csvSafeTypes -notcontains $regType)) {
|
||||||
|
Write-Host " [SKIP] Non-CSV-safe type '$regType' at ${regPath}\$regName (the .reg file import handled it)" -ForegroundColor DarkGray
|
||||||
|
$counters.Skipped++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if ($regPath -match '^HKLM' -and -not $isAdmin -and -not $DryRun) {
|
if ($regPath -match '^HKLM' -and -not $isAdmin -and -not $DryRun) {
|
||||||
Write-Host " [SKIP] HKLM key requires elevation: $regPath\$regName" -ForegroundColor DarkYellow
|
Write-Host " [SKIP] HKLM key requires elevation: $regPath\$regName" -ForegroundColor DarkYellow
|
||||||
$counters.Skipped++
|
$counters.Skipped++
|
||||||
|
|||||||
Reference in New Issue
Block a user