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
|
||||
$counters[$CounterKey]++
|
||||
|
||||
$manifestRows.Add([PSCustomObject]@{
|
||||
RelativePath = $destRelPath
|
||||
OriginalPath = $f.FullName
|
||||
SizeBytes = $f.Length
|
||||
LastModified = $f.LastWriteTime.ToString('o')
|
||||
Hash = (Get-FileHash $f.FullName -Algorithm MD5 -ErrorAction SilentlyContinue).Hash
|
||||
})
|
||||
} 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]@{
|
||||
RelativePath = $destRelPath
|
||||
OriginalPath = $f.FullName
|
||||
SizeBytes = $f.Length
|
||||
LastModified = $f.LastWriteTime.ToString('o')
|
||||
Hash = $hash
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -212,9 +212,19 @@ function Restore-FileItem {
|
||||
}
|
||||
|
||||
if ((Test-Path $DestFile) -and -not $Force) {
|
||||
$srcHash = (Get-FileHash $SourceFile -Algorithm MD5).Hash
|
||||
$destHash = (Get-FileHash $DestFile -Algorithm MD5).Hash
|
||||
if ($srcHash -eq $destHash) {
|
||||
# SHA256 not MD5: MD5 throws under Windows FIPS policy
|
||||
# ("This implementation is not part of the Windows Platform FIPS
|
||||
# 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
|
||||
$counters.Skipped++
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user