この記事で切り分けられること
Task Scheduler に登録した ps1 から呼ぶ発射スクリプトが、決まった時刻に動くはずなのに動かなかった場合の切り分けです。特に「process は生きているのに出力だけ出ていない」「前日は動いたのに今日は止まった」というときに、PC のスリープが原因かどうかを確認する手順を書きます。
症状
14:16 に1本目の投稿は出ていた。しかし 20:00 に出るはずだった2本目(付随する下書き含む)が出ていなかった。タスクマネージャーで見ると、発射用の process 自体は生きたまま残っていた。エラーも出ていない。ログも途中で止まっているだけで、例外は吐いていなかった。
原因
PC が 14:40 ごろからスリープに入っていた。23:24 に一瞬だけ起きて、スクリプト内の時刻待ち処理(wait_until(h, m) のようなループ)が一度抜けたが、その直後にまたスリープに入り、公開処理を担う子プロセスごと止まっていた。
原因は大きく2つある。
- time.sleep によるループ待機は、PC が眠っている間は進まない。起きている時間だけがカウントされるわけではなく、スリープ中は丸ごと止まる。
- wait_until(h, m) が時・分だけを見て日付を見ていなかった。そのため翌朝に処理が再開すると、既に過ぎた「今日の20:00」ではなく、プロセスが生きている限り「次に来る20:00」を待ち直す形になり、意図したタイミングでは何も出なかった。
直し方
3つの手当てをした。
- 発射の待機中は Windows の API である SetThreadExecutionState を呼び、ES_CONTINUOUS | ES_SYSTEM_REQUIRED を立てて PC を眠らせないようにする。管理者権限は不要。
- 既に時刻を過ぎてしまった残りの手順は、再度 06:55 まで待たせずに、気づいた時点で手で実行する。
- 待ち合わせの時刻は時・分だけでなく datetime(年, 月, 日, 時, 分) で絶対指定にし、日付がずれたまま待ち直すことがないようにする。
ps1 側では、この待機付きの発射処理を detached な子プロセスとして起動し、本体の ps1 自体はすぐ終わる形にしている。
# 待機中にスリープさせないための呼び出し例(ctypes 経由)
import ctypes
ES_CONTINUOUS = 0x80000000
ES_SYSTEM_REQUIRED = 0x00000001
ctypes.windll.kernel32.SetThreadExecutionState(
ES_CONTINUOUS | ES_SYSTEM_REQUIRED
)
# 時刻は絶対指定にする
from datetime import datetime
target = datetime(2026, 11, 11, 20, 0)
# ps1 側:発射処理を detached で起動し、ps1 本体はすぐ終える
Start-Process -FilePath "python" `
-ArgumentList "C:/Users/<あなたのユーザー名>/scripts/launch.py" `
-WindowStyle Hidden
この形にすることで、待機中に PC がスリープに入ろうとしても SetThreadExecutionState が効いている間は止まらず、万一止まっても日付入りの絶対時刻指定なので、再開後に古い時刻を待ち直すことはなくなる。
それでも駄目なときに次に見る場所
- タスクマネージャーで該当 process が本当に生きているかを確認する。生きていなければ、スリープではなく別の場所(認証切れ、例外落ち)でエラー処理が必要になる。
- イベントビューアーの電源関連ログで、該当時刻帯に実際にスリープ・復帰が起きているかを確認する。SetThreadExecutionState を入れたのに止まる場合は、呼び出しのタイミングが待機ループより前後にずれていないかを見る。
- 一回限りの処理を自前の sleep ループで作るのはそもそも避ける。本来は Task Scheduler の WakeToRun 設定でスケジュールし、登録自体を本人の ps1 で行う形にする。当日限りの一回物だけ、眠らせない旗つきの detached process で済ませる。

Claude Codeとは何か、実際に投げた依頼文と直し方から説明する
Notion API連携の最初の設定をインテグレーション作成から実際に動かす手順
CSVの文字化けと列ずれが止まる場所をPythonのコードで具体的に潰す手順