VBScriptを掌握する極限の知見:FileSystemObjectのAttributes属性制御によるファイル要塞化と動的解除
開発現場において、VBScriptによる自動化スクリプトは今なおレガシーシステムの裏側やキッティング自動化の現場で強烈な生命力を放っている。しかし、素人が書いたスクリプトは「ファイルがロックされていました」「誤って設定ファイルを上書きして壊しました」という稚拙なエラーで容易に爆散する。
プロのエンジニアが作るべき自動化ツールとは、「対象ファイルを自ら守り、必要な瞬間だけその鎧を脱ぎ捨てる」という動的なライフサイクル管理が実装されているものである。
今回は、`FileSystemObject (FSO)` の `Attributes` プロパティを完全に掌握し、読み取り専用(Read-only)や隠しファイル(Hidden)属性をプログラム側から自在にコントロールする、極限まで堅牢なファイル制御のノウハウを伝授する。
—
1. なぜ「Attributesプロパティ」のビット演算でハマるのか?
`FSO.GetFile(path).Attributes` が返す値は、単なるフラグの数値ではなく、複数の属性がビット単位でオア(OR)合成されたものである。
よくある素人の実装は、以下のように直接代入してしまうものだ。
‘ 【悪手】これでは既存の他の属性(アーカイブなど)が全て吹き飛ぶ
fileObj.Attributes = 1 ‘ 読み取り専用にするつもりが、他の属性を破壊する
ファイルには「読み取り専用(1)」「隠しファイル(2)”, “システムファイル(4)”, “アーカイブ(32)」などの状態が同居し得る。属性を操作する際は、現在の属性を保持したまま、目的のビットだけを立てる(あるいは落とす)「ビット演算」が鉄則となる。
—
2. 堅牢な属性制御のロジック設計
属性の付与と解除を安全に行うためのメカニズムは以下の通りだ。
- 属性の付与 (Bitwise OR): `CurrentAttributes OR TargetAttribute`
- 属性の解除 (Bitwise AND NOT): `CurrentAttributes AND (NOT TargetAttribute)`
これをVBScriptの貧弱な演算子環境で美しく、かつ安全にカプセル化する必要がある。
—
3. 【プロダクションコード】設定ファイルの要塞化と安全な動的書き換えエンジン
以下のコードは、重要な設定ファイル(`config.ini`)を普段は「読み取り専用 兼 隠しファイル」として要塞化し、スクリプトが更新処理を行う瞬間だけ一時的にその鎧を剥ぎ、書き込み完了後に再び厳重な保護状態に戻す、実務直結のプロダクションコードである。
Option Explicit
‘ ==============================================================================
‘ スクリプト名: SecureConfigUpdater.vbs
‘ 概要: ファイル属性を動的に制御し、設定ファイルの安全な更新を行う実用サンプル
‘ 著者: チーフアーキテクト
‘ ==============================================================================
Call Main()
Sub Main()
Dim fso, targetPath, backupPath
Set fso = CreateObject(“Scripting.FileSystemObject”)
targetPath = fso.GetAbsolutePathName(“config.ini”)
backupPath = targetPath & “.bak”
WScript.Echo “=== 処理開始 ===”
‘ 1. 対象ファイルが存在しない場合は初期作成するモジュールを想定
If Not fso.FileExists(targetPath) Then
Call CreateInitialConfig(fso, targetPath)
End If
‘ 2. 【重要】更新作業のため、一時的に属性を解除して「通常ファイル」にする
WScript.Echo “[Info] ファイルの保護を解除します…”
Call SetFileAttributes(fso, targetPath, False, False)
‘ 3. 堅牢なバックアップ作成(上書き許可)
If fso.FileExists(targetPath) Then
fso.CopyFile targetPath, backupPath, True
End If
‘ 4. 安全なファイル書き込み(エラーハンドリング付き)
On Error Resume Next
Call WriteConfigData(fso, targetPath)
If Err.Number <> 0 Then
WScript.Echo “[Error] 書き込み失敗。バックアップから復旧します: ” & Err.Description
fso.CopyFile backupPath, targetPath, True
On Error GoTo 0
Exit Sub
End If
On Error GoTo 0
‘ 5. 【重要】更新完了後、再びファイルを要塞化(読み取り専用 + 隠しファイル)
WScript.Echo “[Info] ファイルを再び保護(読み取り専用・隠し属性)します…”
Call SetFileAttributes(fso, targetPath, True, True)
WScript.Echo “=== 処理正常終了 ===”
Set fso = Nothing
End Sub
‘ ==============================================================================
‘ 属性制御コア関数
‘ @param fso FileSystemObjectインスタンス
‘ @param filePath 対象ファイルのパス
‘ @param isReadOnly True: 読み取り専用を付与 / False: 解除
‘ @param isHidden True: 隠し属性を付与 / False: 解除
‘ ==============================================================================
Sub SetFileAttributes(fso, filePath, isReadOnly, isHidden)
Const AttrReadOnly = 1
Const AttrHidden = 2
Dim fileObj
Set fileObj = fso.GetFile(filePath)
Dim currentAttr
currentAttr = fileObj.Attributes
‘ 読み取り専用の制御
If isReadOnly Then
‘ ビットを立てる (OR)
currentAttr = (currentAttr Or AttrReadOnly)
Else
‘ ビットを落とし込む (AND NOT)
currentAttr = (currentAttr And Not AttrReadOnly)
End If
‘ 隠しファイルの制御
If isHidden Then
currentAttr = (currentAttr Or AttrHidden)
Else
currentAttr = (currentAttr And Not AttrHidden)
End If
‘ 最終的な属性値を適用
fileObj.Attributes = currentAttr
Set fileObj = Nothing
End Sub
‘ ==============================================================================
‘ 設定ファイル初期作成モジュール
‘ ==============================================================================
Sub CreateInitialConfig(fso, filePath)
Dim ts
Set ts = fso.CreateTextFile(filePath, True)
ts.WriteLine “[Settings]”
ts.WriteLine “Server=192.168.1.10”
ts.WriteLine “Timeout=30”
ts.Close
Set ts = Nothing
End Sub
‘ ==============================================================================
‘ 設定データ書き込みモジュール
‘ ==============================================================================
Sub WriteConfigData(fso, filePath)
Dim ts
‘ ForWriting = 2
Set ts = fso.OpenTextFile(filePath, 2, False)
ts.WriteLine “[Settings]”
ts.WriteLine “Server=10.0.0.99” ‘ 更新後の値
ts.WriteLine “Timeout=60”
ts.WriteLine “Updated=” & Now()
ts.Close
Set ts = Nothing
End Sub
—
4. 現場でありがちな「罠」とアーキテクトからの助言
罠1: 「権限不足 (Permission Denied)」による即死
ネットワーク共有フォルダや `C:\Program Files` 配下など、書き込み権限がない場所で `File.Attributes` を変更しようとすると、容赦なくランタイムエラーが発生する。
スクリプトを実行するユーザーアカウントの権限管理を確実に行うか、エラーハンドリング(`On Error Resume Next` と `Err.Number` の監視)を必ずインテグレートすること。
罠2: セキュリティソフトや他プロセスによるファイルロック
FSOで属性を変更した直後にテキストファイルを開こうとすると、OSやセキュリティソフトのファイルスキャンが間に合わず、一瞬ロックがかかるケースがある。
もし連続して書き込み処理を行う場合は、`WScript.Sleep 100` などの微小なウェイトを挟むことで、I/O競合を防ぐという泥臭いだが確実な防衛策も時には必要となる。
—
総括
VBScriptは古い言語と揶揄されることもあるが、OSの根幹にダイレクトに触れられる強力なツールである。
ファイル属性を制する者は、ローカル環境のファイルI/Oを制する。安易なファイル放置をやめ、「必要なときだけ開き、終わったら要塞化する」というセキュアでプロフェッショナルな設計を、あなたの業務自動化スクリプトにも標準装備してほしい。
