VBScript (Visual Basic Scripting Edition) を掌握する極限の知見:WMI でプリンタの悲鳴を聞き逃さない!印刷ジョブ監視と自動復旧への道
やあ、みんな! VBScript の世界へようこそ!
「マクロの記録」ボタンをポチポチするだけじゃ物足りなくなってきた君、もっと賢く、もっと自動化された世界を目指したい君。そんな君たちのために、今日は VBScript の奥深い世界、特に WMI (Windows Management Instrumentation) という強力なツールを使った、オフィス印刷環境の運用を劇的に楽にするテクニックを伝授しよう。
今回のテーマは 「印刷ジョブ監視と自動復旧」 だ。ネットワークプリンタで「用紙切れ」や「エラー」が出て、大事な印刷ジョブが止まっちゃった! なんて経験、誰にでもあるはず。そんな時、手動でプリンタをリセットしたり、ジョブを削除したりするのは、もう終わりにしよう。VBScript と WMI を使えば、そんな面倒な作業を自動化できちゃうんだ。
この記事を読み終える頃には、君は VBScript の基礎はもちろん、WMI を使ってシステムの状態を「見る」という、一歩進んだスキルを身につけているはずだよ。「ここをクリアすれば、VBScript の基本はバッチリですよ」って、自信を持って言えるように、一緒に学んでいこう!
なぜ VBScript なのか? そして WMI とは?
まずは、なぜこの自動化に VBScript を使うのか、そして WMI というのが一体何なのか、その本質を掴んでおこう。
VBScript (Visual Basic Scripting Edition) の魅力:手軽さと強力さのハイブリッド
VBScript は、Windows 環境で手軽に使えるスクリプト言語だ。特別な開発環境は必要なく、メモ帳があればすぐに書き始められる。それでいて、ファイル操作、レジストリ操作、そして今回のように WMI を通じてシステム情報を取得したり、操作したりといった、かなり強力な機能も持っているんだ。
- 手軽さ: メモ帳と Windows さえあればOK!
- 実行環境: Windows に標準搭載されている WSH (Windows Script Host) で動く。
- 汎用性: システム管理、ファイル整理、簡単なアプリケーション連携など、様々な場面で活躍する。
「でも、VB.NET とか VBA とか、もっと高機能な言語もあるんじゃない?」って思うかもしれない。確かにそうだ。でも、VBScript の真価は、「ちょっとした自動化」 や 「手軽にシステムにアクセスしたい」 という場面で発揮される。今回の印刷ジョブ監視のように、日常的な運用で発生する「困った」をサクッと解決するのに、VBScript は最適なパートナーなんだ。
WMI (Windows Management Instrumentation):Windows の「健康診断」と「操作」を可能にする仕組み
WMI は、Windows システムのあらゆる情報を管理し、操作するための標準的なインターフェースなんだ。例えるなら、Windows の「健康診断」をして、異常があれば「治療」もできる、そんな強力な仕組みだ。
WMI を使うことで、以下のようなことが可能になる。
- システム情報の取得: CPU 使用率、メモリ使用量、インストールされているソフトウェア、そして今回使う 印刷ジョブの情報 など、様々な情報を取得できる。
- デバイスの管理: プリンタの状態確認や、サービスの開始・停止なども可能。
- イベントの監視: 特定のイベントが発生したときに通知を受け取ることもできる。
WMI は、`Win32_` で始まるクラス群(オブジェクトのことだと思ってくれ)を通して、様々な管理機能を提供する。今回注目するのは、`Win32_PrintJob` というクラスだ。このクラスを覗くことで、現在プリンタに溜まっている印刷ジョブの詳細な情報を取得できるんだ。
印刷ジョブ監視の基本:WMI で `Win32_PrintJob` を覗いてみよう
さて、いよいよ本題だ! WMI を使って、印刷ジョブの情報を取得する方法を見ていこう。
1. WMI オブジェクトへの接続
まずは、WMI サービスに接続するためのオブジェクトを作成する必要がある。これは VBScript のお約束だ。
‘ WMI サービスに接続するためのオブジェクトを作成
Set objSWbemServices = GetObject(“winmgmts:\\.\root\cimv2”)
‘ エラーハンドリングを有効にする (後述)
On Error Resume Next
- `GetObject(“winmgmts:\\.\root\cimv2”)`: これが WMI サービスに接続するための呪文のようなものだ。「`winmgmts`」は WMI を使うためのプロトコル、「`\\.\`」はローカルマシンを指し、「`root\cimv2`」は WMI の名前空間(情報の集まり)を指定している。
2. `Win32_PrintJob` クラスから情報を取得
次に、`Win32_PrintJob` クラスのインスタンス(つまり、個々の印刷ジョブ)を取得する。
‘ Win32_PrintJob クラスのインスタンスを取得
Set colPrintJobs = objSWbemServices.ExecQuery(“SELECT FROM Win32_PrintJob”)
‘ WMI クエリの実行結果をチェック
If Err.Number <> 0 Then
Wscript.Echo “WMI クエリの実行中にエラーが発生しました: ” & Err.Description
Wscript.Quit
End If
- `objSWbemServices.ExecQuery(“SELECT FROM Win32_PrintJob”)`: これは SQL のようなクエリ言語で、`Win32_PrintJob` クラスから全てのプロパティ(“)を持つオブジェクトを取得している。「`SELECT FROM Win32_PrintJob`」というクエリが、WMI の世界では「印刷ジョブの一覧ちょうだい!」というお願いになるんだ。
- `If Err.Number <> 0 Then …`: ここでエラーチェックをしている。WMI クエリは、権限がない場合などに失敗することがある。エラーがあれば、メッセージを表示してスクリプトを終了させる。
3. 取得したジョブ情報をループで処理
取得した印刷ジョブのリストを一つずつ見ていく。
‘ 印刷ジョブがあれば、それぞれの情報を表示
If colPrintJobs.Count = 0 Then
Wscript.Echo “現在、印刷ジョブはありません。”
Else
Wscript.Echo “— 印刷ジョブ一覧 —”
For Each objPrintJob In colPrintJobs
Wscript.Echo “ジョブ名: ” & objPrintJob.Name
Wscript.Echo “ジョブID: ” & objPrintJob.JobID
Wscript.Echo “ドキュメント名: ” & objPrintJob.DocumentTitle
Wscript.Echo “ステータス: ” & GetPrintJobStatus(objPrintJob.JobStatus) ‘ ステータスを分かりやすく表示
Wscript.Echo “——————–”
Next
End If
- `colPrintJobs.Count = 0`: 取得したジョブの数が 0 かどうかをチェック。
- `For Each objPrintJob In colPrintJobs`: `colPrintJobs` というコレクション(リスト)の中にある、それぞれの `objPrintJob` オブジェクトに対して、ループ処理を行う。
- `objPrintJob.Name`, `objPrintJob.JobID`, `objPrintJob.DocumentTitle`: `Win32_PrintJob` オブジェクトが持っているプロパティの一部だ。ジョブの名前、ID、ドキュメント名などを取得できる。
- `GetPrintJobStatus(objPrintJob.JobStatus)`: ここで、後述するカスタム関数 `GetPrintJobStatus` を呼び出している。`JobStatus` プロパティは数値で返ってくるので、それを人間が理解できる文字列に変換するためにこの関数を使っているんだ。
4. ステータスを分かりやすく表示する関数
`Win32_PrintJob` の `JobStatus` プロパティは、ビットフラグという形式で状態を表している。これは、複数の状態が同時にONになっている可能性があるためなんだ。例えば、「用紙切れ」と「エラー」が同時に発生している、といったケースだ。
このビットフラグを分かりやすい文字列に変換するために、以下のような関数を用意しよう。
‘ Win32_PrintJob の JobStatus を分かりやすい文字列に変換する関数
Function GetPrintJobStatus(statusValue)
Dim strStatus
strStatus = “”
If (statusValue And 1) = 1 Then strStatus = strStatus & “未定義, ” ‘ Undefined
If (statusValue And 2) = 2 Then strStatus = strStatus & “保留中, ” ‘ Printing
If (statusValue And 4) = 4 Then strStatus = strStatus & “印刷完了, ” ‘ Printing
If (statusValue And 8) = 8 Then strStatus = strStatus & “キャンセル中, ” ‘ Cancelling
If (statusValue And 16) = 16 Then strStatus = strStatus & “キャンセル済み, ” ‘ Cancelled
If (statusValue And 32) = 32 Then strStatus = strStatus & “エラー, ” ‘ Error
If (statusValue And 64) = 64 Then strStatus = strStatus & “用紙切れ, ” ‘ Paper Jam
If (statusValue And 128) = 128 Then strStatus = strStatus & “内部エラー, ” ‘ Printer Error
If (statusValue And 256) = 256 Then strStatus = strStatus & “用紙セットエラー, ” ‘ Paper Out
If (statusValue And 512) = 512 Then strStatus = strStatus & “トナー切れ, ” ‘ Low Toner
If (statusValue And 1024) = 1024 Then strStatus = strStatus & “ドアオープン, ” ‘ Door Open
If (statusValue And 2048) = 2048 Then strStatus = strStatus & “カバーオープン, ” ‘ Cover Open
If (statusValue And 4096) = 4096 Then strStatus = strStatus & “インク切れ, ” ‘ Ink Low
If (statusValue And 8192) = 8192 Then strStatus = strStatus & “出力トレイ満杯, ” ‘ Output Bin Full
If (statusValue And 16384) = 16384 Then strStatus = strStatus & “印刷中, ” ‘ Printing (again, often used interchangeably with 2)
If (statusValue And 32768) = 32768 Then strStatus = strStatus & “印刷待機中, ” ‘ Waiting
‘ 末尾のカンマとスペースを削除
If Right(strStatus, 2) = “, ” Then
strStatus = Left(strStatus, Len(strStatus) – 2)
End If
If strStatus = “” Then strStatus = “不明”
GetPrintJobStatus = strStatus
End Function
- `If (statusValue And X) = X Then`: これはビット演算の「AND」を使っている。`statusValue` の中に、特定のビット(状態)が立っている(1になっている)かどうかを判定しているんだ。例えば `statusValue And 32` は、`statusValue` の32番目のビットがONなら結果は32になり、そうでないなら0になる。この結果が `32` と一致するかどうかで、エラー状態かどうかを判断している。
- `strStatus = strStatus & “エラー, “`: 該当する状態が見つかったら、文字列に追加していく。
- `If Right(strStatus, 2) = “, ” Then …`: 最後に、追加した文字列の末尾に余分なカンマとスペースがあれば削除している。
このコードを保存して実行すると、現在プリンタに溜まっている印刷ジョブの名前、ID、ドキュメント名、そして分かりやすいステータスが表示されるはずだ。
応用編:エラー検知と自動復旧への道
さて、ここからが本番だ! 取得したジョブ情報を使って、エラーを検知し、自動的に復旧させる方法を考えてみよう。
1. エラー状態のジョブを特定する
先ほどの `GetPrintJobStatus` 関数を応用して、エラー状態になっているジョブを特定しよう。`Win32_PrintJob` の `JobStatus` プロパティは、エラー状態を示すビット(例: 32: Error, 64: Paper Jam, 256: Paper Out, 512: Low Toner など)が立っている場合に、それらのジョブを抽出できる。
2. エラー原因に応じたアクション
エラーを検知したら、それに合ったアクションを実行しよう。
- 用紙切れ・トナー切れ・出力トレイ満杯などの物理的な問題:
- 該当ジョブを 削除 する。
- 通知メールを送信 する(これは VBScript 単体では難しいので、Outlook オブジェクトなどを利用するか、外部ツールと連携する必要がある)。
- 管理者に ログファイルに記録 する。
- 一時的なプリンタエラー(プリンタがオフラインなど):
- ジョブを一旦保留 にして、しばらく待ってから 再送信 を試みる。
- プリンタの リセット を試みる(これは WMI の `Win32_Printer` クラスで可能だが、権限やプリンタドライバの対応に依存する)。
3. 自動再送信・削除のサンプルコード
ここでは、エラー状態のジョブを検知して、それを 削除 する簡単な例を紹介しよう。再送信やリセットは、さらに複雑な処理や、プリンタドライバ、OS のバージョンに依存する部分が増えるため、まずは「問題のあるジョブを一旦排除する」ことから始めるのが現実的だ。
‘ WMI サービスに接続
Set objSWbemServices = GetObject(“winmgmts:\\.\root\cimv2”)
On Error Resume Next
‘ Win32_PrintJob クラスのインスタンスを取得
Set colPrintJobs = objSWbemServices.ExecQuery(“SELECT FROM Win32_PrintJob”)
If Err.Number <> 0 Then
Wscript.Echo “WMI クエリの実行中にエラーが発生しました: ” & Err.Description
Wscript.Quit
End If
Dim bFoundErrors
bFoundErrors = False
‘ 印刷ジョブがあれば、それぞれの情報をチェック
If colPrintJobs.Count > 0 Then
Wscript.Echo “— 印刷ジョブのエラーチェック —”
For Each objPrintJob In colPrintJobs
Dim jobStatus
jobStatus = objPrintJob.JobStatus
‘ エラー状態を判定 (例: Error, Paper Jam, Paper Out, Low Toner など)
‘ 32: Error, 64: Paper Jam, 256: Paper Out, 512: Low Toner
If (jobStatus And 32) = 32 Or (jobStatus And 64) = 64 Or (jobStatus And 256) = 256 Or (jobStatus And 512) = 512 Then
Wscript.Echo “【エラー検知】”
Wscript.Echo ” ジョブ名: ” & objPrintJob.Name
Wscript.Echo ” ドキュメント名: ” & objPrintJob.DocumentTitle
Wscript.Echo ” ステータスコード: ” & jobStatus
Wscript.Echo ” 詳細ステータス: ” & GetPrintJobStatus(jobStatus)
‘ — ここでエラー対応アクションを実行 —
‘ 例: エラーのあるジョブを削除する
On Error Resume Next ‘ ジョブ削除時のエラーも無視する
objPrintJob.Delete_ ‘ Delete_ メソッドでジョブを削除
If Err.Number = 0 Then
Wscript.Echo ” -> ジョブを削除しました。”
Else
Wscript.Echo ” -> ジョブの削除に失敗しました。エラー: ” & Err.Description
Err.Clear
End If
On Error GoTo 0 ‘ エラーハンドリングを元に戻す
bFoundErrors = True
End If
Next
End If
If Not bFoundErrors Then
Wscript.Echo “現在、エラー状態の印刷ジョブはありません。”
End If
‘ — GetPrintJobStatus 関数は前述のものをここに記述 —
Function GetPrintJobStatus(statusValue)
‘ … (上記コードと同じ) …
End Function
Wscript.Echo “— 処理完了 —”
- `objPrintJob.Delete_`: `Win32_PrintJob` オブジェクトには、ジョブを削除するための `Delete_` というメソッドが用意されている。これを呼び出すことで、該当する印刷ジョブをプリンタキューから削除できる。
- `On Error Resume Next` と `On Error GoTo 0`: ジョブの削除は、権限がない場合や、ジョブがすでに完了・削除されている場合などに失敗することがある。`On Error Resume Next` でエラーを無視し、`Err.Number` でエラーが発生したかどうかを確認してから、必要に応じてエラーハンドリングを元に戻す (`On Error GoTo 0`) のは、VBScript でよく使うテクニックだ。
4. 定期実行とロギング
このスクリプトを実用的にするには、定期的に実行できるようにする必要がある。Windows の「タスクスケジューラ」を使えば、数分おきや数時間おきにこのスクリプトを実行させることができる。
また、エラーが発生した際や、ジョブが削除された際には、ログファイルに記録 しておくと、後で原因を追跡するのに役立つ。
‘ ログファイルへの書き込み関数 (例)
Sub LogMessage(message)
Dim objFSO, objFile
Dim logFilePath
logFilePath = “C:\Logs\PrintJobMonitor.log” ‘ ログファイルのパスを指定
Set objFSO = CreateObject(“Scripting.FileSystemObject”)
‘ ログディレクトリが存在しない場合は作成
If Not objFSO.FolderExists(objFSO.GetParentFolderName(logFilePath)) Then
objFSO.CreateFolder objFSO.GetParentFolderName(logFilePath)
End If
‘ ファイルに追記モードで開く
Set objFile = objFSO.OpenTextFile(logFilePath, 8, True) ‘ 8: ForAppending, True: Create if not exists
objFile.WriteLine Now() & ” – ” & message
objFile.Close
Set objFile = Nothing
Set objFSO = Nothing
End Sub
‘ 上記のサンプルコードの Wscript.Echo の代わりに LogMessage を使う
‘ 例:
‘ LogMessage “— 印刷ジョブのエラーチェック —”
‘ LogMessage “【エラー検知】ジョブ名: ” & objPrintJob.Name & “, ドキュメント名: ” & objPrintJob.DocumentTitle
‘ LogMessage ” -> ジョブを削除しました。”
陥りやすいエラーと、その回避策
VBScript で WMI を使う際に、よくある失敗と、その対策をいくつか紹介しておこう。
- 権限不足: WMI を使ってシステム情報を取得したり、操作したりするには、それなりの権限が必要だ。特に、リモートマシンに対して操作を行う場合は、管理者権限が必要になることが多い。
- 回避策: スクリプトを実行するユーザーに適切な権限を付与する。タスクスケジューラで実行する場合は、「最上位の特権で実行する」オプションを有効にする。
- WMI クラス名の誤り: `Win32_PrintJob` のクラス名やプロパティ名を間違えると、当然ながら情報は取得できない。
- 回避策: Microsoft の公式ドキュメントや、WMI Explorer のようなツールで、クラス名やプロパティ名を正確に確認する。
- オブジェクトの解放忘れ: `Set objObject = Nothing` を使って、不要になったオブジェクトを明示的に解放することは、VBScript ではそれほど厳密に要求されないが、大量のオブジェクトを扱う場合や、メモリリークが懸念されるような処理では、意識しておくと良い。
- 回避策: スクリプトの最後や、オブジェクトが不要になった箇所で `Set objObject = Nothing` を記述する。
- エラーハンドリングの甘さ: WMI の操作は、ネットワークの問題、プリンタの状態、権限など、様々な要因で失敗する可能性がある。エラーハンドリングをしっかり行わないと、スクリプトが予期せず停止したり、意図しない動作をしたりする。
- 回避策: `On Error Resume Next` を適切に使い、`Err.Number` でエラーをチェックする。重要な処理の前には必ずエラーチェックを行い、エラー発生時には分かりやすいメッセージを表示したり、ログに記録したりする。
まとめ:VBScript (Visual Basic Scripting Edition) で、印刷の悩みを「自動」で解決!
どうだったかな? WMI を使うことで、VBScript が単なる簡単なスクリプト言語から、Windows システムを深く理解し、操作するための強力なツールへと進化することが実感できたんじゃないだろうか。
今回学んだ `Win32_PrintJob` クラスを使った印刷ジョブの監視と、エラー検知・削除のテクニックは、オフィス印刷環境の運用を格段に楽にしてくれるはずだ。
- WMI の基本: `GetObject(“winmgmts”)` で接続し、`ExecQuery` で情報を取得する。
- `Win32_PrintJob`: 印刷ジョブの詳細情報を取得できる。
- `JobStatus`: ビットフラグで状態を表すので、ビット演算で解析する。
- `Delete_` メソッド: エラーのあるジョブを削除できる。
もちろん、これはあくまでも出発点だ。ここからさらに、
- 特定のプリンタだけを対象にする。
- エラー発生時に管理者へメール通知する。
- 一定時間経過しても解消しないエラーに対して、プリンタドライバーの再インストールや、サービスのリスタートを試みる。
といった、より高度な自動化へと発展させていくことも可能だ。
VBScript は、まだまだ現役で活躍できる強力なスクリプト言語だ。今回学んだ知識を武器に、君もぜひ、日々の業務を「自動化」という名の魔法で、より快適なものに変えていってほしい。
「ここをクリアすれば、VBScript の基本はバッチリですよ」って、君が自信を持って言えるようになるまで、応援しているからね! また次の記事で会おう!
