目的
特定の単一のプロセスが終了した際に、何かWSHで処理を実行させたい場合などに、プロセスの有無を調べて、存在しなかったら処理を行うサンプルスクリプト。
この例の場合は、McAfeeの手動スキャン(SCAN32.exe)のプロセスの有無を調べて、終了していたら
Windowsを強制終了する... というもの。
ただ、後日SCAN32.exeコマンドで、予め作成されたタスクを実行するコマンドラインオプションを指定することで、コマンドラインコンソールに同期して実行される(SCAN32.exeが終了するまでプロンプトに処理が戻ってこない)ので、普通に連続してSCAN32.exeのタスク実行コマンドと、シャットダウンコマンドを記述さればいいだけだった...
(´・ω・`)。
内容
<?xml version="1.0"?>
<!--日本語-->
<package>
<job id="ShutdownAfterSCAN32">
<script language="VBScript">
<![CDATA[
'プロセス検査時間設定
' この設定の場合最大6時間待機
Const RETRY_TIME_WAIT = 300000 '再試行待機時間(5分)
Const RETRY_COUNT_MAX = 72 '再試行最大回数
'TODOエラーハンドリングを追加すること
'処理0: 処理の確認
' ダイアログで「はい」を押下しない限り
' プロセスの検索~シャットダウンを実行しません。
Dim vMsgBoxResult
vMsgBoxResult = MsgBox("SCAN32.exeプロセスが終了次第シャットダウンします。" & vbCrLf & _
"よろしいですか?" & vbCrLf & _
"(SCAN32.exeプロセスがいない場合" & vbCrLf & _
" 単なるシャットダウンになります。)" , vbOkCancel, "確認")
If (vMsgBoxResult = vbCancel) Then
Call MsgBox("中止しました。", vbOkOnly, "確認")
Call WScript.Quit(1)
End If
Dim oWMIService
Set oWMIService = GetObject("winmgmts:\root\cimv2")
Dim bAllowShutdown 'シャットダウン許可
bAllowShutdown = False
Dim vI
For vI = 1 To RETRY_COUNT_MAX Step 1
Dim bExist 'プロセス存在
bExist = False
'処理1: WMIを使ってSCAN32.exeプロセス(McAfeeのスキャン)が
' 起動中かどうか評価
' .1 検出した場合、一定時間待機して再度評価
' .2 検出しなかった場合シャットダウンを実行
' .3 検出した場合で、一定回数待機を繰り返した場合
' スクリプト自体を終了します。その場合は
' シャットダウンしません。
Dim oProcList
Set oProcList = oWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'SCAN32.exe'")
Dim oProc
For Each oProc In oProcList
bExist = True
Exit For
Next
If (bExist) Then
'プロセスが見つかった場合
Call WScript.Sleep(RETRY_TIME_WAIT)
Else
'プロセスが見つからなかった場合
' シャットダウン許可
bAllowShutdown = True
Exit For
End If
Next
If (bAllowShutdown) Then
'シャットダウン許可がある場合
'処理2: SCAN32.exeのプロセスが見つからなかった場合
' WMIを使ってOSをシャットダウン
Set oWMIService = GetObject("winmgmts:{impersonationLevel=impersonate, (Shutdown)}\root\cimv2")
Dim oSystemList
Set oSystemList = oWMIService.ExecQuery("SELECT * FROM Win32_OperatingSystem")
Dim oSystem
For Each oSystem In oSystemList
'オペレーティングシステムにシャットダウンコマンド
Call oSystem.Win32Shutdown(5) '5 = (1=終了 | 4=強制)
Next
Else
'シャットダウン許可が下りなかった場合
' (再試行最大回数を過ぎた場合)
Call MsgBox("時間内にSCAN32が終了しませんでした。")
Call WScript.Quit(1)
End If
'正常終了
Call WScript.Quit(0)
]]>
</script>
</job>
</package>
プロセスを検出するのに、WMIのWin32_Processクラスを用い、オペレーティングシステムのシャットダウンを実行するのも、Win32_OperatingSystemクラスを用いている。
実はWin32_OperatingSystemインスタンスを取得する際に指定しているモニカ文字列
{impersonationLevel=impersonate, (Shutdown)}
の部分は、どういうことなのか?良く分かっていない
(´・ω・`)。
そもそもWMIのリファレンス自体がCOMのリファレンスだったり?と良く分からない部分が多いのが事実である。
その辺は要調査。
上述のコードの細かい処理については割愛。
Network COM+?だからなのか、RPC受信や、NetBIOSセッションを受信できるようにWindowsファイアウォールを構成しておけばリモートのPCもシャットダウンが可能だった。
ちなみにこのスクリプト、当初は確認ダイアログなどを実装しておらず、またループ処理もWindowsのタスクスケジューラで実装していた。
しかし、タスクスケジューラでのプロセスの有無の検出間隔を短くし過ぎてしまい、またタスクが有効なままコンピュータをシャットダウンしてしまったものだから、起動してスクリプトが走ると即シャットダウンという恐ろしい状態になってしまった。
オペレーティングシステムのシャットダウン系のタスクを実装する場合は、コンピュータが起動して一定時間内はシャットダウンしにいかないような安全設計をしておく必要があると感じた。
最終更新:2009年01月15日 02:54