WMIとVBAで実現する!特定Windowsプロセスの死活監視と異常検知の自動化システム

Tech

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

WMIとVBAで実現する!特定Windowsプロセスの死活監視と異常検知の自動化システム

【背景と目的】

基幹システムと連携する外部プロセスのハングアップや強制終了を検知できず、データ連携エラーや業務遅延が発生する課題を解決します。

【処理フロー図】

graph TD
A["監視開始"] --> B["WMIクエリ実行"]
B --> C{"対象プロセスは存在するか?"}
C -->|No: 異常検出| D["異常ログの記録 & ユーザー通知"]
C -->|Yes: 正常稼働| E{"メモリ使用量は閾値内か?"}
E -->|No: 異常検出| D
E -->|Yes: 正常稼働| F["一定時間スリープ"]
F --> B

※上記のフローに従い、バックグラウンドで指定したプロセスのステータスを一定間隔で巡回監視します。

【実装:VBAコード】

外部参照設定を不要にするため、WMIへの接続は後期バインディング(Late Binding)で行います。また、ミリ秒単位で待機処理を行うため、64bit環境に対応した Sleep APIを宣言しています。

Option Explicit

' 64bit/32bit両対応のSleep API宣言
#If VBA7 Then

    Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else

    Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If

' 監視制御用のフラグ
Private IsMonitoring As Boolean

''' <summary>
''' プロセス監視を開始するメインルーチン
''' </summary>
Public Sub StartProcessMonitoring()
    Dim targetProcess As String
    Dim memoryThresholdMB As Double
    Dim intervalSeconds As Long

    ' --- 設定値 ---
    targetProcess = "chrome.exe"       ' 監視対象のプロセス名
    memoryThresholdMB = 500#           ' メモリ異常検知の閾値 (MB)
    intervalSeconds = 5                ' 監視インターバル (秒)
    ' --------------

    Dim wmiService As Object
    Dim query As String
    Dim processList As Object
    Dim proc As Object
    Dim processCount As Long
    Dim memUsageMB As Double
    Dim logRow As Long

    ' 画面更新と自動計算を停止して高速化・チラつき防止
    With Application
        .ScreenUpdating = False
        .Calculation = xlCalculationManual
        .EnableEvents = False
    End With

    On Error GoTo ErrorHandler

    ' WMIサービスへの接続
    Set wmiService = GetObject("winmgmts:\\.\root\cimv2")
    IsMonitoring = True
    logRow = Sheet1.Cells(Sheet1.Rows.Count, "A").End(xlUp).Row + 1

    ' ログシートのヘッダー準備
    If logRow = 2 And Sheet1.Range("A1").Value = "" Then
        Sheet1.Range("A1:D1").Value = Array("日時", "プロセス名", "状態", "メモリ使用量(MB)")
    End If

    MsgBox "プロセス監視を開始します(Escキーまたはブレークで停止可能)", vbInformation, "監視開始"

    Do While IsMonitoring
        processCount = 0
        memUsageMB = 0

        ' WMIクエリの作成と実行
        query = "SELECT * FROM Win32_Process WHERE Name = '" & targetProcess & "'"
        Set processList = wmiService.ExecQuery(query)

        ' プロセス情報の解析
        For Each proc In processList
            processCount = processCount + 1
            ' WorkingSetSize (バイト単位) を MB 単位に変換
            memUsageMB = memUsageMB + (CDbl(proc.WorkingSetSize) / 1024 / 1024)
        Next proc

        ' シートへログを出力(高速化のため配列に格納して一括出力)
        Dim logData(1 To 1, 1 To 4) As Variant
        logData(1, 1) = Now
        logData(1, 2) = targetProcess

        ' 異常検知ロジック
        If processCount = 0 Then
            logData(1, 3) = "【異常】プロセス未起動"
            logData(1, 4) = 0
            Call WriteLog(logData, logRow)
            Call AlertUser(targetProcess & " が起動していません!")
        ElseIf memUsageMB > memoryThresholdMB Then
            logData(1, 3) = "【警告】メモリ過大消費"
            logData(1, 4) = Round(memUsageMB, 2)
            Call WriteLog(logData, logRow)
            Call AlertUser(targetProcess & " のメモリ使用量が閾値を超過しています: " & Round(memUsageMB, 2) & " MB")
        Else
            logData(1, 3) = "正常稼働中"
            logData(1, 4) = Round(memUsageMB, 2)
            Call WriteLog(logData, logRow)
        End If

        logRow = logRow + 1

        ' OSに制御を戻し、Excelのフリーズを防止
        DoEvents

        ' 指定秒数待機 (Sleepはミリ秒指定)
        Sleep intervalSeconds * 1000
    Loop

CleanExit:
    ' 画面更新と自動計算を元に戻す
    With Application
        .ScreenUpdating = True
        .Calculation = xlCalculationAutomatic
        .EnableEvents = True
    End With
    Exit Sub

ErrorHandler:
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical, "エラー終了"
    IsMonitoring = False
    Resume CleanExit
End Sub

''' <summary>
''' 監視を安全に停止させるルーチン
''' </summary>
Public Sub StopProcessMonitoring()
    IsMonitoring = False
    MsgBox "監視停止リクエストを受け付けました。", vbInformation, "監視停止"
End Sub

''' <summary>
''' ログシートへの高速書き込み処理
''' </summary>
Private Sub WriteLog(ByRef data() As Variant, ByVal targetRow As Long)
    Sheet1.Cells(targetRow, 1).Resize(1, 4).Value = data
End Sub

''' <summary>
''' 異常検知時のアラート通知処理
''' </summary>
Private Sub AlertUser(ByVal message As String)
    ' 簡易的にステータスバーとビープ音で通知
    Application.StatusBar = "⚠️ " & message
    Beep
    ' 必要に応じてここにメール送信やTeams通知ロジックを組み込み可能
End Sub

【技術解説】

  1. WMI(Windows Management Instrumentation)の活用 GetObject("winmgmts:\\.\root\cimv2") を利用して、Windows OSのシステム管理情報へアクセスしています。Win32_Process クラスに対してSQLに似たクエリを投げることで、実行中のプロセス一覧やそのリソース消費状況(メモリ使用量等)をリアルタイムに取得できます。

  2. Win32 API Sleep によるCPU負荷軽減 VBA標準の Application.Wait は1秒単位でしか待機できず、待機中もExcelがビジー状態になることがあります。Win32 APIの Sleep を使うことで、ミリ秒単位の制御が可能になり、待機中のCPU使用率を極限まで下げることができます。

  3. 配列書き出しによるシート操作の高速化 毎サイクルごとにセルへ個別書き込みを行うと動作が重くなるため、1行分のデータを一度配列(logData)に格納し、Resize メソッドを用いてセルへ一括転記しています。これにより描画負荷を最小限に抑えています。

【注意点と運用】

  • 無限ループとExcelのフリーズ回避 DoEvents をループ内に配置しないと、Excelが完全に操作不能(ホワイトアウト)になります。必ず DoEvents を挟み、必要に応じて StopProcessMonitoring を実行できるように設計してください。

  • 管理者権限の壁 他ユーザーが実行しているプロセスや、システム特権で動作しているサービスプロセスを取得する場合、Excel(VBA)を「管理者として実行」しなければWMIクエリが一部の情報を取得できず、エラーまたは0件となる場合があります。

  • メモリリークの監視単位 WorkingSetSize は物理メモリの使用量を示します。対象プロセスの構造(マルチプロセス型など)によっては、親プロセスだけでなく子プロセスのメモリも合算して監視対象にする必要があります。

【まとめ】

  • 定期実行の間隔は業務に合わせる:頻繁な監視(1秒以下)はPC本体の負荷になるため、5秒〜30秒間隔での運用を推奨します。

  • 記録シートのクリーンアップ:ログが数万行に達するとExcelの動作が重くなるため、一定行数を超えたら古いログを削除、または別ファイルへ退避するロジックを併用してください。

  • 通知の多重化:本コードの AlertUser 内に、OutlookやAPI連携を用いたチャットツール(Teams/Slack)への自動投稿を組み込むことで、完全な無人監視体制が構築できます。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました