ファイルの変更を検知する時に一般的に行われるのが ハッシュ値の比較です。ファイルの変更検知はすなわち改ざんがないか、ファイルが更新されてないかなど、あいまいではない変化の検知を意味するのでこういうのって大事です。*1
日付やファイル名での判断ダメ、絶対。
例えば、MySQL などをダウンロードしようとすると、ダウンロードリンクそばに ハッシュ値がありますよね?ダウンロードされたものがこの値と一致していない場合は改ざんがあったことを気づけるわけです。
今回は、PowerShell v3 *2、あるいは v4 で標準のCmdletより便利にファイルハッシュを取得するための関数の紹介です。
目次
Linux でのハッシュ値確認
Linux では、openssl のopenssl sha1
であったり、md5sum
や sha1sum
、shasum
、sha224sum
、sha256sum
、sha384sum
、sha512sum
とまぁはい。ふつーに一般的な標準環境ですぐに確認できます。
便利、簡単。
Windows でのハッシュ値確認
翻って Windows ではというと、Windows 8.1 / 2012 R2 で標準となった PowerShell v4 までは標準でファイルハッシュを確認するユーティリティは提供されていませんでした。PowerShell v3では標準でCmdletがないんですね。
実際には、.NET から叩けば簡単ですが、コマンドラインでさくっと使いたいという時に、以前は cmd や PowerShell でサポートされておらず悲しい思いをすることが多かったです。
cmd での確認
File Checksum Integrity Verifier (FCIV) を使う人が多いようですね。
今使う人がいるかは知りません。私も使ったことありません()
PowerShell v4 から標準Cmdletの提供
さてPowerShell v4 には、Get-FileHash
という Cmdlet が追加されています。
これを使うことで、ファイルのハッシュ値をmd5 や sha1、sha256 など、各種アルゴリズムで算出できる便利さんです。
但し、以下のように Path に [String[]] を渡さないと自身では 再帰的(Recursive)にファイルを検知してくれないのでめんどくさいです。*3
つまりパイプラインで渡すか、
Get-ChildItem -Recurse -File | Get-FileHash
変数をパラメータで渡すかです。
$file = Get-ChildItem -Recurse -File Get-FileHash -Path $file.FullName
取得結果は、利用されたアルゴリズムとハッシュ値、パスをプロパティに持っているので操作も容易ですね。
Algorithm Hash Path --------- ---- ---- SHA256 7D5D4F18A97D8E4A16EC6432094F708C7CA558349D6D2C78DBB19FB771354289 D:\GitHub\Pow... SHA256 875CF5087260F2A5CB4F37632A34F6730D0F81D3A4E68B3663A1B72B08A20735 D:\GitHub\Pow... SHA256 F78E66EEA3E67912EB2F2ED7BAE499BEEEE86F1C3001B0BDCE6B4217059ECC12 D:\GitHub\Pow... SHA256 FE37E4F26DFAFFF8146AEF8516B91083DE8A904A14AA7DA33710CC8778BAEDEB D:\GitHub\Pow... SHA256 F4A0896AAF8E71A539503EE0EB27BD8CC0B0ABE449A12A55F61A6F5030B21BCF D:\GitHub\Pow...
リスト表示するとこうですね。
Algorithm : SHA256 Hash : 7D5D4F18A97D8E4A16EC6432094F708C7CA558349D6D2C78DBB19FB771354289 Path : D:\GitHub\PowerShellUtil\.gitattributes
PowerShell v3 でファイルのハッシュ値を確認したい
はい。.NET を使ってください。。単純に C# で書くのをPowerShell に移植すれば okです。
かき捨てだとこんな感じでしょうか。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Security.Cryptography; namespace ConsoleApplication4 { class Program { static void Main(string[] args) { if (args.Length == null) throw new ArgumentNullException(); var file = args[0]; var hash = GetFileHash(file); Console.WriteLine(hash); Console.ReadLine(); } static string GetFileHash(string file) { using (FileStream stream = File.OpenRead(file)) { SHA256Managed sha = new SHA256Managed(); byte[] hash = sha.ComputeHash(stream); return BitConverter.ToString(hash).Replace("-", String.Empty); } } } }
でましたね。
cmd > ConsoleApplication4.exe d:\GitHub\PowerShellUtil\Get-FileHashIndex\Get-FileHashIndex.ps1 00AF5018AEFF8B5C3F17E0B1ADF111E29F9AFB874C583B5740A605EEEF70744F
Cmdlet でもいいのですが、PowerShell Scriptでも同様に書けます。
合わせて、v4標準の Get-FileHash
と同様に各種アルゴリズムのサポート、パイプライン入力、処理の最適化、-Recurse
のサポートをしてみました。
GitHub で公開しておきます。
using が使えず Dispose 書いてたり*4、若干 C# と書き方が違いますがやってることは一緒です。
v4の Get-FileHash
に比べて、同じ v5 September Preview 環境で、倍程度高速化しています。*5
使い方も、出力も変わらないので便利に使ってあげてください。
Get-FileHashIndex -Path d:\GitHub\PowerShellUtil\Get-FileHashIndex\Get-FileHashIndex.ps1
Algorythm Hash Path --------- ---- ---- SHA256 00AF5018AEFF8B5C3F17E0B1ADF111E... D:\GitHub\PowerShellUtil\Get-F...
まとめ
これで、v3 でも ファイルのハッシュ値確認できますねー、わーい。
パラメータ入力とパイプライン入力両方をサポートした書き方の参考になれば幸いです。