Capture-MclCache: robocopy to Z: and verify by hash instead of zipping

This commit is contained in:
cproudlock
2026-10-18 09:31:04 -04:00
parent 902ce5780a
commit 716d4eee6b

View File

@@ -19,11 +19,16 @@
files\ copies of the small text files (*.json, *.xml,
*.tag, *.txt, *.ini, *.log, *.cmd, *.ps1, *.bat)
under 5 MB, same relative paths
mcl-capture-<label>-<timestamp>.zip
SHA256SUMS hash of every file above, for checking the copy
Then it robocopies that folder to -CopyTo (default Z:\mcl-capture, the
dev box pxe-images share), hashes every copied file back through the
share and compares with SHA256SUMS. No zip: archives arrive empty on
that share. The dev box can re-check with: sha256sum -c SHA256SUMS
Nothing large is copied: no WIM, driver, MSU or installer. Text copies
have any Azure SAS signature (sig=...) blanked, so the zip carries no
storage credential. Read-only on the cache; needs no admin rights.
have any Azure SAS signature (sig=...) blanked, so the capture carries
no storage credential. Read-only on the cache; needs no admin rights.
.PARAMETER Label
Short name for this run, for example pro or ltsc.
@@ -34,11 +39,16 @@
.PARAMETER OutDir
Where to write the capture. Default: the current user's Desktop, or
this script's folder when there is no Desktop.
.PARAMETER CopyTo
Folder to copy the capture into and verify. Default Z:\mcl-capture.
Pass -CopyTo none to keep it on this PC only.
#>
param(
[Parameter(Mandatory = $true)][ValidatePattern('^[A-Za-z0-9_-]{1,20}$')][string]$Label,
[string]$Root = "C:\ProgramData\GEAerospace\MediaCreator",
[string]$OutDir = [Environment]::GetFolderPath("Desktop")
[string]$OutDir = [Environment]::GetFolderPath("Desktop"),
[string]$CopyTo = "Z:\mcl-capture"
)
$ErrorActionPreference = "Stop"
if (-not $OutDir) { $OutDir = $PSScriptRoot } # no Desktop (e.g. run as SYSTEM)
@@ -146,8 +156,13 @@ if ($skippedBig.Count) {
}
$sum | Set-Content -LiteralPath (Join-Path $dest "summary.txt") -Encoding UTF8
$zip = "$dest.zip"
Compress-Archive -Path (Join-Path $dest "*") -DestinationPath $zip -Force
# Relative path with forward slashes, the way sha256sum -c reads it.
function Get-RelPath($full, $base) { $full.Substring($base.Length + 1).Replace('\', '/') }
$sumLines = foreach ($f in (Get-ChildItem -LiteralPath $dest -Recurse -File | Sort-Object FullName)) {
"$((Get-FileHash -LiteralPath $f.FullName -Algorithm SHA256).Hash.ToLower()) $(Get-RelPath $f.FullName $dest)"
}
[System.IO.File]::WriteAllText((Join-Path $dest "SHA256SUMS"), (($sumLines -join "`n") + "`n"))
Write-Host ""
Write-Host "Captured $($all.Count) files ($copied text files copied)." -ForegroundColor Green
@@ -157,4 +172,45 @@ if ($tags.Count -eq 0) {
if ($unreadable.Count) {
Write-Host "$($unreadable.Count) file(s) could not be read; listed in summary.txt." -ForegroundColor Yellow
}
Write-Host "Send back: $zip"
Write-Host "Capture folder: $dest"
if (-not $CopyTo -or $CopyTo -eq "none") { exit 0 }
$drive = Split-Path -Qualifier $CopyTo -ErrorAction SilentlyContinue
if (($drive -and -not (Test-Path -LiteralPath "$drive\")) -or -not (Test-Path -LiteralPath (Split-Path $CopyTo -Parent))) {
Write-Host ""
Write-Host "$CopyTo is not reachable, so nothing was copied." -ForegroundColor Yellow
Write-Host "Map Z: to the dev box pxe-images share and run again, or copy the folder above by hand."
exit 1
}
$target = Join-Path $CopyTo (Split-Path $dest -Leaf)
Write-Host ""
Write-Host "Copying to $target ..."
& robocopy.exe $dest $target /E /COPY:DT /R:2 /W:5 /NP /NFL /NDL /NJH /NJS | Out-Null
$rc = $LASTEXITCODE
if ($rc -ge 8) {
Write-Host "Copy FAILED (robocopy exit $rc)." -ForegroundColor Red
exit 2
}
# Read every file back through the share and compare with SHA256SUMS.
$bad = New-Object System.Collections.Generic.List[string]
foreach ($line in $sumLines) {
$hash = $line.Substring(0, 64)
$rel = $line.Substring(66)
$copy = Join-Path $target ($rel.Replace('/', '\'))
if (-not (Test-Path -LiteralPath $copy -PathType Leaf)) { $bad.Add("missing $rel"); continue }
$got = (Get-FileHash -LiteralPath $copy -Algorithm SHA256).Hash.ToLower()
if ($got -ne $hash) { $bad.Add("differs $rel ($((Get-Item -LiteralPath $copy).Length) bytes)") }
}
if ((Get-FileHash -LiteralPath (Join-Path $target "SHA256SUMS") -Algorithm SHA256).Hash -ne
(Get-FileHash -LiteralPath (Join-Path $dest "SHA256SUMS") -Algorithm SHA256).Hash) {
$bad.Add("differs SHA256SUMS")
}
if ($bad.Count) {
Write-Host "Copy NOT verified: $($bad.Count) of $($sumLines.Count + 1) files wrong." -ForegroundColor Red
foreach ($b in $bad) { Write-Host " $b" }
exit 2
}
Write-Host "Copied and verified: all $($sumLines.Count + 1) files match." -ForegroundColor Green
Write-Host "On the share: $target"