tech.guitarrapc.cóm

Technical updates

PowerShell v3 でも ファイルのハッシュ値 (File hash) を確認したい

ファイルの変更を検知する時に一般的に行われるのが ハッシュ値の比較です。ファイルの変更検知はすなわち改ざんがないかファイルが更新されてないかなど、あいまいではない変化の検知を意味するのでこういうのって大事です。*1

日付やファイル名での判断ダメ、絶対。

例えば、MySQL などをダウンロードしようとすると、ダウンロードリンクそばに ハッシュ値がありますよね?ダウンロードされたものがこの値と一致していない場合は改ざんがあったことを気づけるわけです。

f:id:guitarrapc_tech:20141029034107p:plain

f:id:guitarrapc_tech:20141029034201p:plain

今回は、PowerShell v3 *2、あるいは v4 で標準のCmdletより便利にファイルハッシュを取得するための関数の紹介です。

目次

Linux でのハッシュ値確認

Linux では、openssl のopenssl sha1 であったり、md5sumsha1sumshasumsha224sumsha256sumsha384sumsha512sum とまぁはい。ふつーに一般的な標準環境ですぐに確認できます。

便利、簡単。

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 でも ファイルのハッシュ値確認できますねー、わーい。

パラメータ入力とパイプライン入力両方をサポートした書き方の参考になれば幸いです。

*1:FileStream なのかファイル全体を Byte配列で読むかでも変わりますが

*2:v2 は PSCustomObject ないから Add-Member に置き替えればいけるかな

*3:LiteralPath でもいいですが簡略で

*4:ぐぬぬ

*5:パイプラインのコスト? なんか余計なこといろいろしてるにゃぁ