こんにちは!VBScriptの世界へようこそ。
業務の自動化を進めていくと、必ずと言っていいほど直面する壁があります。それが「同じスクリプトの二重起動(多重実行)問題」です。
例えば、タスクスケジューラで定期実行している処理が終わらないうちに、次の実行時間が来てしまったり、ユーザーが「あれ、動いてないな?」と勘違いして何度もアイコンをダブルクリックしてしまったり……。
これが原因で、同じファイルに同時に書き込みにいってしまい、データが破損したり、ファイルがロックされてエラーで強制終了したりする悲劇が起きるのです。
今回は、現場のインフラを守る「ロックファイル」を使ったスマートな排他制御(二重実行ガード)の極意を、優しく、そして本質的に解説していきますね。ここをクリアすれば、あなたの書くスクリプトはプロの現場でも通用する「堅牢なシステム」に生まれ変わりますよ!
—
1. なぜ排他制御(二重起動防止)が必要なのか?
VBScriptは、Windows環境で手軽に動かせる最高の自動化ツールですが、裏を返せば「動かそうと思えば、何個でも同時に同じスクリプトを起動できてしまう」という危うさを持っています。
もし、顧客データを処理するVBScriptが二重起動したらどうなるでしょうか?
- 処理Aと処理Bが同時に同じExcelファイルを開き、片方が上書き保存した瞬間に、もう片方のデータが消え去る。
- ログファイルへの書き込み権限が競合し、「書き込みできません」という致命的なエラー(Run-time error)でスクリプトがクラッシュする。
こうしたカオスを防ぐために、「今、俺はこの処理を独占して実行中だ!」という目印(ロックファイル)を立て、他のプロセスの侵入をブロックする仕組みが必要なのです。
—
2. ロックファイル方式の基本戦略
今回実装する仕組みは、非常にシンプルかつ強力です。料理で例えるなら「調理場の入口に『使用中』の札をかける」アプローチです。
1. スクリプト開始時:
指定した場所に「`lock.tmp`」のような空のファイルが存在するかチェックする。
2. 存在しない場合(安全):
すぐにロックファイルを作成し、「今から俺が支配する!」と宣言して処理を進める。
3. 存在する場合(すでに誰かが動いている):
「おっと、先客がいるな」と判断し、二重起動とみなしてメッセージを出して優しく終了する。
4. スクリプト終了時(正常・異常問わず):
自分が作ったロックファイルを責任を持って削除し、次の人のために道を開ける。
この「確実にロックを外す(後片付けをする)」という部分が、エンジニアとしての腕の見せどころになります。
—
3. 【実践】コピペで使える!二重実行ガード付きVBScript
それでは、実際のコードを見てみましょう。そのままメモ帳に貼り付けて、拡張子を `.vbs` にしていたらすぐにテストできます。
Option Explicit
‘ =========================================================================
‘ VBScript 排他制御(ロックファイルによる二重起動防止)サンプル
‘ =========================================================================
Dim objFSO, strLockFile, wshShell
Set objFSO = CreateObject(“Scripting.FileSystemObject”)
Set wshShell = CreateObject(“WScript.Shell”)
‘ ロックファイルのパス(スクリプトと同じ場所に作成する)
strLockFile = objFSO.BuildPath(objFSO.GetParentFolderName(WScript.ScriptFullName), “script_running.lock”)
‘ — 1. 二重起動チェック —
If objFSO.FileExists(strLockFile) Then
‘ すでにロックファイルが存在する場合は多重起動と判定
MsgBox “現在、このスクリプトは別のプロセスによって実行中です。” & vbCrLf & _
“処理が終了するまでしばらくお待ちください。”, vbExclamation, “二重起動ガード”
WScript.Quit
End If
‘ — 2. ロックの取得(ファイルの作成) —
‘ Trueを指定して、もし同名ファイルがあっても上書き(念のため)
On Error Resume Next
Dim objLockFile
Set objLockFile = objFSO.CreateTextFile(strLockFile, True)
If Err.Number <> 0 Then
MsgBox “ロックファイルの作成に失敗しました。権限を確認してください。”, vbCritical, “エラー”
WScript.Quit
End If
On Error GoTo 0
objLockFile.Close
Set objLockFile = Nothing
‘ ★ここから下に、本来行いたい重い処理やメインの業務ロジックを記述します★
WScript.Echo “メイン処理を開始します…”
‘ 【シミュレーション】処理に10秒かかると仮定(この間に別のスクリプトを叩いてみて!)
WScript.Sleep 10000
WScript.Echo “メイン処理が完了しました。”
‘ — 3. 終了処理(ロックファイルの確実に解放) —
‘ エラーが発生しても必ずロックを外せるように、最後にファイルを削除する
If objFSO.FileExists(strLockFile) Then
objFSO.DeleteFile strLockFile, True
End If
‘ オブジェクトの解放
Set objFSO = Nothing
Set wshShell = Nothing
WScript.Echo “スクリプトを正常終了しました。”
—
4. コードの深掘りと「知見」の共有
ここからは、なぜこのような書き方をしているのか、実務で役立つプロの知見をいくつかお伝えします。
① パスの指定には `ScriptFullName` を使おう
`WScript.ScriptFullName` は、「今動いているこのスクリプト自体の絶対パス」を返してくれます。これと `Scripting.FileSystemObject` の `GetParentFolderName` を組み合わせることで、「スクリプトがどこから実行されても、必ずそのスクリプトと同じフォルダにロックファイルを作る」という安全性を担保できます。
カレントディレクトリ(`CurDir`)に依存させないのが、プロのバッチを書く上での鉄則です。
② エラー時の「ゾンビロック」にどう立ち向かうか?
初学者が最もハマるのが、「メイン処理の途中でエラーが起きたり、ユーザーが無理やりタスクマネージャーで強制終了したりしたときに、ロックファイルが残り続けて二度と動かなくなる現象(ゾンビロック)」です。
今回のコードではシンプルに実装していますが、本番の運用環境では以下の工夫を取り入れるとさらに堅牢になります:
- タイムスタンプのチェック:ロックファイルの作成日時を確認し、「前回の作成から3時間以上経過していれば、前回の処理は異常終了したとみなして強制的にロックを削除して処理を進める」という自己治癒ロジックを入れる。
- `On Error Resume Next` の適切な管理:ファイル操作の前後でのみエラーをトラップし、予期せぬバグを隠蔽しないようにする。
—
まとめ:ここをクリアすればVBScriptの基本はバッチリ!
いかがでしたでしょうか?
今回は、ロックファイルを使った王道かつ最強の排他制御について解説しました。
- スクリプト開始時に「目印(ファイル)」があるか確認する。
- なければ自分が目印を置いて処理を走らせる。
- 終わったら必ず目印を片付ける。
このシンプルなルールを組み込むだけで、あなたの書くVBScriptは「ただの自動化お助けツール」から、「インフラ事故を防ぐ信頼性の高い業務システム」へとランクアップします。
現場での運用エラーに悩まされないために、ぜひ次の開発からこの二重起動ガードを取り入れてみてくださいね。応援しています!
