こんにちは!エンジニアリングの世界へようこそ。
今日は、多くの人が頭を悩ませる「ネットワーク越しの一斉ログ書き込み」という実務の壁を、VBScriptで美しく突破する方法を伝授します。
「社内の複数PCから、一斉にVBScriptが走って共有フォルダのログファイルに書き込もうとしたら、ファイルがロックされてエラーで落ちた……」
こんな悲劇、インフラ担当者や自動化を愛するエンジニアなら一度は経験があるはずです。
今回は、この「書き込み衝突」を完全に回避し、さらにネットワークが一時的に不安定でもデータを絶対にロストしない「一時ローカル保存 & リトライ付き・安全一元化アルゴリズム」を一緒に作っていきましょう。
ここをクリアすれば、あなたのVBScriptスキルは単なる「マクロの延長」を超え、堅牢なシステムを構築できる本物のエンジニアの領域に到達します。さあ、始めましょう!
—
なぜ共有フォルダへの同時書き込みは失敗するのか?
VBScriptでファイルを操作するとき、私たちはよく `Scripting.FileSystemObject` を使いますよね。
例えば、こんなコードを書いたことはありませんか?
‘ 【危険なアンチパターン】
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ 共有フォルダのファイルをいきなり開いて追記する
Set logFile = fso.OpenTextFile(“\\server\share\log.txt”, 8, True)
logFile.WriteLine “ログだよ”
logFile.Close
一見、何の問題もなさそうなこのコード。しかし、10台のPCが全く同時にこのスクリプトを実行したらどうなるでしょうか?
Windowsのファイルシステム(SMB)の仕様上、他のPCがすでにそのファイルを開いて書き込みを行っている最中、別のPCからの `OpenTextFile` は「アクセスが拒否されました (Permission Denied / Error 70)」という冷酷なエラーを返して異常終了します。
これを防ぐためには、以下の3ステップを踏む「大人の設計」が必要になります。
1. まずは安全な自分のPC(ローカル)にログを一時保存する(ネットワークに頼らない!)
2. ネットワークの向こう側の共有ファイルにアクセスを試みる。
3. もし他の奴が書き込んでいて失敗(衝突)したら、少し時間を置いてから何回かリトライ(再挑戦)する。
この「ローカル一時保存 + リトライ制御」こそが、マルチ端末環境を生き抜くための極意です。
—
実装!安全一元化ログモジュール
それでは、実際の現場でそのままコピペして使える、極上の実用スクリプトを公開します。
デスクトップなどに `logger.vbs` として保存し、中身をじっくり読んでみてください。
‘ ==============================================================================
‘ [モジュール名] 安全一元化ログ書き込みエンジン
‘ [概要] ローカル一時保存とリトライ制御により、共有フォルダへの衝突を防ぐ
‘ ==============================================================================
Option Explicit
‘ メイン処理の実行例
Call WriteSharedLog(“業務アプリA”, “処理が正常に完了しました。”)
Sub WriteSharedLog(strAppName, strMessage)
Dim fso, wshShell
Dim localLogDir, localLogPath, sharedLogPath
Dim objStream, timestamp, logData
Dim retryCount, maxRetries, waitInterval
Dim success
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set wshShell = CreateObject(“WScript.Shell”)
‘ 1. タイムスタンプとログデータの作成
timestamp = Now()
logData = “[” & timestamp & “] [” & strAppName & “] [” & wshShell.ExpandEnvironmentStrings(“%USERNAME%”) & “] ” & strMessage
‘ 2. 万が一のためのローカル一時保存先(ユーザーのTempフォルダ等を利用)
‘ ネットワークが完全に切断されていても、ローカルには必ず証拠を残します
localLogDir = wshShell.ExpandEnvironmentStrings(“%TEMP%)\AppLogs”)
If Not fso.FolderExists(localLogDir) Then
fso.CreateFolder(localLogDir)
End If
localLogPath = localLogDir & “\local_stock.log”
‘ ローカルへまずは確実に書き込み
On Error Resume Next
Set objStream = fso.OpenTextFile(localLogPath, 8, True)
If Err.Number = 0 Then
objStream.WriteLine logData
objStream.Close
End If
On Error GoTo 0
‘ 3. 共有フォルダへの転送・追記(ここが本番の排他・リトライ処理)
sharedLogPath = “\\your-server\share-folder\central_operation.log” ‘ ※実際の環境に合わせて変更してください
maxRetries = 5 ‘ 最大リトライ回数
waitInterval = 2000 ‘ 待機時間(ミリ秒:ここでは2秒)
retryCount = 0
success = False
Do While retryCount < maxRetries And Not success On Error Resume Next ' 共有ファイルを開いて追記を試みる(モード8 = ForAppending) Set objStream = fso.OpenTextFile(sharedLogPath, 8, True) If Err.Number = 0 Then ' 書き込み成功! objStream.WriteLine logData objStream.Close success = True Else ' 衝突(エラー 70 など)が発生した場合、カウンターを増やして待機 Err.Clear retryCount = retryCount + 1 ' WScript.Sleepで少し待つ(他のPCが書き込みを終わるのを譲り合う) WScript.Sleep waitInterval End If On Error GoTo 0 Loop ' オブジェクトの解放(メモリリークを防ぐVBScriptの基本作法) Set objStream = Nothing Set wshShell = Nothing Set fso = Nothing If Not success Then ' 必要に応じて、ここでローカルに溜まった旨をイベントログに書くなどの処理を入れます WScript.Echo "警告: 共有ログへの書き込みに失敗しましたが、ローカルには保存されました。" End If End Sub ---
コードのここがポイント!プロの技術解説
上記のコードには、VBScriptを安定稼働させるための知恵が詰まっています。いくつか重要なポイントを解説します。
① `On Error Resume Next` とエラーハンドリングの鉄則
VBScriptでは、ファイル共有エラーが発生するとスクリプト全体が停止(クラッシュ)してしまいます。これを防ぐために一時的にエラーを無視(`On Error Resume Next`)し、`Err.Number` を監視して「失敗したらリトライする」というスマートな分岐を作っています。処理が終わったら必ず `On Error GoTo 0` で通常の監視に戻すのがお作法です。
② `WScript.Sleep` による「譲り合い(バックオフ)」
もし10台のPCが一斉に書き込もうとして、リトライのタイミングが全く同じだったらどうなるでしょうか? やはり衝突し続けますよね。
今回は単純な固定ウェイト(2秒)にしていますが、実務では `WScript.Sleep (1000 + Int(Rnd 1000))` のようにランダムな秒数(ジッター)を混ぜると、衝突確率を劇的に下げることができます。
③ オブジェクトの明示的な解放(`Set … = Nothing`)
VBScriptの実行エンジンはガベージコレクションがあまり賢くありません。特にファイルシステムやシェルを操作するオブジェクトは、使い終わったら明示的に `Nothing` を代入してメモリを解放してあげることが、長期間稼働するスクリプトの秘訣です。
—
陥りやすいエラーと注意点
1. UNCパス(`\\server\…`)のパーミッション問題
- スクリプトを実行するユーザーが、共有フォルダに対して「変更(書き込み)」権限を持っていることを必ず確認してください。読取専用だと、どれだけコードを工夫しても `OpenTextFile` はエラーを吐き続けます。
2. ファイルが肥大化しすぎる問題
- この方式で長期間運用すると、`central_operation.log` が巨大化します。定期的に別名でバックアップ・圧縮するローテーションバッチをタスクスケジューラ等で組んでおくと完璧です。
—
おわりに
いかがでしたでしょうか?
今回は、単にファイルを書き込むだけでなく、「ネットワークの競合」という現実世界の壁をロジカルに乗り越えるためのコードを見てきました。
「動けばいいや」のコードから、「エラーが起きることを前提に守りを固めた」コードへ。
ここをクリアできたあなたなら、もうVBScriptの基礎は完全にマスターしています。自信を持って、日々の業務自動化にこの知見を役立ててくださいね!
