VBScriptを掌握せよ:FSOと正規表現で実現する「堅牢な」コンフィグ置換術
業務自動化の世界において、VBScriptは「レガシー」などと揶揄されることがある。しかし、それは言語のせいではない。使い手の「ライフサイクル管理」への無理解が、バグの温床を生んでいるに過ぎない。
環境移行やバッチ処理の現場で、設定ファイル(INIやテキスト)を書き換えるコードを書く際、君たちは「とりあえず文字列を読み込んで置換する」という安易なアプローチに逃げていないか?
本稿では、ファイルシステムオブジェクト(FSO)と正規表現エンジンを極限までチューニングし、「二度とバグを生まない」設定変更スクリプトのアーキテクチャを伝授する。
—
1. なぜ「力技の置換」は破滅を招くのか
多くの初心者は、ファイルを全行読み込み、`Replace`関数で強引に置換する。これは以下の理由からプロダクション環境では推奨できない。
- 誤置換のリスク: `Key=Value`を置換する際、他の行に偶然同じ文字列が含まれていた場合、無関係な箇所まで破壊する。
- ファイルロックと破損: 書き込み失敗時のハンドリングが甘ければ、設定ファイルが空になり、システムが起動不能になる。
- エンコーディングの罠: BOM付きUTF-8やShift-JISの混在環境で、FSOのデフォルト挙動に依存すると文字化けが発生する。
これらを解決する唯一の解は、「正規表現による構造的解析」と「一時ファイル経由の安全なスワップ」である。
—
2. 実践:プロダクション品質のコンフィグ置換コード
このスクリプトは、単なる置換ではなく、正規表現を用いて「キー」を厳密に特定し、一時ファイルを経由してアトミックに近い書き込みを行う。
Option Explicit
‘ ——————————————————————
‘ 設定ファイルを安全に置換する堅牢な関数
‘ @param filePath ファイルパス
‘ @param key 対象のキー
‘ @param newValue 置換後の値
‘ ——————————————————————
Function UpdateConfigValue(filePath, key, newValue)
Dim fso, readFile, writeFile, line, pattern, regEx
Dim tempFile, isFound
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set regEx = New RegExp
‘ キーに一致し、かつ行頭から始まるパターン(コメントアウトを除外)
regEx.Pattern = “^(” & key & “\s=\s)(.)$”
regEx.IgnoreCase = True
tempFile = fso.GetSpecialFolder(2) & “\config_tmp_” & fso.GetTempName
Set readFile = fso.OpenTextFile(filePath, 1, False, -2) ‘ -2: システムデフォルトエンコーディング
Set writeFile = fso.CreateTextFile(tempFile, True)
isFound = False
Do Until readFile.AtEndOfStream
line = readFile.ReadLine
If regEx.Test(line) Then
‘ 正規表現で置換を実行
writeFile.WriteLine regEx.Replace(line, “$1” & newValue)
isFound = True
Else
writeFile.WriteLine line
End If
Loop
readFile.Close
writeFile.Close
‘ 成功した場合のみ、元のファイルを上書きする
If isFound Then
fso.CopyFile tempFile, filePath, True
UpdateConfigValue = True
Else
UpdateConfigValue = False
End If
‘ 後始末:リソースリークを防ぐ
fso.DeleteFile tempFile
Set fso = Nothing
End Function
‘ — 実行例 —
Dim result
result = UpdateConfigValue(“C:\app\config.ini”, “DB_SERVER”, “192.168.1.100”)
If result Then
WScript.Echo “設定変更が正常に完了しました。”
Else
WScript.Echo “対象のキーが見つかりませんでした。”
End If
—
3. この設計が「堅牢」である理由
① 正規表現による「スコープ」の限定
`regEx.Pattern = “^(” & key & “\s=\s)(.)$”` を見てほしい。
- `^` を指定することで、行頭からのマッチングを強制する。これにより、値の中に同じ文字列が含まれていても誤置換されない。
- `\s=\s` により、`Key=Value`と`Key = Value`という記述の揺れを吸収する。
② 一時ファイルによる安全性確保
メモリ上で文字列を連結して書き込む方法は、ファイルが大きい場合にメモリ枯渇のリスクを伴う。また、直接書き込みは途中でエラーが起きた場合にファイルが破損する。
一時ファイルへ逐次書き出し、成功した瞬間に `CopyFile` で上書きするこの手法は、「All or Nothing」の原則に基づいている。
③ リソース管理への意識
`Set = Nothing` は、VBScriptのようなガベージコレクションが甘い環境では重要だ。特にCOMオブジェクト(FSOなど)は、メモリリークの温床になりやすい。スクリプトがループ内で呼び出される設計の場合、この後始末を怠ると即座にシステム全体が重くなる。
—
4. チーフアーキテクトからの助言
VBScriptは強力だが、その「自由さ」は毒にもなる。実務でこのスクリプトを運用する際は、以下の「鉄則」を守ってほしい。
1. バックアップの自動生成: `fso.CopyFile filePath, filePath & “.bak”` を関数冒頭に追加せよ。運用トラブルの9割は、この一行があれば解決する。
2. ログ出力: `WScript.Echo` に頼らず、テキストファイルにタイムスタンプ付きのログを吐く関数を別途作れ。
3. エンコーディングの確認: 日本のレガシー環境では `Shift-JIS` が多用されるが、モダンな環境なら `UTF-8` が基本。`OpenTextFile` の第4引数は常に意識すること。
VBScriptは古いが、その「軽量さ」と「OS標準搭載」という武器は、今なお自動化の最前線で輝く。君たちが書く一行が、明日誰かの残業をゼロにするかもしれない。その責任を持ってコードを書いてほしい。
