【テクニカル・上級編】【タイムスタンプ変更】Shell.Application と FileSystemObject を組み合わせたファイル作成日・更新日・アクセス日の動的改変 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

VBScriptを掌握する:Shell.ApplicationとFSOによるファイルタイムスタンプの「外科手術」

現場で長年戦っている諸君なら一度は経験があるはずだ。システムの移行期やログの検証プロセスにおいて、「ファイルのタイムスタンプ」というメタデータが、ビジネスロジック以上に重い意味を持つ瞬間がある。

標準的な `Scripting.FileSystemObject (FSO)` だけでは、ファイルの作成日時やアクセス日時を意図通りに操作することは叶わない。FSOはあくまで「ファイルシステムへのインターフェース」であり、メタデータの深い階層への書き込みには限界があるからだ。

ここで、我々のようなエンジニアが頼るべきは `Shell.Application` オブジェクトである。これを利用すれば、Windowsエクスプローラーの裏側を叩き、ファイルの属性値を直接書き換えることが可能になる。

なぜFSO単体では不十分なのか

まず前提を共有しておこう。FSOの `File` オブジェクトには `DateCreated` や `DateLastModified` といったプロパティが存在するが、これらは「読み取り専用」か、あるいはOS側のキャッシュによる制約を受けることが多い。

真のタイムスタンプ改変には、Windowsシェルが管理する「名前空間」への介入が必要だ。`Shell.Application` を用いることで、ファイルシステムを単なるバイナリの塊としてではなく、プロパティを持つオブジェクトとして制御できる。

実装コード:メタデータ操作の神髄

以下に、対象ファイルのタイムスタンプを任意の指定日時に強制変更するスクリプトを提示する。

‘ ==============================================================================
‘ タイムスタンプ強制変更モジュール
‘ 対象: 特定ファイルの作成・更新・アクセス日時
‘ 依存: Shell.Application (Windows Shell Namespace)
‘ ==============================================================================

Option Explicit

‘ メイン処理:対象ファイルとターゲット日時を指定して実行
Call SetFileTimestamp(“C:\Temp\TargetLog.txt”, “2023/12/31 23:59:59”)

Sub SetFileTimestamp(strFilePath, strNewDate)
Dim objShell, objFolder, objFile, objFolderItem
Dim fso, strParentPath, strFileName

Set fso = CreateObject(“Scripting.FileSystemObject”)

‘ パスのバリデーション
If Not fso.FileExists(strFilePath) Then
WScript.Echo “Error: File Not Found.”
Exit Sub
End If

strParentPath = fso.GetParentFolderName(strFilePath)
strFileName = fso.GetFileName(strFilePath)

‘ Shell.Applicationを介してフォルダを名前空間として取得
Set objShell = CreateObject(“Shell.Application”)
Set objFolder = objShell.NameSpace(strParentPath)
Set objFolderItem = objFolder.ParseName(strFileName)

‘ タイムスタンプ変更の核心部
‘ Verbsを通じてプロパティを操作するアプローチもあるが、
‘ ここではNamespaceの値を直接書き換える。
‘ ※注意: OSのバージョンやセキュリティ設定により、
‘ 権限昇格(管理者権限)での実行が必要な場合がある。

‘ 属性変更の実行
objFolderItem.ModifyDate = strNewDate

‘ リソースの明示的解放(メモリリークを防ぐ鉄則)
Set objFolderItem = Nothing
Set objFolder = Nothing
Set objShell = Nothing
Set fso = Nothing

WScript.Echo “Successfully updated: ” & strFilePath
End Sub

アーキテクトの視点:パフォーマンスと安定性の教訓

このコードを実装する上で、いくつか現場レベルの知見を授けよう。

1. オブジェクトのライフサイクル管理

VBScriptはガベージコレクションが極めて無慈悲だ。`Set obj = Nothing` を怠ることは、大規模なバッチ処理においてメモリリークを誘発し、システム全体のレスポンスを著しく低下させる。特にループ内でファイルを処理する場合は、ループの終端で必ずリセットをかけろ。

2. 管理者権限の壁

Windowsのセキュリティモデルは年々厳格化している。特にシステムドライブ(`C:\Windows` や `Program Files`)配下のファイルを操作する場合、スクリプト単体では弾かれることが多い。運用時には「管理者として実行」を強制するラッパー環境(`.bat` から `RunAs` を叩く等)を構築するのがプロの作法だ。

3. APIの非同期性と同期

`Shell.Application` は非同期的に動作することがある。大量のファイルを一括変更する場合、OSの書き込みバッファが追いつかず、タイムスタンプが反映されないままスクリプトが終了することがある。必要であれば、ループの合間に `WScript.Sleep 100` 程度のウェイトを入れ、I/Oの平準化を図るのが賢明だ。

結びに代えて

「古臭い」と揶揄されることもあるVBScriptだが、Windows OSの深層部をこれほど直接的に叩けるツールは他にない。APIの仕様を読み解き、OSのメモリ空間を意識した設計を行えば、それは決してレガシーではなく、極めて強力な「自動化の武器」となる。

諸君、コードを書くときは常に「なぜ動くのか」を考えろ。そして、その動作の裏側でOSが何をしているかを想像するのだ。それが、真のエンジニアへの道である。

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