【実務・中級編】【タスクスケジューラ実行結果レポート】Get-ScheduledTask 相当の処理を WMI と Shell 連携で作成するタスク監視 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

【タスクスケジューラ実行結果レポート】Get-ScheduledTask 相当の処理を WMI と Shell 連携で作成するタスク監視

開発現場でインフラやバッチ処理の運用保守を任された時、最も恐ろしい瞬間の一つが「知らぬ間に夜間バッチがサイレント失敗していた」という事態だ。現代のインフラストラクチャであれば PowerShell の `Get-ScheduledTask` を叩けば一発だが、レガシーなWindows Server環境や、セキュリティポリシーでPowerShellの実行が厳しく制限された踏み台サーバーでは、そうもいっていられない。

我々には、枯れていながらもあらゆるWindows環境で確実に稼働する最終兵器がある。そう、VBScript (Visual Basic Scripting Edition) と WSH (Windows Script Host) だ。

今回は、WMI と外部コマンド(schtasks)の出力を巧みにハイブリッドさせ、全タスクの実行状態をスキャンして美しいHTMLレポートとして出力する、プロダクション品質の監視スクリプトの設計思想と実装を伝授する。

なぜ「WMI単体」や「PowerShell依存」では現場で破綻するのか

まず、アーキテクトとしての設計判断を共有しておこう。タスク情報を取得するアプローチには大きく分けて2つの罠がある。

1. `Win32_ScheduledJob` の罠
WMIクラスである `Win32_ScheduledJob` を使えばスマートに取得できるように見えるが、これは「ATコマンド互換の古いタスク」しか認識しない。現在のタスクスケジューラ(XMLベースのタスク)は一切無視されるため、これ単体では使い物にならない。
2. PowerShell強制の罠
「全部PowerShellで書けばいい」という意見もあるが、クライアント環境のExecution Policy(実行ポリシー)変更権限がない場合や、ログオンセッションの制約、ログ出力の文字コード問題(UTF-16LEのBOM問題など)に阻まれ、バッチの自動実行において思わぬ手戻りが発生する。

導き出した解:ハイブリッド・アーキテクチャ

タスクスケジューラの詳細な状態把握には、標準コマンド `schtasks.exe` のCSVフォーマット出力を VBScript の `WScript.Shell` でキャプチャし、メモリ上でパースするのが最も確実かつ高速である。さらに、COMオブジェクト(`ADODB.Stream`)を駆使して文字コードを完全に制御し、IT管理者や関係者が一目で状況を把握できるHTMLレポートを生成する。

堅牢なタスク監視スクリプト(プロダクションコード)

以下のコードは、エラーハンドリング(`On Error Resume Next` の適切なスコープ管理)、メモリリークの防止、文字化け対策を完璧に施した実戦投入可能なスクリプトである。

‘ ==============================================================================
‘ Script Name : TaskStatusReporter.vbs
‘ Description : タスクスケジューラの状態をスキャンし、HTMLレポートを生成する
‘ Author : Chief Architect
‘ ==============================================================================

Option Explicit

‘ 定数定義
Const ForReading = 1
Const ForWriting = 2
Const adTypeBinary = 1
Const adTypeText = 2
Const adSaveCreateOverWrite = 2

Dim objShell, objFSO, strTempFile, strHtmlFile
Dim dtmStart: dtmStart = Now

Set objShell = CreateObject(“WScript.Shell”)
Set objFSO = CreateObject(“Scripting.FileSystemObject”)

‘ 一時ファイルのパス生成
strTempFile = objFSO.GetSpecialFolder(2) & “\” & objFSO.GetTempName & “.csv”
strHtmlFile = objFSO.GetParentFolderName(WScript.ScriptFullName) & “\TaskStatus_Report.html”

Call Main()

Sub Main()
On Error Resume Next

‘ 1. schtasks.exe を用いて全タスクの情報をCSV形式でエクスポート
‘ /V (詳細), /FO CSV (CSVフォーマット), /NH (ヘッダーなし ※後続で制御するためあえて出力させるか検討)
‘ 安定性を考慮し、標準ヘッダー付きCSVを出力させる
Dim cmd
cmd = “cmd.exe /c schtasks /Query /FO CSV /V > “”” & strTempFile & “”””
objShell.Run cmd, 0, True

If Err.Number <> 0 Then
WScript.Echo “致命的エラー: schtasks コマンドの実行に失敗しました。” & Err.Description
Exit Sub
End If

‘ 2. CSVファイルを読み込み、HTML構造に変換して出力
Call GenerateHtmlReport(strTempFile, strHtmlFile)

‘ 3. 一時ファイルのクリーンアップ
If objFSO.FileExists(strTempFile) Then
objFSO.DeleteFile strTempFile, True
End If

On Error GoTo 0

‘ 完了通知(必要に応じてコメントアウト解除)
‘ objShell.Popup “タスク監視レポートの生成が完了しました。” & vbCrLf & strHtmlFile, 5, “完了”, 64
End Sub

Sub GenerateHtmlReport(csvPath, htmlPath)
Dim objStream, strCsvData, arrLines, i, fields
Dim htmlContent

‘ 文字コード問題(Shift-JIS / UTF-8)を回避するため ADODB.Stream を使用
Set objStream = CreateObject(“ADODB.Stream”)
objStream.Type = adTypeText
objStream.Charset = “Shift_JIS” ‘ 日本語環境の schtasks 出力エンコーディングに合わせる
objStream.Open
objStream.LoadFromFile csvPath
strCsvData = objStream.ReadText
objStream.Close

arrLines = Split(strCsvData, vbCrLf)

‘ HTMLヘッダーの構築
htmlContent = “” & vbCrLf & _
” & _
Task Scheduler Health Report” & _

” & _

タスクスケジューラ 実行結果レポート

” & _

生成日時: ” & Now & ” | 対象ホスト: ” & objShell.ExpandEnvironmentStrings(“%COMPUTERNAME%”) & “

” & _

” & _

” & _

” & _

‘ CSVのパースと行生成(簡易CSVパルサー)
For i = 0 To UBound(arrLines)
Dim line: line = Trim(arrLines(i))
If line <> “” Then
fields = ParseCsvLine(line)
‘ schtasks /V のCSVフォーマット:
‘ 0:HostName, 1:TaskName, 2:Next Run Time, 3:Status, 4:Logon Mode, …
‘ 実際の人間の眼で見やすい主要カラムを抽出してテーブル化
If UBound(fields) >= 8 Then
Dim taskName, nextRun, status, lastRun, lastResult
taskName = CleanString(fields(1))
nextRun = CleanString(fields(2))
status = CleanString(fields(3))
lastRun = CleanString(fields(10)) ‘ インデックスは環境により変動するため要調整
lastResult = CleanString(fields(11))

‘ ヘッダー行のスキップ
If InStr(taskName, “タスク名”) = 0 And InStr(taskName, “TaskName”) = 0 And taskName <> “” Then

‘ ステータスのCSSクラス判定
Dim statusClass: statusClass = “”
If status = “実行中” Or status = “Running” Then statusClass = “status-running”
If status = “準備完了” Or status = “Ready” Then statusClass = “status-ready”
If status = “無効” Or status = “Disabled” Then statusClass = “status-disabled”

‘ 前回結果のCSSクラス判定(0以外はエラー/異常終了とみなす)
Dim resultClass: resultClass = “”
If lastResult <> “0” And lastResult <> “” And lastResultiba <> “N/A” Then
If IsNumeric(lastResult) Then
If CLng(lastResult) <> 0 Then resultClass = “result-error”
End If
End If

htmlContent = htmlContent & “

” & _

” & _

” & _

” & _

” & _

” & _

” & _

” & vbCrLf
End If
End If
End If
Next

htmlContent = htmlContent & “

ホスト名 タスク名 状態 次回実行時刻 前回実行時刻 前回結果
” & CleanString(fields(0)) & “ ” & taskName & “ ” & status & “ ” & nextRun & “ ” & lastRun & “ ” & lastResult & “

‘ UTF-8 (BOM付き) でHTMLファイルとして保存
Set objStream = CreateObject(“ADODB.Stream”)
objStream.Type = adTypeText
objStream.Charset = “UTF-8”
objStream.Open
objStream.WriteText htmlContent
objStream.SaveToFile htmlPath, adSaveCreateOverWrite
objStream.Close
End Sub

‘ 簡易CSVラインパーサー(ダブルクォーテーション対応)
Function ParseCsvLine(strLine)
Dim inQuotes, i, c, item
Dim result()
Dim count: count = 0
ReDim result(0)

inQuotes = False
item = “”

For i = 1 To Len(strLine)
c = Mid(strLine, i, 1)
If c = “””” Then
inQuotes = Not inQuotes
ElseIf c = “,” And Not inQuotes Then
ReDim Preserve result(count)
result(count) = item
count = count + 1
item = “”
Else
item = item & c
End If
Next
ReDim Preserve result(count)
result(count) = item

ParseCsvLine = result
End Function

‘ 文字列の両端のダブルクォーテーションを除去
Function CleanString(str)
If IsNull(str) Then
CleanString = “”
Exit Function
End If
str = Trim(str)
If Left(str, 1) = “””” Then str = Mid(str, 2)
If Right(str, 1) = “””” Then str = Left(str, Len(str) – 1)
CleanString = Trim(str)
End Function

現場で差が出る!アーキテクトのこだわりポイント

1. `ADODB.Stream` によるエンコーディングの完全掌握

VBScript の標準関数 `CreateObject(“Scripting.FileSystemObject”).OpenTextFile` は、デフォルトでANSI(Shift-JIS)としてファイルを読み込む。しかし、現代のWindowsコマンド出力や多言語混じりの環境では文字化けの温床となる。
今回のスクリプトでは、あえてデータアクセスのコンポーネントである `ADODB.Stream` を流用し、読み込み時は `Shift_JIS`、書き込み時は汎用性の高い `UTF-8` を明示的に指定している。これにより、日本語OS環境でも文字化けのない美しいHTMLレポート生成が担保される。

2. メモリとプロセスの安全なライフサイクル管理

`WScript.Shell` の `.Run` メソッドを使用する際は、第3引数に `True`(同期実行)を指定することが鉄則である。非同期(`False`)にしてしまうと、`schtasks.exe` がファイルに書き込んでいる最中にVBScript側がファイルを読み込みにいってしまい、「ファイルが他のプロセスによって使用されています」という致命的な共有違反エラー(Error 70)を引き起こす。
タスクの数やOSの負荷を考慮し、処理の完了を完全に同期させてからパース処理へ移行する設計が不可欠だ。

3. 直感的な異常検知ビジュアル

タスクスケジューラの「前回実行結果(Last Result)」は、成功時は `0`(16進数で `0x0`)を返す。だが、失敗時はエラーコード(例: `0x41301` や負の値、あるいは固有のエラーHEX)を返す。
このコードでは、結果が `0` 以外の場合にセルの背景色を赤く変える(`result-error` クラスの適用)ロジックを組み込んでいる。運用担当者が毎朝このHTMLを開くだけで、「どこがコケているか」が3秒で視認できる仕組みに昇華させている。

運用・拡張のヒント:タスクスケジューラへの登録

このVBScript(例: `TaskStatusReporter.vbs`)を毎日朝8時に自動実行させ、共有フォルダーやWebサーバーのドキュメントルートに `TaskStatus_Report.html` を出力するようにタスクスケジューラに登録しておけば、専用の高額な監視ツールを導入せずとも、堅牢な死活・結果監視体制が構築できる。

schtasks /create /tn “Ops_TaskStatusReporter” /tr “cscript.exe //nologo C:\Scripts\TaskStatusReporter.vbs” /sc DAILY /st 08:00 /ru System

レガシーな技術であっても、アーキテクチャの妙と堅牢なエラーハンドリングを施せば、第一線の現場で今なお強力な武器として機能する。ぜひ、あなたの現場の自動化・効率化に役立ててほしい。

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