用 sha256 校验 Windows 下载文件:从 EZA Modern LS 说起
我下载开源软件有个固定习惯:文件落到 Downloads 文件夹之后,先算一遍 SHA-256,再双击安装。这个习惯是被一次失败经历养成的------某个工具的下载页在 CDN 边缘节点上返回了半截文件,大小看着差不多,装到一半才报错。从那以后,哈希校验成了我流程里的第一步,而不是可选项。这篇就按我实际操作的顺序写,以 EZA Modern LS 这个 Windows 上的 ls 替代工具为例,把命令、失败场景和边界情况都过一遍。
先把文件放好,再谈校验
我一般会新建一个临时目录,避免和下载文件夹里的同名旧文件混淆:
powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\Downloads\verify" | Out-Null
Move-Item "$env:USERPROFILE\Downloads\eza-modern-ls*.zip" "$env:USERPROFILE\Downloads\verify\"
Get-ChildItem "$env:USERPROFILE\Downloads\verify\"
路径里带空格、带中文的情况我都遇到过,所以命令里一律用引号包住 $env:USERPROFILE 展开后的路径。文件名也确认一遍:如果下载页给的是 eza-modern-ls-v0.x.x-x86_64.zip,而你手里是浏览器自动加后缀的 eza-modern-ls (1).zip,那说明你之前下过一次,先删旧的再校验,否则很容易拿错文件去比对。
Windows 上的两种算法子:certutil 与 Get-FileHash
Windows 自带两条路。老系统、受限环境里我常用 certutil,它不需要 PowerShell:
cmd
certutil -hashfile "%USERPROFILE%\Downloads\verify\eza-modern-ls.zip" SHA256
输出是三行:第一行是算法名,第二行是哈希,第三行是完成提示。注意 certutil 默认输出大写十六进制,中间没有分隔符。
PowerShell 里我更倾向 Get-FileHash,因为它返回对象,方便脚本里继续处理:
powershell
$file = "$env:USERPROFILE\Downloads\verify\eza-modern-ls.zip"
$actual = (Get-FileHash -Path $file -Algorithm SHA256).Hash.ToLower()
$expected = "把下载页公布的哈希粘贴到这里".ToLower()
if ($actual -eq $expected) {
"OK $actual"
} else {
"MISMATCH"
"expected: $expected"
"actual : $actual"
}
两个细节值得说。第一,大小写:不同来源公布的哈希可能大小写混用,比较前统一转小写,省得肉眼比对时误判。第二,Get-FileHash 在 PowerShell 5.1 和 7.x 上都可用,但如果你的文件在 UNC 路径(\\server\share\...)上,先复制到本地再算,网络中断会让哈希计算直接抛异常。
校验失败时我按这个顺序排查
哈希对不上,先别急着怀疑被篡改。我遇到的绝大多数情况是下面几类:
文件没下完。 浏览器显示"已完成"不代表字节完整,尤其是断点续传之后。对比文件大小和下载页标注的大小,差几个 KB 就是没下完,重新下载即可 revoke 掉旧文件。
下错了版本。 同一个项目常有 x86_64、aarch64、portable、setup 多个包,哈希各不相同。看文件名里的架构标识,别拿 ARM 包的哈希去校验 x64 包。
多了一层解压。 有些站点公布的是压缩包内可执行文件的哈希,不是 zip 本身的哈希。这种情况要么先解压再对 .exeutu 算,要么去页面确认哈希对应的是哪一层。我在 EZA Modern LS 这类工具上就吃过这个亏,页面写的是归档文件哈希,我却解压后去算里面的 eza.exe。
复制粘贴带了空格或换行。 从网页复制哈希时,行尾常混入不可见字符。用 $expected.Trim() 清一下,或者干脆把哈希写进一个 .sha256 文件再读。
如果以上都排除,文件大小一致、来源可信、哈希仍然不符,那就不要运行它,删掉,换官方镜像或等一段时间重下。这不是过度谨慎,而是校验存在的意义。
边界情况:大文件、批量与自校验文件
单个几十 MB 的 zip,Get-FileHash 一两秒就完事。但如果是几个 GB 的镜像,计算期间会占满一个核,机械硬盘上还可能拖慢其他 IO。我的做法是放到后台任务里跑,前台继续干别的:
powershell
$job = Start-Job -ScriptBlock {
param($p)
(Get-FileHash -Path $p -Algorithm SHA256).Hash
} -ArgumentList "$env:USERPROFILE\Downloads\verify\eza-modern-ls.zip"
Wait-Job $job | Out-Null
Receive-Job $job
Remove-Job $job
批量校验时,很多项目会附带一个 SHA256SUMS 文件,格式是"哈希 + 两个空格 + 文件名"。PowerShell 没有内置的 sha256sum -c,我写了个小循环读它:
powershell
$dir = "$env:USERPROFILE\Downloads\verify"
Get-Content "$dir\SHA256SUMS" | ForEach-Object {
if ($_ -match '^([0-9a-fA-F]{64})\s+\*?(.+)$') {
$expected = $Matches[1].ToLower()
$name = $Matches[2].Trim()
$actual = (Get-FileHash -Path (Join-Path $dir $name) -Algorithm SHA256).Hash.ToLower()
"{0} {1}" -f ($(if ($actual -eq $expected) { "OK" } else { "FAIL" })), $name
}
}
这里有个坑:SHA256SUMS 里的文件名可能带 ./ 前缀或子目录,Join-Path 拼出来会找不到文件。遇到报错就先把文件列表打印出来,确认路径形态再改正则。
还有一种情况是工具自身提供校验子命令,比如某些安装器支持 --verify,但那属于工具行为,不能替代对下载文件本身的哈希计算------文件在运行前就已经可能被替换了。
相关资源
EZA Modern LS 的下载页和校验信息可以在 GitVaults 上找到,我一般直接从那里取公布的 SHA-256 值来比对:EZA Modern LS。下载后按上面的流程走一遍,再解压使用,整个过程不到一分钟,但能挡掉不少低级问题。
一点说明
以上命令都在 Windows 11 + PowerShell 7.4 和 Windows 10 + PowerShell 5.1 上实际跑过,certutil 部分在 cmd 里验证。如果你在 WSL 或 Git Bash 里习惯用 sha256sum,思路一样,只是比较逻辑换成 sha256sum -c。你在校验下载文件时遇到过哪些奇怪情况------比如哈希页和实际文件对不上、或者压缩包内文件哈希与归档哈希混用------欢迎补充,我会把常见场景整理进后续的实操笔记。