タスクスケジューラでマクロを起動させていると、時々マクロ作業が途中で失敗したり、ループ状態で終了ができない状態になることがあります。常にPCの状態を確認していれば良いですが、タスク実行を深夜時間に設定していると目視で確認が取れず、何時間もタスクが終了できない事があります。タスクが停滞する状況を回避する手段として、タスクスケジューラでタイムアウトの時間を設けるのですが、いざタイムアウトが発生してもそれを検知することができません。
そこで、今回はタスクスケジューラでタイムアウト検知する設定と、検知した内容をメールで通知する方法を紹介します。これらの設定後、タイムアウトを発生させるスクリプトも紹介し、メール通知ができるか確認したいと思います。
タイムアウト仮発生コマンド作成
タイムアウトを仮発生させるコマンド
タイムアウトを発生させるために仮コマンドを作成します。内容は、60秒待機するだけのスクリプトです。
Start-Sleep -Seconds 60
このコマンドを「Sleep_60.ps1」というファイル名で保存しておきます。
タスクスケジューラに登録
タスクスケジューラの登録方法詳細は、以下ページを参照ください。
タスクスケジューラ設定の状況をスクリーンショットで紹介します。
スクリプト開始を現時点より未来に設定し、設定時刻でスクリプト実行する時間を決めます。開始時間を以下例では「2023/05/17 19:15:09」に設定しています。
「停止するまでの時間」にチェックを入れ、デフォルト設定の「3日間」にカーソルを合わせます。
直接編集で「5秒間」を入力します。トルクダウンで選択もできますが、秒単位の選択肢はありませんので、設定したい秒数を直接入力します。
操作タブの設定例は以下のとおりです。
- プログラム/スクリプト
pwsh - 引数の追加
-Command C:\Users\<ユーザ名>\Documents\PowerShell\Sleep_60.ps1 - 開始(オプション)
必要に応じてファイルが保存されているフォルダ名を記入
C:\Users\<ユーザ名>\Documents\PowerShell
タイムアウト発生確認
タスクスケジューラで設定した時間にタイムアウト発生のスクリプトが実行されたか確認します。無事タイムアウトが発生した場合、履歴タブでタイムアウト発生イベントIDが329になっていることを確認できます。
イベントビューアでタイムアウト発生履歴確認
過去にタイムアウトが発生した履歴をイベントビューアで確認することができます。この項目を確認しなくともタイムアウト検知の設定はできますので、ここは飛ばしもらっても構いません。過去のタイムアウト発生履歴を確認したい場合、以下アコーディオンブロックをクリックすれば確認方法が表示されます。
イベントビューアで過去のタイムアウト検知履歴確認
コントロールパネルを開き、「システムとセキュリティ」をクリック
Windowsツールの「イベントログの表示」をクリック
イベントビューアの項目を以下順に選択する。
アプリケーションとサービスログ ⇒ Windows ⇒ TaskSceduler ⇒ Operational
「Operational」の項目を右クリックし、「現在のロゴをフィルター」を選択する。
イベントIDにタイムアウト発生イベント番号の329を入力し、「OK」をクリック
STEP3を実行した結果が以下スクショになります。タスクスケジューラのタイムアウト検知履歴が表示されました。
タイムアウト検知
タイムアウト検知もタスクスケジューラで設定します。事前設定したタスク(sleep_60)でタイムアウトが発生した時に出現するイベントログを、これまたタスクスケジューラでキャッチし、イベントログの内容をメール送信させます。簡単にフローを書くと以下のとおりです。
1.時間指定でsleep.ps1を実行
2.タイムアウトログ発生(ID:329)
➡
3.タイムアウトイベントを検知
4.最新のタイムログをメール送信
タイムアウトのログ内容取得+メール送信(PowerShell)
最新のタイムアウトログの内容を取得し、それをメール送信するスクリプトをPowerShellで作成します。タイムアウトログは、イベントログを取得するWevtutilを利用します。また、メールはSmtpClientを使用し、送信実行します。まずはコード紹介です。
#タイムアウトのログをテキスト取得(テキストファイル取得したい場合は、echoで出力)
$event_content =wevtutil qe Microsoft-Windows-TaskScheduler/Operational /rd:true /f:text /c:1 /q:*"[System[(EventID=329)]]"
#echo $event_content > C:\Users\<ユーザ名>\Documents\PowerShell\タイムアウト検知ログ.txt
###タイムアウト検知をメールで連絡
$server = "<ServerName>"
$port = "PortNumber"
$User = "UserName"
$Pass = "Password"
# メール送信設定のオブジェクト作成
$SMTPClient=New-Object Net.Mail.SmtpClient($server,$port)
$SMTPClient.Credentials=New-Object Net.NetworkCredential($User,$Pass)
####メールの内容####
$from = "from_MailAddress"
$to = "to_MailAddress"
#$cc = ""
$subject = "タイムアウト検知"
#Windows10の場合は、全文出力可
#$body = $event_content
#WIndows11の場合、8行目辺りでメール文が切れてしまうため、必要項目をピックアップ
$arr = $event_content.split("`r`n")
$body = $arr[3] + $arr[5] + $arr[11] + $arr[12] + $arr[13]
$MailMassage=New-Object Net.Mail.MailMessage($from,$to,$subject,$body)
#$MailMassage.Cc.Add($cc)
# メール送信
$SMTPClient.Send($MailMassage)
コードを書く時の注意点として、エンコードは、「Shift-JIS」にしておいた方が良いです。2023年5月現在では本文はUTF-8でも日本語文字化けはされませんでした。(以前は本文も文字化けが酷かった。。)
件名が日本語の場合、エンコードをShift-JISに設定しておかなければ、相変わらず文字化けしてしまう様です。VSCodeでエンコードをShift-JISに設定する方法は以下アコーディオンブロックをクリックすれば確認方法が展開されます。
VSCode エンコード選択
タイムアウトログのテキスト取得
タイムアウトのログをテキスト取得するために、Wevtutil(Windows Event Utility)を使用します。Wevtutilは、サーバーPCのログ管理で利用されるコマンドで、Windows Homeバージョンでは利用できない可能性があります。Wndows Proでは利用可能です。各コマンド、引数の意味を簡単に説明します。
- wevtutil qe Microsoft-Windows-TaskScheduler/Operational
-
タスクスケジューラを指定してログを取得
- /rd:true
-
最新のログから取得する
- /f:text
-
ログの出力をテキスト形式とする
- /c:1
-
取得するログ件数の指定
- /q:*"[System[(EventID=329)]]"
-
SystemイベントのID:329(タイムアウト)を指定
メール送信
メール送信については、必要なSMTPサーバ情報と、メールアドレスを記入いただきます。
Windows10 Proでは特に問題無く使用できているのですが、Windows11 Pro(10.0.22621 N/A ビルド 22621)でこのコマンドを実行した時にメール本文が8行目辺りで切れてしまい、肝心のタイムアウト発生したスクリプト名が表示されませんでした。(なんでやねん。。)
ブレークポイント設けて変数に代入したログ内容を確認すると、全文がちゃんと代入されていましたし、テキストファイルにログ内容を出力しても特に問題なく全文が出力されていました。自宅のWindows10 Proで同様の設定をしても問題なくメール本文にイベントログ全文がちゃんと送信されてました。しょーがないので、Windows11の場合は、ログ内容をSplitで配列化して必要項目のみをメール本文に出力したいと思います。ログ内容全文が必要な場合は、テキストファイルに出力しても良いと思います。
設定方法で何か誤りがあるかもしれませんので、改善方法を見つけたら再度掲載したいと思います。
タイムアウト検知タスクの作成
タスクスケジューラでタイムアウトイベントを検知し、最新のタイムログをメール送信するスクリプトを実行します。
以下項目を選択します。
・タスク開始:イベント時
・ログ:Microsoft-Windows-TaskScheduler/Operational
・イベントID:329
操作タブの設定例は以下のとおりです。
- プログラム/スクリプト
powershell(pwshを設定すると、件名が日本語の場合文字化けします。) - 引数の追加
-Command C:\Users\<ユーザ名>\Documents\PowerShell\タイムアウト検知.ps1 - 開始(オプション)
必要に応じてファイルが保存されているフォルダ名を記入
C:\Users\<ユーザ名>\Documents\PowerShell
タイムアウト検知の確認
最後に作成したタイムアウト発生の仮コマンド(sleep_60)のタスクを再度時刻設定し、実際にタイムアウト検知とメール通知ができるか確認します。タイムアウトの通知がメールで到着すれば成功です。