用 PowerShell 校验文件的 SHA-256:匹配与失败处理
下载完安装包后,仅凭文件名或“下载成功”无法判断文件内容是否与发布方公布的一致。PowerShell 自带 Get-FileHash,可以在运行或解压之前先做比对。下面只用本地临时文件模拟下载结果,没有联网,也没有使用云产品。测试环境为 Windows 11、PowerShell 7.6.7。
示例先写入三个 ASCII 字节 abc(不含换行和 BOM),使用 abc 的已知 SHA-256 值比较;然后把内容改成 abd,仍用原来的期望值。目录名含随机 GUID,清理时只删除本次创建的目录。复制到 PowerShell 7 执行:
function Assert-FileSha256 {
param([string]$Path, [string]$Expected)
$Expected = $Expected.Trim()
if ($Expected -notmatch '^[0-9a-fA-F]{64}$') {
throw '期望值不是 64 位十六进制 SHA-256'
}
$actual = (Get-FileHash -LiteralPath $Path -Algorithm SHA256 -ErrorAction Stop).Hash
if ($actual -ine $Expected) {
throw "哈希不一致:$actual"
}
"校验通过:$actual"
}
# 已知测试向量,实际使用时应改为可信渠道公布的值。
$expected = 'BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD'
$dir = Join-Path ([IO.Path]::GetTempPath()) ('sha256-demo-' + [guid]::NewGuid().ToString('N'))
$created = $false
try {
New-Item -ItemType Directory -Path $dir -ErrorAction Stop | Out-Null
$created = $true
$file = Join-Path $dir 'download.bin'
[IO.File]::WriteAllBytes($file, [Text.Encoding]::ASCII.GetBytes('abc'))
Assert-FileSha256 -Path $file -Expected $expected
[IO.File]::WriteAllBytes($file, [Text.Encoding]::ASCII.GetBytes('abd'))
try {
Assert-FileSha256 -Path $file -Expected $expected
} catch {
"已阻止:$($_.Exception.Message)"
}
} finally {
if ($created) {
Remove-Item -LiteralPath $dir -Recurse -Force -ErrorAction Stop
"临时目录已清理:$(-not (Test-Path -LiteralPath $dir))"
}
}
实际输出如下:
校验通过:BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD
已阻止:哈希不一致:A52D159F262B2C6DDB724A61840BEFC36EB30C88877A4030B65CBE86298449C9
临时目录已清理:True
函数先检查期望值是否为 64 位十六进制,再计算文件的 SHA-256;-ine 不区分字母大小写。-LiteralPath 把方括号等字符按路径字面处理;-ErrorAction Stop 让读取失败成为可捕获的终止错误。失败时抛出异常,本例为了展示第二种结果才捕获异常并打印“已阻止”,实际上没有尝试安装或解压。
校验比较的是字节,不看文件名或后缀。同名的不同版本、下载中断后留下的不完整文件,都可能得到不同的哈希,但哈希本身不能告诉你原因。要校验最终准备使用的那个文件,别把解压后文件的哈希与压缩包的期望值混在一起。大文件需要完整读取一次,网络盘上的耗时也取决于读取速度。
要用于真实下载,先从可信的发布方渠道取得对应文件、版本和架构的期望哈希;不要从待检查文件自己算一个值再与自己比较。如果文件和哈希都来自被篡改的来源,两者即使一致也不能证明可信。发布方提供数字签名时,还应按其说明验证签名。哈希一致也不代表软件无恶意,校验后还应避免文件在使用前被替换。
校验不一致时不要继续执行该文件,先检查路径、版本和期望值来源,再从可信渠道重新获取。示例的 catch 只是为了演示,并没有主动设置非零进程退出码。在真正的自动化脚本中不要吞掉异常,应在入口处报告错误、使用非零退出码并停止后续步骤。
本文由 Hermes AI 助手协助编写和实际测试。
- 点赞
- 收藏
- 关注作者
评论(0)