Wax/Trace triad: switch to SHA256 hashes (FIPS-compliant) + separate hash-failure path from copy-failure path
Backup-FormtracepakSettings observed 17 Errors on a real shopfloor PC (G5PRTW04ESF / WJF00159 capture) - all of the form: WARNING: Failed to copy ...App.ini: Exception calling ".ctor" with "0" argument(s): "This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms." Cause: Windows FIPS policy is enabled on West Jefferson shopfloor PCs. The per-file Get-FileHash -Algorithm MD5 call throws a hard .NET exception that bypasses -ErrorAction SilentlyContinue (the throw is from the MD5 constructor, not the cmdlet's parameter binder). That exception was caught by the broad try/catch around both Copy-Item + manifest add, producing a misleading "Failed to copy" message even though Copy-Item already succeeded. Net effect: files copied fine, but manifest rows were missing for those files (Install would fall back to its bulk-copy path). Two fixes: - Switch the hash algorithm from MD5 to SHA256 in both Backup (manifest row capture) and Install (Restore-FileItem hash-skip compare). SHA256 is Get-FileHash's default and is FIPS-compliant. Old MD5-hashed backups remain restorable because Install computes hashes fresh from disk at restore time and does not read the Hash column from file_manifest.csv. - Split the broad try/catch in Backup's Copy-ToStaging into two try/catches: the first wraps only Copy-Item (real copy failure -> Errors counter + skip the file), the second wraps only Get-FileHash (hash failure -> log warning, manifest row gets a null Hash and is still recorded). A hash failure no longer pretends the copy failed. - Install's hash compare is wrapped in try/catch too so a hash exception falls through to overwrite-mode rather than crashing the restore. Smoke tested on win11 VM: SHA256 round-trip works (64-char hashes in file_manifest.csv), Backup reports 0 Errors, Install hash-skip path correctly skips Identical files on second-run idempotency check.
This commit is contained in:
@@ -221,18 +221,32 @@ function Copy-ToStaging {
|
|||||||
}
|
}
|
||||||
Copy-Item -Path $f.FullName -Destination $destFull -Force
|
Copy-Item -Path $f.FullName -Destination $destFull -Force
|
||||||
$counters[$CounterKey]++
|
$counters[$CounterKey]++
|
||||||
|
} catch {
|
||||||
|
Write-Warning " Failed to copy $($f.FullName): $_"
|
||||||
|
$counters.Errors++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# Hash computation runs in its own try so a hash failure (e.g. FIPS
|
||||||
|
# policy banning MD5, missing file, permission) does NOT roll back
|
||||||
|
# the copy we just succeeded at. SHA256 is the default and is
|
||||||
|
# FIPS-compliant; older Backup runs may have written MD5 hashes
|
||||||
|
# into file_manifest.csv but Install never reads those - it computes
|
||||||
|
# fresh hashes at restore time for the [SKIP] Identical check.
|
||||||
|
$hash = $null
|
||||||
|
try {
|
||||||
|
$hash = (Get-FileHash -LiteralPath $f.FullName -Algorithm SHA256 -ErrorAction Stop).Hash
|
||||||
|
} catch {
|
||||||
|
Write-Warning " Hash skipped for $($f.FullName): $_"
|
||||||
|
}
|
||||||
|
|
||||||
$manifestRows.Add([PSCustomObject]@{
|
$manifestRows.Add([PSCustomObject]@{
|
||||||
RelativePath = $destRelPath
|
RelativePath = $destRelPath
|
||||||
OriginalPath = $f.FullName
|
OriginalPath = $f.FullName
|
||||||
SizeBytes = $f.Length
|
SizeBytes = $f.Length
|
||||||
LastModified = $f.LastWriteTime.ToString('o')
|
LastModified = $f.LastWriteTime.ToString('o')
|
||||||
Hash = (Get-FileHash $f.FullName -Algorithm MD5 -ErrorAction SilentlyContinue).Hash
|
Hash = $hash
|
||||||
})
|
})
|
||||||
} catch {
|
|
||||||
Write-Warning " Failed to copy $($f.FullName): $_"
|
|
||||||
$counters.Errors++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,9 +212,19 @@ function Restore-FileItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((Test-Path $DestFile) -and -not $Force) {
|
if ((Test-Path $DestFile) -and -not $Force) {
|
||||||
$srcHash = (Get-FileHash $SourceFile -Algorithm MD5).Hash
|
# SHA256 not MD5: MD5 throws under Windows FIPS policy
|
||||||
$destHash = (Get-FileHash $DestFile -Algorithm MD5).Hash
|
# ("This implementation is not part of the Windows Platform FIPS
|
||||||
if ($srcHash -eq $destHash) {
|
# validated cryptographic algorithms"). SHA256 is FIPS-compliant
|
||||||
|
# and is Get-FileHash's default.
|
||||||
|
$srcHash = $null
|
||||||
|
$destHash = $null
|
||||||
|
try {
|
||||||
|
$srcHash = (Get-FileHash -LiteralPath $SourceFile -Algorithm SHA256 -ErrorAction Stop).Hash
|
||||||
|
$destHash = (Get-FileHash -LiteralPath $DestFile -Algorithm SHA256 -ErrorAction Stop).Hash
|
||||||
|
} catch {
|
||||||
|
Write-Warning " Hash compare failed for ${DestFile}: $_ - falling through to overwrite"
|
||||||
|
}
|
||||||
|
if ($srcHash -and $destHash -and $srcHash -eq $destHash) {
|
||||||
Write-Host " [SKIP] Identical: $DestFile" -ForegroundColor DarkGray
|
Write-Host " [SKIP] Identical: $DestFile" -ForegroundColor DarkGray
|
||||||
$counters.Skipped++
|
$counters.Skipped++
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user