同じ名前のファイルは同じ中身?PowerShellでSHA-256を比較する

PowerShellカテゴリを表すパンダのイラスト PowerShell

この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。PowerShellと.NETの公式仕様を根拠に、ファイルのSHA-256を読み取り専用で比較する手順を整理しました。

検証ステータス:📘 公式仕様に基づく解説・Windows実機未確認

同じ名前のファイルは同じ中身?PowerShellでSHA-256を比較する

同じファイル名でも安心できない

メールで受け取った報告書を保存したところ、昨日の報告書と同じファイル名だった。更新版のはずなのにサイズも似ている。こんなとき、ファイル名だけを比較しても内容の同一性は分からない。ファイル名は人が付ける目印であり、ファイルの中身そのものではないからだ。更新日時もコピーや保存操作で変化するため、内容が同じかどうかを判断する決定打にはならない。

そこで使えるのがSHA-256というハッシュ関数だ。ファイルを構成するバイト列から256ビットの値を計算し、通常は64桁の16進数で表示する。二つのファイルのハッシュ値が異なれば、その二つのバイト列は異なる。値が一致すれば同じ内容である可能性は非常に高い。ただし数学的に完全一致を保証するものではなく、悪意のある相手から受け取るファイルの真正性を保証する仕組みでもない。この違いが、業務で使うときの重要な境界になる。

まずは架空のデータを安全に試す

WindowsのPowerShell 7、またはWindows PowerShell 5.1で、個人情報を含まない小さなテキストを使う。以下は一時フォルダに新しいサンプルを作成する手順であり、既存の業務ファイルを変更するものではない。PowerShellで次のコードを一行ずつ確認して実行する。保存先に同名のファイルが存在する場合は上書きされるため、専用の新しいフォルダを使う。

$dir = Join-Path ([System.IO.Path]::GetTempPath()) 'papanda-hash-demo-20261109'
[System.IO.Directory]::CreateDirectory($dir) | Out-Null
$a = Join-Path $dir 'report-a.txt'
$b = Join-Path $dir 'report-b.txt'
$utf8 = [System.Text.UTF8Encoding]::new($false)
[System.IO.File]::WriteAllText($a, '備品: 机 3台', $utf8)
[System.IO.File]::WriteAllText($b, '備品: 机 3台', $utf8)
Get-FileHash -LiteralPath $a -Algorithm SHA256
Get-FileHash -LiteralPath $b -Algorithm SHA256

ここで観察するのは、表示されたPathではなくHash列だ。二つのパスは異なるが、書き込んだ文字列も文字コードも同じなので、ハッシュ値は一致するはずだ。これは期待結果であり、ここでWindows上の実行結果を取得したわけではない。ハッシュの値を記事に固定していないのは、読者自身が出力を確認するためである。

この実験では文字列をUTF-8のBOMなしで書いている。BOMとはファイル先頭に付くことがある符号で、見た目が同じ文字列でもBOMの有無が違えばバイト列は異なる。ハッシュは文字の意味ではなくバイトを対象にするため、文字コードの指定をそろえることが比較の前提になる。PowerShellのバージョンによってテキスト出力コマンドの既定文字コードが異なることがあるので、.NETの書き込みAPIを使って条件を固定した。

一文字だけ変えて比較する

次はbだけの台数を変更する。aを変更しないことが比較実験の要点だ。変更後に同じコマンドを実行すると、Hash列が異なることを期待できる。ハッシュ値の一部だけが変わるのではなく、全体が大きく変化し得る点にも注目したい。

[System.IO.File]::WriteAllText($b, '備品: 机 4台', $utf8)
(Get-FileHash -LiteralPath $a -Algorithm SHA256).Hash
(Get-FileHash -LiteralPath $b -Algorithm SHA256).Hash

たった一文字の変更でも異なるハッシュが得られるのは、SHA-256が入力全体を混ぜ合わせて固定長の値を生成するからだ。逆に、ハッシュ値を見ただけでは、何文字目が変わったのか、机の台数が増えたのか減ったのかは分からない。ハッシュは差分を表示する道具ではなく、差分の存在を検出する道具と理解すると使い分けやすい。

処理の流れを図で読む

図の左側はファイルの内容、中央はSHA-256計算、右側は値の比較を示す。ファイル名や更新日時ではなく、読み込んだバイト列を基準に判断する点が重要だ。

flowchart LR
    A[ファイルAのバイト列] --> C[SHA-256計算]
    B[ファイルBのバイト列] --> D[SHA-256計算]
    C --> E{ハッシュ値は一致?}
    D --> E
    E -->|いいえ| F[内容は異なる]
    E -->|はい| G[同じ内容の可能性が極めて高い]

この図は計算結果の意味を表しており、暗号署名の検証や送信者の認証までは表していない。ハッシュが一致したとしても、攻撃者がファイルとそのハッシュ値を一緒に差し替えられる状況では安全性の証拠にならない。信頼できる配布元が別経路で公開したハッシュ値と照合する場合と、同じメールに添付されたハッシュ値を信じる場合では、確認の強さが異なる。

失敗したときはどこを見るか

ファイルが存在しない場合、Get-FileHashはハッシュ値を返せない。まずLiteralPathの文字列と実際のファイルの場所を確認する。ファイルが別のアプリケーションで排他的に開かれている場合やアクセス権が不足している場合にも読み取りが失敗することがある。失敗したのに空欄を一致と判定しないよう、業務用スクリプトではエラーを明示的に扱う必要がある。

もう一つの落とし穴は、テキストを見た目で比較する場合だ。WindowsのCRLFとUnix系のLFは、画面上では同じ改行に見えることがあるが、バイト列は違う。UTF-8とUTF-16も同じ日本語を表現できるが、ファイルのバイト列は異なる。ハッシュが違ったからといって文章の意味まで違うとは限らない。文章としての差を知りたいなら、文字コードと改行を正規化した後に差分比較する別の処理が必要になる。ただし原本の完全性を調べる場面では、正規化によって元の差異を隠さない方がよい。

実務でどう使い分けるか

バックアップの複製確認、配布前後のファイル照合、同名ファイルの取り違え防止ではハッシュが便利だ。例えば担当者が作成したCSVを別フォルダへコピーした後、コピー元とコピー先のSHA-256を比較すれば、少なくとも読み取った内容が一致するかを確認できる。作業記録には対象パス、比較日時、アルゴリズム、一致・不一致、エラーの有無を残すと再現性が高まる。ただし業務ファイルの中身や個人情報をログへ丸ごと出力する必要はない。

ファイルが書き込み中に変化すると、比較した時点の状態が曖昧になる。処理前にファイルを確定させ、必要なら読み取り専用のスナップショットやコピーを対象にする。また、二つのファイルが同じ内容かという問いと、そのファイルが正しい発行元から届いたかという問いは分ける。後者には署名検証や信頼できる経路でのハッシュ照合など、別の確認が必要だ。

大量のファイルを比較する場合は、まずファイルの列挙範囲と権限を限定する。ハッシュ計算はファイルの全体を読むので、巨大なバックアップを何度も走査するとディスクI/Oを消費する。更新日時やサイズで候補を絞ることは性能上の工夫として有効だが、最終的な同一性判断をそれだけで済ませることとは違う。比較の目的に応じて、性能と確認精度のバランスを取る。

まとめ

同じ名前や同じサイズのファイルでも、同じ中身とは限らない。SHA-256を使うと、バイト列の差異を手軽に検出できる。最初は同じ文字列の二つのファイルで一致を観察し、次に一文字だけ変更して不一致を確認すると、ハッシュの役割が分かりやすい。文字コード・改行・読み取り失敗・処理中の変更・配布元の真正性は別々に考え、必要な確認を組み合わせることが実務では大切だ。

公式資料

  • Microsoft Learn: Get-FileHash https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-filehash

  • Microsoft Learn: UTF8Encoding https://learn.microsoft.com/en-us/dotnet/api/system.text.utf8encoding

  • NIST: Secure Hash Standard (FIPS 180-4) https://csrc.nist.gov/pubs/fips/180-4/upd1/final

文書情報

記事タイトル
同じ名前のファイルは同じ中身?PowerShellでSHA-256を比較する
作成日
更新日
Source URL
https://papanda925.com/?p=18577

ライセンス: 本記事のうち、当サイトが権利を有する本文・自作図表は、特記なき限り CC BY 4.0 で利用できます。生成AIを活用して作成・編集した内容を含みます。コードについて、別途ライセンス表示またはリンク先GitHubリポジトリのライセンスがある場合は、その条件を優先します。引用・第三者資料・画像・商標等は本ライセンスの対象外です。 利用ポリシー

タイトルとURLをコピーしました