序文:なぜ今、VBScriptでファイルツリーを掌握するのか
モダンな開発環境に身を置く者たちは、VBScriptを「過去の遺物」と切り捨てる。しかし、真のアーキテクトは知っている。エンタープライズの深淵、あるいは制約の厳しい閉鎖ネットワーク環境において、「標準構成のWindowsだけで完結し、外部ランタイムを一切要求しない」という特性が、どれほどの戦略的価値を持つかを。
今回我々が対峙するのは、FileSystemObject(FSO)を用いた再帰的なファイル探索と、それを単なるテキストではなく「対話的なHTMLレポート」へと昇華させるプロセスだ。
数万のファイルが蠢くファイルサーバーの全容を、美しく、かつ高速に可視化する。これは単なるスクリプト作成ではない。COMオブジェクトのライフサイクル管理、文字列連結の計算量、そしてDOM構造の設計を統合する「システム設計」そのものである。
—
1. 牙を研ぐ:FSOと再帰の設計思想
FSO(`Scripting.FileSystemObject`)は、Windows OSの根幹を支えるCOMコンポーネントだ。しかし、無計画な再帰呼び出しは、容易にスタック領域を食いつぶし、あるいはメモリリークを引き起こす。
オブジェクト解放の鉄則
VBScriptのガベージコレクションは、参照カウント方式に基づいている。ループ内で生成される `Folder` や `File` オブジェクトを明示的に `Nothing` で解放しない場合、巨大なディレクトリツリーの走査においてメモリ消費が指数関数的に増大するリスクがある。
文字列連結の罠
多くの初心者は `str = str & “new line”` という書き方をする。しかし、VBScriptにおいて文字列連結は常に新しいメモリ領域の確保とコピーを伴う。数万行のHTMLを生成する場合、この演算は $O(n^2)$ の破滅的な遅延を招く。プロフェッショナルは 「配列への格納と一括 Join」 を選択する。
—
2. 極限のコード:Interactive Tree Generator
以下に示すコードは、単なるサンプルではない。実務での運用に耐えうる、エラーハンドリングとパフォーマンス最適化を施した「完成系」の一つだ。
‘ ===========================================================================
‘ FSO Interactive HTML Report Generator
‘ Author: Legendary Chief Architect
‘ Description: 再帰的探索によるファイルツリーの可視化とHTML5/CSS3によるレポート出力
‘ ===========================================================================
Option Explicit
‘ 設定:解析対象パスと出力先
Const TARGET_PATH = “C:\Project”
Const OUTPUT_FILE = “FileTreeReport.html”
Main
Sub Main()
Dim fso, rootFolder, htmlBuffer
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FolderExists(TARGET_PATH) Then
MsgBox “対象フォルダが存在しません: ” & TARGET_PATH, vbCritical
Exit Sub
End If
‘ HTML生成用のバッファ(動的配列)を初期化
Dim buffer: Set buffer = CreateObject(“System.Collections.ArrayList”)
‘ ヘッダーの書き込み
Call AddHeader(buffer)
‘ 再帰探索開始
Set rootFolder = fso.GetFolder(TARGET_PATH)
WScript.Echo “スキャン開始: ” & rootFolder.Path
Call TraverseFolder(rootFolder, buffer, 0)
‘ フッターの書き込み
Call AddFooter(buffer)
‘ ファイル出力(UTF-8を考慮する場合はADODB.Streamだが、簡便さのためFSOを使用)
Dim ts: Set ts = fso.CreateTextFile(OUTPUT_FILE, True)
Dim line
For Each line In buffer
ts.WriteLine line
Next
ts.Close
MsgBox “レポート生成完了: ” & OUTPUT_FILE, vbInformation
End Sub
‘ — 再帰探索エンジン —
Sub TraverseFolder(objFolder, buffer, depth)
On Error Resume Next ‘ アクセス拒否対策
Dim subFolder, file, indent
indent = depth 20 ‘ CSSによるインデント用
‘ フォルダ行の追加
buffer.Add “
“📁 ” & HTMLEncode(objFolder.Name) & _
”
”
‘ ファイル情報の取得
buffer.Add “
For Each file In objFolder.Files
Dim sizeKB: sizeKB = Round(file.Size / 1024, 1)
buffer.Add “
“📄 ” & HTMLEncode(file.Name) & _
”
”
Next
buffer.Add “
”
‘ サブフォルダへの再帰
For Each subFolder In objFolder.SubFolders
Call TraverseFolder(subFolder, buffer, depth + 1)
Next
‘ メモリ解放:深い再帰でのオブジェクト蓄積を防ぐ
Set subFolder = Nothing
Set file = Nothing
If Err.Number <> 0 Then Err.Clear
End Sub
‘ — ヘルパー関数:HTMLテンプレート —
Sub AddHeader(buffer)
buffer.Add “
buffer.Add “
buffer.Add “ ”
buffer.Add “
System Architecture File Report
”
buffer.Add “
Generated at: ” & Now & “
”
End Sub
Sub AddFooter(buffer)
buffer.Add “”
End Sub
Function HTMLEncode(str)
If IsNull(str) Then
HTMLEncode = “”
Exit Function
End If
Dim tmp: tmp = str
tmp = Replace(tmp, “&”, “&”)
tmp = Replace(tmp, “<", "<")
tmp = Replace(tmp, ">“, “>”)
tmp = Replace(tmp, “”””, “"”)
HTMLEncode = tmp
End Function
—
3. 徹底解説:シニアエンジニアが注目すべき勘所
3.1 `System.Collections.ArrayList` の活用
VBScriptの動的配列(`ReDim Preserve`)は、要素を増やすたびに配列全体のコピーが発生するため、極めて低速だ。ここでは .NET Framework の `ArrayList` を COM 経由で呼び出している。これにより、動的なバッファリングを $O(1)$ に近い効率で実現している。これは、VBScriptでパフォーマンスを追求する際の常套手段だ。
3.2 `On Error Resume Next` の戦略的配置
ファイルシステム操作において、システム保護フォルダや使用中のファイルへのアクセス拒否(Error 70)は日常茶飯事だ。トラップを仕掛けずに再帰を回すのは無謀と言える。本スクリプトでは、個別のフォルダ・ファイル処理に対してエラーを無視しつつ、オブジェクトの解放を確実に行う構造を採っている。
3.3 HTMLの対話性と視認性
出力されるHTMLには最小限のCSSを埋め込んでいる。実務においては、ここに JavaScript を一行加え、`display: none` を切り替えるだけで、折り畳み可能なツリービューが完成する。静的なテキストログを渡されるのと、ブラウザで検索・展開ができるレポートを渡されるのとでは、現場の意思決定スピードが劇的に変わる。
—
4. 継承される知見:レガシーを「資産」に変える
このスクリプトは、Windows Server 2008から最新のWindows 11まで、環境を選ばずに動作する。PowerShellが実行ポリシー(Execution Policy)によって制限されている現場でも、`.vbs` は静かに、かつ確実に任務を遂行する。
チーフアーキテクトの忠告:
技術の価値は、その新しさではなく「目的をいかに確実に、かつ最小のコストで達成するか」で決まる。VBScriptという刃を研ぎ続けることは、時に最新のフレームワークを学ぶこと以上に、システムの深淵を理解する助けとなるだろう。
このコードをベースに、MD5ハッシュの計算ロジックや、特定の拡張子(`.log`, `.config`)のみを抽出するフィルタリング機能を実装してみるがいい。それはもはや単なるスクリプトではなく、立派な「運用監視ソリューション」への第一歩となるはずだ。
