Windows > WSH > 特定のプロセスの終了を検出する

目的

特定の単一のプロセスが終了した際に、何か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]
最終更新:2009年01月15日 02:54