ファイルの変更を検知する時に一般的に行われるのがハッシュ値の比較です。ファイルの変更検知はすなわち改ざんがないか、ファイルが更新されてないかなど、あいまいではない変化の検知を意味するのでこういうのって大事です。*1
日付やファイル名での判断ダメ、絶対。
例えば、MySQLなどをダウンロードしようとすると、ダウンロードリンクそばにハッシュ値がありますよね? ダウンロードされたものがこの値と一致していない場合は改ざんがあったことを気づけるわけです。
今回は、PowerShell 3.0 *2、あるいはv4で標準のCmdletより便利にファイルハッシュを取得するための関数の紹介です。
Linux でのハッシュ値確認
Linuxでは、opensslのopenssl sha1
であったり、openssl sha1
やopenssl sha1
、openssl sha1
、openssl sha1
、openssl sha1
、openssl sha1
、openssl sha1
とまぁはい。ふつーに一般的な標準環境ですぐに確認できます。
便利、簡単。
Windows でのハッシュ値確認
翻ってWindowsではというと、Windows 8.1 / 2012 R2で標準となった PowerShell 4.0 までは標準でファイルハッシュを確認するユーティリティは提供されていませんでした。PowerShell 3.0では標準でCmdletがないんですね。
実際には、.NETから叩けば簡単ですが、コマンドラインでさくっと使いたいという時に、以前はcmdやPowerShellでサポートされておらず悲しい思いをすることが多かったです。
cmd での確認
File Checksum Integrity Verifier (FCIV) を使う人が多いようですね。
https://support2.microsoft.com/default.aspx?scid=kb;en-us;841290
今使う人がいるかは知りません。私も使ったことありません()
PowerShell 4.0 から標準Cmdletの提供
さてPowerShell 4.0には、Get-FileHash
というCmdletが追加されています。
これを使うことで、ファイルのハッシュ値をmd5やsha1、sha256など、各種アルゴリズムで算出できる便利さんです。
但し、以下のようパスに[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 3.0 でファイルのハッシュ値を確認したい
はい。.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
と同様に各種アルゴリズムのサポート、パイプライン入力、処理の最適化、Get-FileHash
のサポートをしてみました。
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でもファイルのハッシュ値確認できますねー、わーい。
パラメータ入力とパイプライン入力両方をサポートした書き方の参考になれば幸いです。