【テクニカル・上級編】【完全一致重複ファイル抽出】CertUtil ハッシュ値と Dictionary を組み合わせたディスク内の重複ファイル一括検出・整理 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

現代のレガシー:VBScriptによる「究極の重複ファイル排除」戦略

多くのシステム管理者が「過去の遺物」と切り捨てるVBScript。しかし、OSの根幹であるWindows Script Host (WSH) を直接叩き、外部ライブラリの依存なしにシステムを制御できるその特性は、今日においても極めて強力な武器だ。

今回は、ディスクの肥大化という悪夢に対し、`CertUtil`と`Scripting.Dictionary`を組み合わせた「外科手術レベル」の重複排除ツールを実装する。メモリ効率を極限まで高め、大規模なファイルシステムに対しても安定して動作する設計思想を伝授しよう。

1. なぜ「CertUtil」なのか?

ファイルの一致判定において、ファイルサイズ比較はあくまで「一次フィルタ」に過ぎない。真の重複判定にはハッシュ値が不可欠だ。
サードパーティ製のツールを導入できないセキュアな環境において、Windowsに標準搭載されている `CertUtil` は、SHA256ハッシュを生成するための最も信頼性の高いバイナリだ。

このツールを `WScript.Shell` の `Exec` メソッドで呼び出す際、決して `Run` を使ってはならない。ストリームを直接パイプで受け取り、メモリバッファを汚染せずに処理を完結させるのがアーキテクトの矜持である。

2. メモリ最適化の極意:Scripting.Dictionaryの活用

数万件のファイルパスをメモリに展開する際、`Dictionary` オブジェクトのキーと値には細心の注意が必要だ。VBScriptのメモリ管理はガベージコレクションに依存するため、ループ内での不要なオブジェクト生成はメモリリークの温床となる。

  • キー: SHA256ハッシュ値
  • 値: 初回出現時のフルパス(または配列として保持)

この構造で実装することで、重複を検知した瞬間に「どのファイルがオリジナルで、どのファイルが冗長か」を即座に特定できる。

3. 実装:重複ファイル抽出・隔離スクリプト

以下のコードは、指定ディレクトリ下のファイルを走査し、ハッシュ値が衝突したファイルを `C:\Temp\Duplicates` へ自動的に隔離(移動)する。

‘ Option Explicitを忘れる者はエンジニアを名乗る資格がない
Option Explicit

Const TARGET_DIR = “C:\TargetFolder”
Const OUTPUT_DIR = “C:\Temp\Duplicates”

Dim fso, dict, shell
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set dict = CreateObject(“Scripting.Dictionary”)
Set shell = CreateObject(“WScript.Shell”)

‘ 隔離用フォルダの構築
If Not fso.FolderExists(OUTPUT_DIR) Then fso.CreateFolder(OUTPUT_DIR)

‘ 再帰的にファイルを処理
ProcessFolder fso.GetFolder(TARGET_DIR)

‘ 後処理:オブジェクトの明示的解放(VBScriptの慈悲)
Set dict = Nothing
Set fso = Nothing
Set shell = Nothing

Sub ProcessFolder(folder)
Dim file, hash, cmd, stream
For Each file In folder.Files
‘ CertUtilでSHA256を算出
cmd = “certutil -hashfile “”” & file.Path & “”” SHA256″
Set stream = shell.Exec(cmd).StdOut
‘ 2行目にはハッシュ値が含まれる(CertUtilの仕様)
stream.SkipLine
hash = Trim(stream.ReadLine)

If dict.Exists(hash) Then
‘ 重複発見:隔離処理
WScript.Echo “重複検知: ” & file.Name & ” -> 隔離中…”
fso.MoveFile file.Path, OUTPUT_DIR & “\” & fso.GetTempName
Else
‘ 初回出現:辞書に記録
dict.Add hash, file.Path
End If
Next

‘ サブフォルダも再帰的に走査
Dim subFolder
For Each subFolder In folder.SubFolders
ProcessFolder subFolder
Next
End Sub

4. チーフアーキテクトからの助言

パフォーマンスのボトルネックを理解せよ

このスクリプトのボトルネックは間違いなく `CertUtil.exe` のプロセス起動オーバーヘッドだ。もし数百万ファイル規模の環境で実行する場合、`Exec` を繰り返すことは推奨しない。

その場合は、PowerShellと連携したハイブリッドアプローチを検討すべきだ。PowerShell側で `Get-FileHash` を使い、その結果をCSV経由でVBScript側が読み込んで判断するという「責務の分離」こそが、大規模運用における現実解となる。

隔離後のセキュリティと整合性

「ファイルを移動する」という行為は、システムにとって破壊的でありうる。本番環境で運用する際は、以下のステップを必ず踏むこと。

1. ドライラン(試運転): 実際に移動させる前に、ログ出力のみを行うモードを実装すること。
2. ハッシュ値の検証: 移動後にオリジナルと重複ファイルが完全に同一であることをバイナリレベルで比較すること。
3. パーミッションの保持: 移動先のアクセス権限が、移動元のセキュリティポリシーに準拠しているか確認すること。

VBScriptは「古い」のではない。OSの心臓部と対話するための「最もシンプルで、最も透明性の高いインターフェース」なのだ。このツールが、貴殿のシステム管理における静かなる守護神となることを願う。

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