【bat】certutilでファイルのハッシュ値を取得・検証する完全ガイド|MD5・SHA1・SHA256・変数抽出・一括計算・改ざん検知まで徹底解説

ダウンロードしたインストーラーやzipファイルが改ざんされていないか確認するとき、配布元が提示するMD5やSHA1のハッシュ値と照合するのが定番の方法です。Windowsには追加インストール不要で使えるcertutilというツールが標準搭載されており、バッチファイルから簡単に呼び出せます。

本記事ではcertutil -hashfileの基本から、ハッシュ値の変数抽出・ダウンロードファイルの自動検証・フォルダ内一括計算・改ざん検知まで、実践で使えるレベルで体系的に解説します。

この記事で分かること

  • certutil -hashfileの基本構文と対応アルゴリズム(MD5・SHA1・SHA256等)
  • certutilの出力から純粋なハッシュ値だけを変数に取り出す方法
  • ダウンロードファイルのハッシュ値を期待値と自動照合する方法
  • フォルダ内の複数ファイルを一括処理してCSVに出力する方法
  • ファイルの改ざん検知への応用とPowerShellとの比較
スポンサーリンク

certutil -hashfileの基本構文

certutilはWindowsに標準搭載された証明書管理ツールですが、-hashfileオプションでファイルのハッシュ値計算にも使えます。

基本構文
rem 書式: certutil -hashfile <ファイルパス> <アルゴリズム>

certutil -hashfile "C:\download\setup.exe" MD5
certutil -hashfile "C:\download\setup.exe" SHA1
certutil -hashfile "C:\download\setup.exe" SHA256
実行例(コンソール表示)
C:\> certutil -hashfile "C:\download\setup.exe" SHA256
SHA256 ハッシュ (ファイル C:\download\setup.exe):
a3f5d2e1b4c6789012345678abcdef0123456789abcdef0123456789abcdef01
CertUtil: -hashfile コマンドは正常に完了しました。

出力は3行構造になっています。この構造を理解することが、ハッシュ値を変数に取り出す際の重要なポイントです。

内容
1行目 アルゴリズム名とファイルパスのヘッダー SHA256 ハッシュ (ファイル C:\...)
2行目 ハッシュ値本体(16進数) a3f5d2e1b4c6...
3行目 完了メッセージ CertUtil: -hashfile コマンドは正常に完了しました。

対応アルゴリズムの比較

certutilが対応するアルゴリズムとその特徴を整理します。

アルゴリズム ハッシュ長 用途 セキュリティ強度
MD5 128bit(32文字) 整合性チェック(レガシー互換) △ 衝突脆弱性あり
SHA1 160bit(40文字) 整合性チェック(レガシー互換) △ 理論的に破られている
SHA256 256bit(64文字) ダウンロード検証・現行標準 ◎ 現在推奨
SHA384 384bit(96文字) 高セキュリティ要件
SHA512 512bit(128文字) 高セキュリティ要件
MD5・SHA1を使うべきではないケース:MD5とSHA1は意図的に同じハッシュ値を持つ2つの異なるファイルを作成できる(衝突攻撃)ことが知られています。セキュリティ目的での使用は避け、新規実装ではSHA256以上を使ってください。 ただし既存システムや配布元がMD5/SHA1のみ提供している場合は、その値での照合に使うことは問題ありません。

ハッシュ値を変数に取り出す

certutilの出力3行のうち、必要なのは2行目のハッシュ値だけです。findstrfor /fを組み合わせて抽出します。

基本的な抽出方法

ハッシュ値を変数に格納
@echo off
setlocal enabledelayedexpansion

set "FILE=C:\download\setup.exe"

rem findstr /v でヘッダー行と完了メッセージ行を除外
rem "CertUtil" を含む行と "ハッシュ" を含む行を除外する
for /f "tokens=* delims=" %%H in (
    'certutil -hashfile "%FILE%" SHA256 ^| findstr /v "CertUtil" ^| findstr /v "SHA256"'
) do set "HASH=%%H"

echo SHA256: %HASH%

上記の方法はシンプルですが、環境によってヘッダー行の文言が変わる可能性があります。より安定した方法として、16進数の行だけを正規表現で抽出する方法を推奨します。

正規表現で16進数行だけを抽出する(推奨)

正規表現による安定した抽出
@echo off
setlocal enabledelayedexpansion

set "FILE=C:\download\setup.exe"

rem findstr /R で16進数のみの行を抽出
rem ^[0-9a-fA-F] で始まる行のみを対象にする
for /f "tokens=* delims=" %%H in (
    'certutil -hashfile "%FILE%" SHA256 ^| findstr /R "^[0-9a-fA-F]"'
) do set "SHA256=%%H"

rem MD5も同様に取得
for /f "tokens=* delims=" %%H in (
    'certutil -hashfile "%FILE%" MD5 ^| findstr /R "^[0-9a-fA-F]"'
) do set "MD5=%%H"

echo MD5   : %MD5%
echo SHA256 : %SHA256%
実行例(コンソール表示)
MD5   : d41d8cd98f00b204e9800998ecf8427e
SHA256 : e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
findstrの正規表現についてfindstr /R "^[0-9a-fA-F]"は「行頭が16進数文字で始まる行」を抽出します。ハッシュ値は16進数の連続した文字列なので、これでヘッダーと完了メッセージを除外できます。/Rは正規表現モードのオプションです。

ダウンロードファイルのハッシュ値を照合する

配布元が提示するハッシュ値と計算値を比較して、ファイルが改ざんされていないか自動確認します。

verify_hash.bat
@echo off
setlocal

set "FILE=C:\download\setup.exe"
rem 配布元が提示するSHA256値(すべて大文字に統一しておく)
set "EXPECTED=A3F5D2E1B4C6789012345678ABCDEF0123456789ABCDEF0123456789ABCDEF01"

rem ファイルが存在するか確認
if not exist "%FILE%" (
    echo [ERROR] ファイルが見つかりません: %FILE%
    exit /b 1
)

rem ハッシュ値を計算して変数に格納
for /f "tokens=* delims=" %%H in (
    'certutil -hashfile "%FILE%" SHA256 ^| findstr /R "^[0-9a-fA-F]"'
) do set "ACTUAL=%%H"

rem /I オプションで大文字小文字を区別せずに比較
if /I "%ACTUAL%"=="%EXPECTED%" (
    echo [OK] ハッシュ値が一致しました。ファイルは正常です。
    echo  計算値: %ACTUAL%
    exit /b 0
) else (
    echo [NG] ハッシュ値が一致しません!ファイルが破損または改ざんされている可能性があります。
    echo  期待値: %EXPECTED%
    echo  計算値: %ACTUAL%
    exit /b 1
)
実行例(コンソール表示)
rem 一致した場合
[OK] ハッシュ値が一致しました。ファイルは正常です。
 計算値: a3f5d2e1b4c6789012345678abcdef0123456789abcdef0123456789abcdef01

rem 不一致の場合
[NG] ハッシュ値が一致しません!ファイルが破損または改ざんされている可能性があります。
 期待値: A3F5D2E1B4C6789012345678ABCDEF0123456789ABCDEF0123456789ABCDEF01
 計算値: b8c7a9f0e5d4321098765432fedcba9876543210fedcba9876543210fedcba98
比較時は大文字小文字を統一する:certutilの出力は小文字ですが、配布元が大文字で提示する場合があります。if /Iで大文字小文字を無視した比較を行うか、あらかじめ大文字に統一しておきましょう。

フォルダ内のファイルを一括でハッシュ計算してCSVに出力する

配布パッケージ全体や監査対象フォルダのハッシュ値を一括で記録したい場合に使います。

batch_hash.bat
@echo off
setlocal enabledelayedexpansion

set "TARGET_DIR=C:\distribution"
set "ALG=SHA256"
set "OUT_CSV=hash_list_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.csv"

rem CSVヘッダー行を書き出し
echo "ファイルパス","%ALG%" > "%OUT_CSV%"

set COUNT=0
set ERRORS=0

for /r "%TARGET_DIR%" %%F in (*) do (
    set "HASH="
    for /f "tokens=* delims=" %%H in (
        'certutil -hashfile "%%~fF" %ALG% ^| findstr /R "^[0-9a-fA-F]"'
    ) do set "HASH=%%H"

    if defined HASH (
        echo "%%~fF","!HASH!" >> "%OUT_CSV%"
        set /a COUNT+=1
    ) else (
        echo [WARN] ハッシュ計算失敗: %%~fF
        set /a ERRORS+=1
    )
)

echo.
echo 完了: %COUNT% 件処理 / %ERRORS% 件失敗
echo 出力: %OUT_CSV%
出力CSVのイメージ
"ファイルパス","SHA256"
"C:\distribution\setup.exe","a3f5d2e1b4c6..."
"C:\distribution\readme.txt","e3b0c44298fc..."
"C:\distribution\lib\core.dll","7f83b1657ff1..."

ファイルの改ざん検知への応用

定期的にハッシュ値を記録しておき、次回実行時と比較することで、ファイルが変更されたかどうかを検知できます。設定ファイルや実行ファイルの不正な改ざんの早期発見に使えます。

tamper_detection.bat
@echo off
setlocal enabledelayedexpansion

set "FILE=C:\app\important_config.ini"
set "BASELINE=C:\app\config_hash_baseline.txt"

rem ===== 現在のハッシュ値を計算 =====
for /f "tokens=* delims=" %%H in (
    'certutil -hashfile "%FILE%" SHA256 ^| findstr /R "^[0-9a-fA-F]"'
) do set "CURRENT_HASH=%%H"

rem ===== ベースラインが存在しない場合は初回登録 =====
if not exist "%BASELINE%" (
    echo %CURRENT_HASH% > "%BASELINE%"
    echo [初回登録] ハッシュ値を記録しました: %CURRENT_HASH%
    exit /b 0
)

rem ===== ベースラインと比較 =====
set /p BASELINE_HASH= < "%BASELINE%"

if /I "%CURRENT_HASH%"=="%BASELINE_HASH%" (
    echo [正常] ファイルに変更はありません。
) else (
    echo [警告] ファイルが変更されました!
    echo  登録時: %BASELINE_HASH%
    echo  現在値: %CURRENT_HASH%
    rem タスクスケジューラから実行する場合はここでメール通知やログ記録も可能
    exit /b 1
)

certutil vs PowerShell Get-FileHash の比較

Windows 10以降ではPowerShellのGet-FileHashコマンドレットも使えます。どちらを使うべきか比較します。

項目 certutil PowerShell Get-FileHash
動作環境 Windows XP〜11(全バージョン) Windows 10以降(PS v4.0+)
起動速度 速い やや遅い(PS起動コスト)
出力形式 人間向けテキスト(要加工) 構造化オブジェクト(扱いやすい)
バッチからの呼び出し ネイティブ対応 powershell -Commandが必要
大文字/小文字 小文字で出力 大文字で出力
エラー処理 ERRORLEVEL確認で可能 Try-Catchで詳細制御可能
PowerShell Get-FileHashの例
rem PowerShellからGet-FileHashを呼び出す
powershell -Command "Get-FileHash -Path 'C:\download\setup.exe' -Algorithm SHA256 | Select-Object -ExpandProperty Hash"

rem バッチ変数に代入する場合
for /f %%H in ('powershell -Command "Get-FileHash -Path 'C:\download\setup.exe' -Algorithm SHA256 | Select-Object -ExpandProperty Hash"') do set "HASH=%%H"
結論古い環境への対応が必要な場合はcertutil、Windows 10以降で複雑なハッシュ処理が必要な場合はPowerShellが適しています。単純なハッシュ取得はcertutilの方が起動が速く記述も短くなります。

よくある落とし穴と対処法

落とし穴①:ハッシュ値に余分なスペースが入る

certutilの出力によっては、ハッシュ値の前後にスペースが含まれる場合があります。変数に取り込む際にdelims=オプションを付けて対処します。

NG: スペースが残る可能性あり
for /f %%H in ('certutil -hashfile "%FILE%" MD5 ^| findstr /R "^[0-9a-fA-F]"') do set "HASH=%%H"
rem ↑ tokens未指定の場合スペース区切りで最初のトークンのみ取得
OK: 行全体をそのまま取得
for /f "tokens=* delims=" %%H in ('certutil -hashfile "%FILE%" MD5 ^| findstr /R "^[0-9a-fA-F]"') do set "HASH=%%H"
rem ↑ "tokens=* delims=" で行全体を1つのトークンとして取得

落とし穴②:ファイルパスにスペースが含まれている

NG: スペース含みパスでエラー
certutil -hashfile C:\My Documents\setup.exe SHA256
rem → 'C:\My' が引数1、'Documents\setup.exe' が引数2と解釈される
OK: ダブルクォートで囲む
certutil -hashfile "C:\My Documents\setup.exe" SHA256

落とし穴③:大きなファイルで時間がかかる

数GBのファイルではハッシュ計算に数分かかることがあります。ネットワークドライブ上のファイルはまずローカルにコピーしてから計算すると速くなります。また処理中に進捗表示はできないため、タイムアウト対策が必要な場面では注意してください。

大きなファイルの対処
rem ネットワークドライブ上の大きなファイルは先にコピー
set "REMOTE_FILE=\\server\share\large_backup.zip"
set "LOCAL_COPY=%TEMP%\hash_target.tmp"

echo コピー中...
copy /y "%REMOTE_FILE%" "%LOCAL_COPY%" >nul
if %ERRORLEVEL% neq 0 (
    echo [ERROR] コピー失敗
    exit /b 1
)

echo ハッシュ計算中...
for /f "tokens=* delims=" %%H in (
    'certutil -hashfile "%LOCAL_COPY%" SHA256 ^| findstr /R "^[0-9a-fA-F]"'
) do set "HASH=%%H"

rem 一時ファイルを削除
del /f "%LOCAL_COPY%" >nul 2>&1

echo SHA256: %HASH%

落とし穴④:certutil コマンドが見つからないエラー

certutilはシステムコマンドですが、PATH設定が壊れている環境では見つからないことがあります。フルパスで指定すれば確実に動作します。

フルパスで確実に呼び出す
rem certutil のフルパス(通常この場所に存在する)
set "CERTUTIL=%SystemRoot%\System32\certutil.exe"

if not exist "%CERTUTIL%" (
    echo [ERROR] certutil.exe が見つかりません
    exit /b 1
)

"%CERTUTIL%" -hashfile "%FILE%" SHA256

完全な実践テンプレート

ダウンロードファイルの検証に使える、エラー処理付きの完全版テンプレートです。

verify_download.bat
@echo off
setlocal

rem ===== 設定(ここを変更)=====
set "FILE=C:\download\setup.exe"
set "ALG=SHA256"
rem 配布元から取得したハッシュ値(大文字・小文字どちらでも可)
set "EXPECTED=a3f5d2e1b4c6789012345678abcdef0123456789abcdef0123456789abcdef01"

rem ===== 前提チェック =====
if not exist "%FILE%" (
    echo [ERROR] ファイルが見つかりません: %FILE%
    exit /b 1
)

rem ===== ハッシュ計算 =====
echo %ALG%ハッシュを計算中: %FILE%
for /f "tokens=* delims=" %%H in (
    'certutil -hashfile "%FILE%" %ALG% ^| findstr /R "^[0-9a-fA-F]"'
) do set "ACTUAL=%%H"

if not defined ACTUAL (
    echo [ERROR] ハッシュ計算に失敗しました。
    exit /b 1
)

rem ===== 照合 =====
echo 期待値: %EXPECTED%
echo 計算値: %ACTUAL%
echo.

if /I "%ACTUAL%"=="%EXPECTED%" (
    echo [OK] 検証成功: ファイルは正常です。
    exit /b 0
) else (
    echo [NG] 検証失敗: ファイルが破損または改ざんされている可能性があります。
    exit /b 1
)

関連記事

よくある質問

Q. certutilでSHA512も計算できますか?
A. はい、certutil -hashfile "ファイル名" SHA512で計算できます。Windows Vista以降で対応しており、その他にもSHA1・SHA256・SHA384などが使えます。MD2・MD4・MD5はレガシーアルゴリズムとして対応しています。
Q. 複数のファイルのハッシュ値を一度に取得してリスト化できますか?
A. for /r %%F in (*) doのループで複数ファイルを順番に処理し、結果をCSVに書き出す方法を本記事で紹介しています。ただしcertutilはファイルを1件ずつ処理するため、ファイル数が多い場合は時間がかかります。
Q. ハッシュ値の比較で大文字小文字の違いはありますか?
A. ハッシュ値の16進数表現は大文字と小文字は等価です。certutilは小文字で出力しますが、配布元が大文字で提供するケースもあります。比較にはif /I(大文字小文字を無視)を使うか、あらかじめどちらかに統一してください。PowerShellの(Get-FileHash ...).Hashは大文字で返します。
Q. certutilを使わずにバッチファイルだけでハッシュ値を計算することはできますか?
A. バッチファイル単体でのハッシュ計算は現実的ではありません。certutilかPowerShellのGet-FileHashを使うのが標準的なアプローチです。古い環境(Windows XP/Vista)ではFCSIV.exe(File Checksum Integrity Verifier、Microsoftが無料配布)も選択肢になります。
Q. 改ざん検知として使う場合、どのアルゴリズムを選ぶべきですか?
A. セキュリティ目的での改ざん検知にはSHA256以上を推奨します。MD5やSHA1は衝突脆弱性があり、悪意を持って同じハッシュ値を持つ別のファイルを作れることが知られています。単純なファイル変更検知(意図的な攻撃を想定しない場合)であればSHA1でも実用上は問題ありませんが、新規実装ではSHA256を使う習慣をつけておくことを推奨します。