【上級プロフェッショナル向け】FSOとNTFSオルタネート・データ・ストリーム(ADS)を組み合わせた隠しメタデータの読み書き
VBScriptが誕生して以来、ファイルシステムオブジェクト(FSO: `Scripting.FileSystemObject`)は、Windows自動化における最も忠実な相棒であった。しかし、多くのエンジニアはFSOを「テキストファイルの読み書き」「フォルダの列挙・コピー」といった表層的な用途にしか使っていない。
ファイルのプロパティやデータベースを外付けせず、「ファイルそのものに不可視のメタデータを直接埋め込む」としたらどうだろうか。
今回は、NTFSファイルシステムの深淵であるオルタネート・データ・ストリーム(ADS: Alternate Data Stream)とFSO、そしてCOMの限界を超えるためのADOストリーム(`ADODB.Stream`)を融合させ、レガシー環境において極限まで洗練された隠しメタデータの読み書きアーキテクチャを解説する。
—
1. なぜFSO単体ではADSを扱えないのか?(アーキテクチャの真実)
WindowsのNTFSは、1つのファイルに対して複数のデータストリームを持つことができる。メインストリーム(私たちが普段触れているファイルの中身)のほかに、名前付きのサブストリーム(例: `file.txt:hidden_meta`)を付加することが可能だ。エクスプローラーからはファイルサイズも変わらず、通常の`dir`コマンドでも隠蔽されるため、特殊な管理情報の保持や、監査証跡の埋め込みに極めて有効である。
しかし、ここでVBScriptエンジニアが直面する最大の壁がある。
FSOの標準メソッド(`OpenTextFile`など)は、パスにコロン(`:`)が含まれるADSの構文をネイティブにサポートしていない場合がある。
FSOの`CreateTextFile`や`OpenTextFile`に直接 `C:\data.txt:metadata` を渡すと、パス構文エラーやアクセス拒否が発生する。この制約を突破するには、WindowsのI/Oサブシステムを直接叩く低レイヤーのストリーム操作、すなわち `ADODB.Stream` オブジェクト をFSOと協調動作させる必要があるのだ。
—
2. メモリ最適化とオブジェクトライフサイクルの鉄則
VBScriptにおける最大のパフォーマンスキラーは、暗黙のオブジェクト参照とメモリリークである。特にレガシーなWindows環境(Windows Server 2008 R2から最新のWindows Server 2022まで)において、COMオブジェクトの解放漏れは、長期間稼働するタスクランナー(タスクスケジューラ経由のバッチ処理など)を確実に死に至らしめる。
- インスタンスのスコープを最小限に絞る
- 使用後は直ちに `Nothing` を代入してメモリを解放する
- エラー発生時(`On Error Resume Next` 乱用時)のクリーンアップを徹底する
これらを遵守した実装コードを以下に提示する。
—
3. 実装コード:ADSメタデータ管理エンジンの全貌
以下のVBScriptは、指定したファイルに対して、ユーザーには一切見えないADS領域へJSON形式のカスタムメタデータ(最終処理者、カスタムタイムスタンプ、バージョン情報)を書き込み、それを完璧に読み出すプロダクションクオリティのモジュールである。
Option Explicit
‘ ==============================================================================
‘ 担当: チーフアーキテクト
‘ 概要: FSOとADODB.Streamを用いたNTFSオルタネート・データ・ストリーム(ADS)操作
‘ ターゲット: Windows Server / Windows 10・11 (NTFS必須)
‘ ==============================================================================
Dim targetFile, streamName, jsonPayload, retrievedData
targetFile = “C:\Automation\TargetDocument.docx”
streamName = “SysMetadata”
jsonPayload = “{“”LastProcessedBy””:””SYSTEM_BOT_01″”,””EpochTime””:1710000000,””Version””:””2.5.0″”}”
WScript.Echo “=== ADSメタデータ操作プロセスを開始 ===”
‘ 1. メタデータの書き込み
If WriteAdsMetadata(targetFile, streamName, jsonPayload) Then
WScript.Echo “[成功] ADSへのメタデータ書き込み完了。”
Else
WScript.Echo “[失敗] メタデータの書き込みに失敗しました。”
WScript.Quit 1
End If
‘ 2. メタデータの読み込み
retrievedData = ReadAdsMetadata(targetFile, streamName)
If retrievedData <> “” Then
WScript.Echo “[成功] 取得した隠しメタデータ: ” & retrievedData
Else
WScript.Echo “[失敗] メタデータの読み込みに失敗しました。”
End If
WScript.Echo “=== プロセス終了 ===”
‘ ——————————————————————————
‘ 関数名: WriteAdsMetadata
‘ 概要: 指定ファイルのADSにUTF-8で文字列を書き込む
‘ ——————————————————————————
Function WriteAdsMetadata(filePath, sName, dataStr)
Dim fso, adsPath, adoStream
WriteAdsMetadata = False
On Error Resume Next
‘ FSOによるファイル存在確認
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FileExists(filePath) Then
‘ ファイルが存在しない場合は空のメインファイルを生成するかエラーとする
‘ 今回は安全のため終了
Set fso = Nothing
Exit Function
End If
Set fso = Nothing ‘ 即座に解放
‘ ADSのパス構築 (例: C:\path\file.ext:streamname)
adsPath = filePath & “:” & sName
‘ ADODB.Streamによる低レイヤーバイナリ/テキストストリーム制御
Set adoStream = CreateObject(“ADODB.Stream”)
With adoStream
.Type = 2 ‘ adTypeText (テキストデータ)
.Charset = “utf-8”
.Open
.WriteText dataStr
.SaveToFile adsPath, 2 ‘ adSaveCreateOverWrite (上書き保存)
.Close
End With
If Err.Number = 0 Then
WriteAdsMetadata = True
Else
‘ 必要に応じてエラーログ出力などを実装
Err.Clear
End If
‘ 【重要】明示的なオブジェクト解放(メモリリーク防止)
Set adoStream = Nothing
On Error GoTo 0
End Function
‘ ——————————————————————————
‘ Function名: ReadAdsMetadata
‘ 概要: 指定ファイルのADSから隠しメタデータを読み出す
‘ ——————————————————————————
Function ReadAdsMetadata(filePath, sName)
Dim fso, adsPath, adoStream, content
ReadAdsMetadata = “”
On Error Resume Next
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FileExists(filePath) Then
Set fso = Nothing
Exit Function
End If
Set fso = Nothing
adsPath = filePath & “:” & sName
Set adoStream = CreateObject(“ADODB.Stream”)
With adoStream
.Type = 2 ‘ adTypeText
.Charset = “utf-8”
.Open
‘ 既存のADSストリームからデータを読み込む
.LoadFromFile adsPath
If Err.Number = 0 Then
content = .ReadText(-1) ‘ adReadAll
ReadAdsMetadata = content
End If
.Close
End With
Set adoStream = Nothing
On Error GoTo 0
End Function
—
4. チーフアーキテクトが指摘する運用上のリスクと極意
このテクニックを実際のエンタープライズ環境や、複雑なシステム間連携のパイプラインに導入する際、以下の「罠」に注意しなければならない。
① ファイルシステムのコピーと移動の罠
NTFSのADSは、FAT32やexFAT、あるいは通常のネットワーク共有(CIFS/SMBの一部古い実装や非NTFSボリューム)にファイルを移動またはコピーすると、メタデータが綺麗に消失する。
もし、バックアップ目的でファイルをZIP圧縮したり、別ドライブへ単純コピーしたりする場合は注意が必要だ。バックアップの際は、PowerShellの `Get-Item -Stream ` や専用のアーカイブツールを使用し、ADSが保持されることを担保するアーキテクチャ設計が求められる。
② セキュリティソフト(EDR / アンチウイルス)の誤検知
高度なセキュリティ製品やEDRは、ファイルに隠されたデータストリーム(ADS)をマルウェアの隠れ場所(Rootkit的な手法)としてスキャンすることがある。社内公式のシステム管理目的であっても、信頼されていないパスや不審な命名規則(例: 実行可能ファイルをADSに隠すなど)で行うと、セキュリティアラートを引き起こす可能性がある。
そのため、ストリーム名(上記の例では `SysMetadata`)は明確に規定し、セキュリティ監査部門に説明できる状態を維持すること。
③ レガシー環境とモダン環境のブリッジ
VBScriptはレガシーな技術と見なされがちだが、WindowsのコアAPIが健在である限り、そのポテンシャルは衰えない。PowerShellへの完全移行が難しい過渡期のシステムにおいて、COMコンポーネントを適切に制御したFSO+ADSの組み合わせは、追加のミドルウェアやDBサーバーを導入することなく、ファイル管理の高度化を実現する究極のソリューションとなる。
オブジェクトのライフサイクルを慈しみ、OSのファイルシステム構造の深層までをコードで統御せよ。真の自動化エンジニアにとって、見えない領域を可視化・制御することこそ最大の悦楽なのだから。
