PowerShell で、二つのフォルダーのファイル構成を比較するコマンドを作る

dirdiff.cmd

@set "arg1=%~1" & set "arg2=%~2"
@powershell "iex((@('','','')+(cat '%~f0' | select -skip 3))-join[char]10)"
@exit /b %ERRORLEVEL%

$md5 = New-Object System.Security.Cryptography.MD5CryptoServiceProvider

function Get-MD5s($dir){
    $md5s = @{}
    Get-ChildItem $dir |
    Where-Object { $_.Mode[0] -ne "d" } |
    ForEach-Object {
        $data = [System.IO.File]::ReadAllBytes($_.FullName)
        $bs = $md5.ComputeHash($data)
        $md5s[ $_.Name ] = `
            ([System.BitConverter]::ToString($bs).ToLower() -replace "-","")
    }
    return $md5s
}

$dir1 = $env:arg1
$dir2 = $env:arg2

$hash1 = (Get-MD5s $dir1)
$hash2 = (Get-MD5s $dir2)

foreach($p in $hash1.Keys){
    if( $hash2.ContainsKey($p) ){
        $private:val1 = $hash1[$p]
        $private:val2 = $hash2[$p]
        if( $val1 -ne $val2 ){
            Write-Output ("{0} differ" -f $p)
            Write-Output ("  {0} {1}" -f $val1,(Join-Path $dir1 $p))
            Write-Output ("  {0} {1}" -f $val2,(Join-Path $dir2 $p))
        }else{
            Write-Verbose ("{0} same" -f $p)
        }
    }else{
        Write-Output ("{0} not found" -f (Join-Path $dir2 $p))
    }
}

foreach($p in $hash2.Keys){
    if( -not $hash1.ContainsKey($p) ){
        Write-Output ("{0} not found" -f (Join-Path $dir1 $p))
    }
}

# vim:set ft=ps1:
  • 最初の3行は、PowerShell をバッチファイル化するためのまじない
  • 二つのディレクトリの直下にあるファイルの md5連想配列に格納して、比較するだけ

こういうのは別のバッチファイルから呼び出したいから、Goで作った方がいいな…と後から思いました。まる

追記

Goで作ってみました。https://github.com/zetamatta/experimental/blob/master/dirdiff/main.go