更新日: ・ 自動化ノートの管理人

タスクスケジューラの失敗に気づく方法 ― 自動実行を毎朝一覧で確かめる

自動実行を増やしていくと、怖くなるのは「失敗すること」より、「止まっているのに気づかないこと」です。失敗は画面やログに出ますが、動いていないタスクは何も出しません。数日たって「そういえば最近、あの記録が増えていない」と気づく、という形で発覚します。

この記事では、私が自宅のPCで自動実行を増やしたときに作った、毎朝の見張りの考え方をまとめます。動かし方そのものはWindowsのタスクスケジューラでClaude Codeを毎日自動で動かすに書いたので、ここでは「止まっていないかの確かめ方」に絞ります。

見張りの流れ

  1. タスクの状態を読むGet-ScheduledTask と Get-ScheduledTaskInfo
  2. 3つの目で判定する前回の結果コード / 最終実行時刻 / 有効か無効か
  3. 意図して止めたものを除く一覧の側に「止めてよい」印を持たせる
  4. 失敗だけを書き残す同じ失敗は1日1回までにする
毎朝この流れを回し、一覧は眺めるだけ、失敗したときだけ通知が届くようにします。

見るべきなのは3つ

タスクが「ちゃんと動いている」とは、次の3つがそろっている状態だと考えています。

結果コードだけを見ていると、「前回は成功したが、その後ずっと動いていない」タスクを見逃します。私の環境の一覧は、主に結果コードで成功か失敗かを判定しています。最終実行時刻と無効の確認は、後から足したほうがよいと考えている点です。

PowerShellで一覧を出す最小の例

タスクの定義は Get-ScheduledTask、実行の履歴は Get-ScheduledTaskInfo で読めます。Microsoftの説明では、後者は「スケジュールされたタスクの、最後の実行時の情報」を取るコマンドで、Get-ScheduledTask の出力をパイプでそのまま渡せます。出力には LastRunTime(最終実行時刻)、LastTaskResult(前回の結果)、NextRunTime(次回の実行時刻)、NumberOfMissedRuns(実行されなかった回数)があります。タスクが有効か無効かは、Get-ScheduledTask の State に出ます。

$names = "DailyTasks", "NightlyBackup"   # 見張りたいタスク名

Get-ScheduledTask -TaskName $names | ForEach-Object {
    $info = $_ | Get-ScheduledTaskInfo
    [pscustomobject]@{
        Name   = $_.TaskName
        State  = $_.State
        Last   = $info.LastRunTime
        Result = '0x{0:X}' -f [uint32]$info.LastTaskResult
        Next   = $info.NextRunTime
        Missed = $info.NumberOfMissedRuns
    }
} | Format-Table -AutoSize

出力の Result は16進数で表示しています。LastTaskResult をそのまま出すと10進数になり、次の表と見比べにくいためです。Microsoftの説明にある Get-ScheduledTask の出力例では、State は Ready、Disabled、Running のように表示されます。

結果コードの読み方

Microsoftが公開しているタスクスケジューラの定数のうち、一覧でよく出会うものを抜き出します。

16進数10進数意味
0x00エラーなく終わった(成功)
0x41300267008次の予定の時刻に実行できる状態
0x41301267009いま実行中
0x41302267010無効になっているので、予定の時刻には動かない
0x41303267011まだ一度も実行されていない
0x41306267014前回の実行が、ユーザーによって終了された
0x41325267045タスクスケジューラが、タスクに実行を依頼した

0以外の行は、Microsoftの定数一覧にある説明です。Microsoftの説明では、定数の名前が SCHED_S_ で始まるものは成功の定数、SCHED_E_ で始まるものはエラーの定数です。この表の0以外の定数は、すべて SCHED_S_ の側です。0x41301(実行中)と0x41303(未実行)は、一覧を作った直後に見ると「失敗」に見えがちですが、実際には失敗ではありません。私の最初の一覧は、登録したばかりのタスクの 0x41303 を失敗と表示してしまいました。この2つは「失敗」ではなく「未実行」「実行中」として別に扱うようにしています。

0x41306 は、説明には「ユーザーが終了した」とあります。私の環境では、タスクの「実行時間の制限」で止まったときにも同じ値が返りました。毎日一定の時刻に止める設計のタスクなら、これが正常な終わり方になります。ただ、固まって時間切れになったタスクでも同じ値が出るので、「このタスクに限って正常」と一覧の側で個別に指定し、他は失敗として扱っています。

スクリプトが exit 1 のように0以外で終わった場合は、私の環境ではその値が LastTaskResult にそのまま入っていました。前の記事で書いた exit $code を入れておくと、ここで失敗が見えます。

「動いていない」から、意図して止めたものを除く

一覧を作ると、必ず「無効のタスク」が混ざります。自分で止めたものもあれば、何かの拍子に止まったものもあります。ここで、無効なタスクを全部「異常」と報告すると、見張りへの信頼が落ちます。逆に、止まっていても気にしない癖がつくと、見張りの意味がなくなります。

私の決めごとは、「失敗や未実行と報告する前に、自分で意図的に止めたものでないかを確かめる」です。一覧の設定ファイルに、止めたタスクの印と理由を残しておくと、確かめる手間が省けます。止めた理由が分かれば、数か月後の自分も迷いません。

もうひとつ、ノートPCを持ち歩く場合の注意があります。私の環境では、バッテリー駆動中は開始しない設定のタスクが、電源につないでいない間ずっと Queued(実行待ち)のままになり、動きませんでした。このとき最終実行時刻が古くなるので、「止まった」ように見えます。壊れたのではなく、電源に戻れば動くので、PCの使い方と合わせて見る必要があります。この設定は動かし方の記事の表にまとめてあります。

失敗に気づく仕組み

私は次の3段にしています。

  1. 毎朝の一覧。上のようなスクリプトを定期的に(私は30分おきに)動かし、結果をHTMLなどの1ページにまとめます。眺めるだけで全体が分かります。
  2. 失敗だけを書き残す。失敗と判定したものだけをNotionのタスクとして作ります。毎日見る場所に失敗が並ぶので、一覧のページを開き忘れても気づけます。Notionへの書き込みは、標準ライブラリだけの小さなPythonで十分でした。定期的に動く見張りがAIを呼び出すと、そのたびに費用がかかるためです。
  3. 同じ失敗を何度も通知しない。30分おきに動かすと、同じ失敗を1日に何十回も見つけます。そのまま通知すると、タスクが山になります。そこで「どのタスクを、どの日に通知したか」を小さなファイルに記録し、同じ日の2回目以降は通知しない形にしました。翌日も直っていなければ、また1件作られます。

通知を絞る工夫は、失敗が続いたときに効きます。通知が多すぎると、本当に大事な1件を見落とします。

まとめ

仕組みを作る側として次に気をつけたいのは、Pythonの仮想環境やブラウザが気づかないうちに消えて、自動実行が静かに失敗することです。OneDriveの中にPythonの仮想環境を置くと壊れる話や、Playwrightのブラウザが消える話も、自動実行が静かに失敗する例です。