【Powershell】フォルダ配下にあるファイルのハッシュ値を取得し、CSVに出力する

スポンサーリンク
powershell
スポンサーリンク

ハッシュ値の一覧を取得したい

仕事で、事前に用意した資材(configとか)を利用するとき、資材の内容が知らない間に変わっていないかチェックするためハッシュ値を比較することになっている。

フォルダ配下にある複数ファイルのハッシュ値を取得すること自体はスクリプト化するほどのことではないが、毎回PowerShellでフォルダパスを打ち込むのも面倒だったので、おまけ機能を少しつけてスクリプト化した。

<参考:一回こっきりとかだったら普通に以下コマンド実行でいいと思う>

Get-ChildItem -File -Recurse "[対象フォルダパス]" | Get-FileHash | export-csv [出力CSV名] -Encoding Default -NoTypeInformation

出力CSV名、はファイル名だけだとPowerShellコマンド実行時のフォルダ直下に作成される。フォルダも指定したいときはフルパスで指定すること。これでも十分目的のものは手に入ると思う。

搭載機能

  • 指定したフォルダ配下(サブフォルダ含む)のファイルに対して、ファイルのハッシュ値を取得し、CSVに出力する。
  • ユーザーはフォルダパスをフォルダダイアログから指定できるようにする。
  • 取得する情報は以下とする。
     アルゴリズム(SHA256とか)
     ハッシュ値
     ファイル作成日時
     ファイル更新日時
     ファイルパス
    ファイル作成日時/更新日時の取得は、ハッシュ値に変化があった場合の調査情報として取得することにしている。
  • 結果はCSVファイルで出力する。ファイル名に実行年月日時分秒をつける。
  • 対象数が多いと時間がかかるので、進捗状況が表示されるようにする。
  • 後からエラーなどを終えるように実行ログを別ファイルとして吐き出す。

コード

絶対改善余地があるけどこんな感じ。

#
# フォルダ配下のファイルのハッシュ値を取得してCSV出力するツール
#
# ファイル名:Get-Filehash-toCSV.ps1

# 調査対象フォルダの初期化
$SearchFolder = ""

# CSVテーブルの用意
$CSVdatas = @()

# 日付の取得
$date = Get-Date -Format "yyyyMMdd";

# 時間の取得
$time = Get-Date -Format "HHmmss";

# 調査結果を出力するフォルダ
$scriptPath = $MyInvocation.MyCommand.Path
$scriptPath_split = Split-Path -Parent $scriptPath
$ResultFolder = ($scriptPath_split+"\結果")

# 調査結果出力結果フォルダがなかったら作成
if( -not (Test-Path $ResultFolder) ) {
    New-Item $ResultFolder -Type Directory
}

# 調査結果出力ファイル名
$ResultFile = ( "\FileHashList_"+$date+"_"+$time+".csv" )
$ExecuteLogFile = ( "\ExecuteLog_"+$date+"_"+$time+".log" )

#調査結果出力フォルダとファイル名のマージ
$Result = Join-Path $ResultFolder $ResultFile
$ExecuteLog = Join-Path $ResultFolder $ExecuteLogFile

# アセンブリ読み込み
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# フォーム作成
$Form = New-Object System.Windows.Forms.Form 
$Form.Size = New-Object System.Drawing.Size(400,150) 
$Form.Text = "ファイルハッシュ値取得ツール"

# ラベル作成(フォルダパス)
$LabelFilePath = New-Object System.Windows.Forms.Label
$LabelFilePath.Location = New-Object System.Drawing.Point(20,10)
$LabelFilePath.Size = New-Object System.Drawing.Size(300,20)
$LabelFilePath.Text = "ファイル調査対象フォルダのパスを入力してください"
$Form.Controls.Add($LabelFilePath)

# フォルダ入力用テキストボックス
$TextBoxFilePath = New-Object System.Windows.Forms.TextBox
$TextBoxFilePath.Location = New-Object System.Drawing.Point(20,30)
$TextBoxFilePath.Size = New-Object System.Drawing.Size(300,20)
$Form.Controls.Add($TextBoxFilePath)

# 参照ボタン
$ButtonFilePath = New-Object System.Windows.Forms.Button
$ButtonFilePath.Location = New-Object System.Drawing.Point(320,30)
$ButtonFilePath.Size = New-Object System.Drawing.Size(40,20)
$ButtonFilePath.Text = "参照"
$Form.Controls.Add($ButtonFilePath)

# OKボタン
$ButtonOK = New-Object System.Windows.Forms.Button
$ButtonOK.Location =  New-Object System.Drawing.Point(230,70)
$ButtonOK.Size = New-Object System.Drawing.Size(60,20)
$ButtonOK.Text = "OK"
$Form.Controls.Add($ButtonOK)

# Cancelボタン
$ButtonCancel = New-Object System.Windows.Forms.Button
$ButtonCancel.Location =  New-Object System.Drawing.Point(300,70)
$ButtonCancel.Size = New-Object System.Drawing.Size(60,20)
$ButtonCancel.Text = "キャンセル"
$ButtonCancel.DialogResult = "Cancel"
$Form.Controls.Add($ButtonCancel)

# フォームを最前面に表示
$form.Topmost = $True

# 参照ボタンをクリック時の動作
$ButtonFilePath.add_click{

    #ダイアログを表示しファイルを選択する
    $Dialog = New-Object System.Windows.Forms.FolderBrowserDialog
    if($Dialog.ShowDialog() -eq "OK"){
        $TextBoxFilePath.Text = $Dialog.SelectedPath
    }
}

# OKボタンをクリック時の動作
$ButtonOK.add_click{

    #ファイルパスが入力されていないときは背景を黄色にする
    if($TextBoxFilePath.text -eq ""){
    $TextBoxFilePath.BackColor = "yellow"
    }else{
        $Form.DialogResult = "OK"
    }
}


Start-Transcript $ExecuteLog


#フォームを表示し処理が完了したらファイルパスを返す
$FormResult = $Form.ShowDialog()
if($FormResult -eq "OK"){

    $SearchFolder = $TextBoxFilePath.text
    echo $SearchFolder"を調査中…ファイルが多いと時間かかります。調査中にPowershellのウィンドウのサイズ変更をしないでください。"


###進捗表示用###
echo "ファイル数取得中"


$GetSearchFolder = Get-ChildItem -File -Recurse $SearchFolder
$fileCount = $GetSearchFolder.Length
$counter   = 0
echo ("ファイル数="+$fileCount)
echo "チェック開始"
echo ""
$denominator = "/"+[string]$fileCount

###ここからハッシュ値を取得してCSVに格納していく。

ForEach($a in $GetSearchFolder) {
    $counter ++;
    Write-Progress -activity "進捗状況" -status $counter$denominator -percentComplete ($counter / $fileCount * 100)

    
        $CSVdata = New-Object PSObject | Select-Object Algorithm,Hash,CreationTime,LastWriteTime,Path
        $Item = Get-FileHash $a.FullName
        $CSVdata.Algorithm = $Item.Algorithm
        $CSVdata.Hash = $Item.Hash
        $CSVdata.CreationTime = $a.CreationTime
        $CSVdata.LastWriteTime = $a.LastWriteTime
        $CSVdata.Path = $a.FullName

        $CSVdatas += $CSVdata

} 

$CSVdatas | Export-CSV $Result -Encoding Default -NoTypeInformation

Invoke-item $Result

} else {
}
Stop-Transcript

実行イメージ

注意点と補足

  • PowerShellが実行可能な環境である必要があります。

改版履歴

2021/06/16 初版公開

コメント

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