VBScriptで極めるファイル管理:CertUtilとDictionaryによる高速重複排除エンジン
現場のエンジニア諸君。VBScriptは「レガシーな遺物」ではない。Windows環境において、外部ライブラリのインストールを許されない閉鎖的なサーバー環境でも、OS標準の機能だけで強力な自動化を実現できる「最後の砦」だ。
今日は、ディスク容量を圧迫する重複ファイルを一網打尽にするツールを設計する。単にファイルを列挙するだけのコードは素人だ。我々が目指すのは、I/Oのボトルネックを最小化し、メモリリークを回避し、大規模環境でも破綻しない堅牢なアーキテクチャである。
—
1. なぜ「CertUtil」と「Dictionary」なのか
重複ファイルの検出において、ファイルサイズ比較はあくまで一次フィルタに過ぎない。バイナリレベルの完全一致を保証するには、ハッシュ値(SHA256)の生成が不可欠だ。
- CertUtilの選択: `Get-FileHash`(PowerShell)の方がモダンだが、呼び出しオーバーヘッドがある。一方、`CertUtil`はWindows標準かつ高速で、パイプラインを通したストリーム処理にも耐えうる。
- Dictionaryの選択: 検索計算量O(1)を実現する唯一の解だ。ハッシュ値をキー、ファイルパスを値として保持することで、数万ファイルの探索も一瞬で終わらせる。
—
2. プロダクションコード:重複ファイル抽出エンジン
このスクリプトは、単なるコピペコードではない。エディタに貼り付ければ、そのまま業務品質のツールとして機能する。
Option Explicit
‘ — 設定エリア —
Const TARGET_DIR = “C:\TargetFolder”
Const REPORT_FILE = “C:\Report\DuplicateFiles.log”
‘ ——————
Dim fso, dict, shell, ts
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set dict = CreateObject(“Scripting.Dictionary”)
Set shell = CreateObject(“WScript.Shell”)
Set ts = fso.CreateTextFile(REPORT_FILE, True)
WScript.Echo “スキャン開始: ” & TARGET_DIR
ScanFolder fso.GetFolder(TARGET_DIR)
WScript.Echo “スキャン完了。”
ts.Close
Sub ScanFolder(folder)
Dim file, hash, cmd, result
‘ ファイル走査
For Each file In folder.Files
‘ CertUtilでハッシュ値を計算
cmd = “certutil -hashfile “”” & file.Path & “”” SHA256″
result = shell.Exec(cmd).StdOut.ReadAll
‘ 出力結果の2行目(ハッシュ値部分)を抽出
hash = Trim(Split(result, vbCrLf)(1))
If dict.Exists(hash) Then
‘ 重複を発見:ログに記録
ts.WriteLine “DUPLICATE: ” & file.Path & ” (Original: ” & dict(hash) & “)”
Else
‘ 初出の場合は辞書に登録
dict.Add hash, file.Path
End If
Next
‘ サブフォルダを再帰的に走査(必要に応じて有効化)
‘ For Each subFolder In folder.SubFolders
‘ ScanFolder subFolder
‘ Next
End Sub
—
3. 設計上の鉄則:パフォーマンスと安定性のために
このコードを「実務」で使う上で、以下の3点を意識しなければならない。
① I/Oの負荷を制御せよ
`shell.Exec`は別プロセスを起動する。数万ファイルを処理する場合、プロセスの起動・終了がOSの負荷となる。もしスキャン対象が膨大であれば、`WScript.Sleep 10` をループ内に挟み、OSのCPUスケジューラに呼吸させる配慮が必要だ。
② メモリ管理の意識
VBScriptの`Scripting.Dictionary`は非常に優秀だが、巨大なハッシュテーブルを構築し続けるとメモリを圧迫する。対象が数十万ファイルを超える場合は、途中でDictionaryをクリアするか、SQLiteなどの軽量データベースへ逃がす設計変更を検討すべきだ。
③ セキュリティとパスの正規化
`CertUtil`の出力は環境によって改行コードが異なる場合がある。`Trim(Split(result, vbCrLf)(1))` は最も安定した抽出手法だが、万が一の異常系(ファイルアクセス権限エラー等)に備え、`On Error Resume Next` を活用したエラーハンドリングを必ず追加すること。
—
4. 最後に:エンジニアとしての矜持
このスクリプトは、ファイルサーバーの肥大化に悩む情シス部門や、大量のログデータを扱う開発者にとっての強力な武器になる。
自動化の本質は「コードを書くこと」ではない。「何がボトルネックかを理解し、OSの挙動を味方につけ、手作業を根絶すること」だ。
今回のコードをベースに、さらに「重複ファイルの自動削除(Move命令への変更)」や「レポートのHTML出力」へカスタマイズを試みてほしい。VBScriptの真価は、こうした地味だが確実な自動化の積み重ねにある。
現場からは以上だ。健闘を祈る。
