システムを運用している場合に、例えばサーバー上で何らかのアプリケーションを常時立ち上げておかないといけないという状況は無いでしょうか?
本来、常時起動が必要な場合は、Windowsアプリケーションであれば「Windowsサービス」としてバックグランドで動かす設計で作成するべきですが、最初は常時起動を前提としていなかったり、パッケージのアプリケーションでサービス化出来なかったり、事情があって普通のWindowsアプリケーションをサーバー上で常時起動しているケースもあるかと思います。
でも、その場合は以下のような問題が有ります。
- リモートデスクトップでログオフするとアプリケーションも終了する。
- 異常データなどのイレギュラーなケースでアプリケーションが強制終了する。
このアプリケーションが業務やシステムで重要な機能を担っていた場合は、知らない間に落ちていたら大変なので、人が目視でチェックするなどのアナログな運用が発生する場合もあるかと思いますが、そんなものは自動化してしまいましょう。
指定したプロセスの死活チェックと自動実行サンプルコード
Option Explicit
Call Main()
Sub Main()
'WMIにて使用する各種オブジェクトを定義・生成する。
Dim oClassSet
Dim oClass
Dim oLocator
Dim oService
Dim TargetAppName
Dim ExistFlag
TargetAppName = "notepad.exe"
ExistFlag = False
'ローカルコンピュータに接続する。
Set oLocator = WScript.CreateObject("WbemScripting.SWbemLocator")
Set oService = oLocator.ConnectServer
'クエリー条件を WQL にて指定する。
Set oClassSet = oService.ExecQuery("Select * From Win32_Process")
'コレクションを解析する。
For Each oClass In oClassSet
'対象のプロセス名が存在するかを判定します。
If InStr(oClass.Description,TargetAppName) > 0 Then
'対象のプロセスが存在すればフラグを立てます。
ExistFlag = True
End If
Next
'存在チェックフラグがFalseの場合に、対象のEXEを起動します。
If ExistFlag = False Then
Call Target_Process_Start()
End If
'使用した各種オブジェクトを後片付けする。
Set oClassSet = Nothing
Set oClass = Nothing
Set oService = Nothing
Set oLocator = Nothing
End Sub
'指定したEXEを起動します。
Sub Target_Process_Start()
Const vbHide = 0 'ウィンドウを非表示
Const vbNormalFocus = 1 '通常のウィンドウで、最前面のウィンドウ
Const vbMinimizedFocus = 2 '最小化で、最前面のウィンドウ
Const vbMaximizedFocus = 3 '最大化で、最前面のウィンドウ
Const vbNormalNoFocus = 4 '通常のウィンドウで、最前面ではない
Const vbMinimizedNoFocus = 6 '最小化で、最前面にはならない
Dim objWShell
Dim TargetExe
TargetExe = """C:\windows\system32\notepad.exe"""
Set objWShell = CreateObject("WScript.Shell")
'対象のEXEを起動します。
objWShell.Run TargetExe, vbNormalFocus, False
Set objWShell = Nothing
End Sub
処理解説
今回はWMIをVBScriptから呼び出して、現在稼働しているプロセス名の一覧を取得しています。その一覧をループ処理で回して、指定したプロセス名が存在しなければ、対象のアプリケーションが落ちていると判断し、強制的にアプリケーションを起動します。
このバッチをタスクスケジューラーで何十分毎などで起動するように設定して使用する想定です。
今回のサンプルコードではメモ帳のプロセスを監視して起動させていますが、ここ(16行目と61行目)を任意のプロセス名や実行ファイルのパスに書き換えてください。プロセス名はタスクマネージャーでプロセスの一覧(Windows10系であればタスクマネージャーの「詳細」タブ)で確認してください。
後、61行目でシェルに実行ファイルのパスを渡す際の文字列を定義していますが、Program Files以下にあるパスの場合は空白がファイルパスの文字列に混ざる為、ダブルクォーテーションを渡す為にダブルクォーテーションを三つ繋げています。VBScriptではこうすることで本来文字列として扱うための区切り文字であるダブルクォーテーションをただの文字列として扱うことが出来ます。
尚、私が業務で稼働させているプロセス監視用のバッチでは、プロセスを起動する処理と併せてメールで通知もさせています。VBScriptでメール送信を行う処理は過去に記事を書いているので良ければそちらもご参照ください。
注意点
バッチ処理でアプリケーションを起動させる場合、バッチを動作させるサーバーにログオン済みのセッションが存在しないと、対象のアプリケーションはバックグランドで起動してしまいます。
その為、起動していても画面には表示されず、タスクマネージャーのプロセス一覧を見ないと起動しているか判別が付かなくなります。
この状態も色々支障があると思うので、アプリケーションの起動まで自動化させる場合は、対象のサーバのセッションはログオフせず「切断」でセッションを残しておく必要があります。※この辺りが少しうろ覚えですが、タスクスケジューラーを設定する際のプロパティの「ユーザーがログオンしているときのみ実行する」も併せて設定しておかないとセッションが残っていようがバックグランドで起動してしまうような気がします・・・。
WMIとは
今回は「WMI」という機能を利用して希望する処理を実現しています。
Windowsサーバーの運用や構築に関する業務経験がない場合、これまで聞いたことがないという人もいるかもしれないので、参考までに簡単に説明もしておきます。
Windows Management Instrumentation (WMI) は、Windows Driver Modelへの拡張の一種で、システムの構成要素について情報収集と通知を行うオペレーティングシステム (OS) のインタフェースを提供する。
上記の一文だけでは分かりにくいですが、「システムの情報収集と通知を行う」と記載してあります。
この「システムの情報収集と通知」とは、CPUの負荷状況を取得したり、NICの通信量を取得することだったり、何らかの異常を検知した時にそれを管理者に通知する機能のことを指します。
この機能だけであれば、Windows環境に限定されない「SNMP」という汎用的なプロトコルを使えば事足りるのですが、WMIはWindows独自に開発され、Windows固有の様々な情報を扱えます。また、当ブログで紹介したVBScriptなどのプログラミング言語を用いてWindowsのサーバーやクライアントの管理作業を自動化するといったことも用意に行えるように設計されているという特徴があります。
WMIでは他にも様々な情報が取り出せる為、もし興味があれば調べてもらえると良いかと思います。
今回のサンプルコードの紹介は以上です。今回も読んで頂きましてありがとうございました。