タスクスケジューラのタスクが実行されない・0x1で終わる ── 原因の切り分けと安全な運用設計
· 更新日: · 小村 豪 · タスクスケジューラ, Windows, PowerShell, 業務自動化, バッチ処理, 運用, トラブルシューティング, 技術相談
更新履歴(7件・最終更新 2026年08月02日)
この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。
- 記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
- イベントIDから調べる先を絞り込む切り分けフローの図と、「前回の実行結果」に混ざる3系統の値を見分ける図を追加しました。あわせて読み方の分類を1か所直しています。イベント327と328は「開始しなかった理由」ではなく「開始したあとに実行中のインスタンスを止めた記録」なので、100が無いときに見るものから、100はあるが102が無いときに見るものへ移しました。
- 外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
- 名前付きミューテックスの例で、前回のジョブが持ったまま強制終了した場合を扱っていなかったのを直しました。このとき`WaitOne`はfalseを返さず`AbandonedMutexException`を投げ、所有権はこちらに移っています。捕まえずに終了すると解放されないまま次回も同じ例外が出て、ジョブが二度と動かなくなります。捕まえて後始末を確認してから続行する形にしました。
- イベントIDの早見表を直しました。プログラムが`0x1`のような非ゼロで終わっても、タスクスケジューラから見れば操作は完了しているので201が出ます。202はタスクスケジューラ側が操作を完了できなかったときのイベントで、非ゼロ終了の受け皿ではありません。`0x1`は201の戻り値と「前回の実行結果」で追う、という読み方に改めました。
- 履歴タブのイベントIDから何を疑うかの早見表を追加しました。あわせてgMSAでタスクを登録する最小手順、履歴を有効にする手順、コピーコマンドの終了コードを正しく判定するラッパー例を追加しています。
- 本文中の関連記事へのリンクの文言が、リンク先の現在のタイトルと食い違っていたのを、実際のタイトルに揃えました。本文の内容は変えていません。
- 初版公開
この記事を引用する(DOI: 10.5281/zenodo.21589895)
この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。
小村 豪(2026)「タスクスケジューラのタスクが実行されない・0x1で終わる ── 原因の切り分けと安全な運用設計」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21589895 https://staging.comcomponent.com/blog/windows-task-scheduler-reliable-scheduled-tasks/
- DOI(最新版)
- 10.5281/zenodo.21589895
- DOI(この版)
- 10.5281/zenodo.21732891
「PowerShell で作った集計スクリプトを毎朝 6 時に動かしたい」「手で実行すれば動くのに、タスクスケジューラに載せると動かない」。業務自動化の相談を受けていると、最後はほぼ必ずこの話になります。
当ブログでも、ログ整理の自動化、Pester によるスクリプトのテスト、C# からの PowerShell 実行、Power Automate による業務自動化と、自動化の話を続けて書いてきました。これらの記事はどれも、最終的には「タスクスケジューラで定期実行する」ことを前提にしています。ところが、そのタスクスケジューラ自体が意外と癖の強い仕組みで、「手動なら動くのに定期実行だと失敗する」「いつの間にか止まっていたことに誰も気づかなかった」という事故が後を絶ちません。
この記事では、タスクスケジューラの仕組みのうち運用事故に直結する部分──実行アカウントとログオン種別、「実行されない」ときの切り分け、戻り値 0x1 の典型原因、ログの残し方、多重起動の制御──を、実務でつまずく順に整理します。
この記事の前提
| 項目 | 内容 |
|---|---|
| 対象 OS | Windows 10 / 11、Windows Server 2016 以降のタスクスケジューラ(Task Scheduler 2.0 系)を前提にしています。もっと古い at コマンド由来のタスクが残っている環境では、まずそれらの棚卸しから始めてください |
| 想定読者 | PowerShell やバッチを書けるが、それを定期実行に載せる段になって詰まっている情シス・開発担当 |
| 操作 | GUI(taskschd.msc)と PowerShell の ScheduledTasks モジュールの両方を扱います。画面キャプチャは掲載していません。代わりに、タブ名・項目名・ボタン名を実際の表記のまま書いているので、手元でタスクスケジューラを開きながら読んでください |
| ドメイン環境の前提 | gMSA(第 3.3 節)はドメイン環境限定の話です。ワークグループ環境の場合は読み飛ばしてください |
1. まず結論
- タスクスケジューラのトラブルの大半は、スクリプトそのものではなく「誰として・どういうセッションで実行されるか」の理解のずれから生じます。「ユーザーがログオンしているかどうかにかかわらず実行する」を選んだ瞬間に、対話セッションともログオン時の環境とも別の世界で動くことを前提に設計してください。1
- 「実行されない」の調査は履歴(History)タブとイベントログが起点です。ただしタスク履歴は既定で無効なので、運用に乗せる前に「すべてのタスク履歴を有効にする」を必ず有効化しておきます。2
- 「前回の実行結果」に出る
0x1はタスクスケジューラのエラーではなく、起動したプログラム自身が終了コード 1 を返したという意味です。原因はスクリプト側にあるので、終了コードを設計し、ログを自分で残す仕組みを先に作ります。3 - PowerShell スクリプトは
-NoProfile -NonInteractive -ExecutionPolicy Bypass -File "フルパス"の形で呼び出し、スクリプト内のパスは$PSScriptRoot基準にするのが基本形です。「開始(オプション)」欄に引用符を入れてはいけないという古典的な罠もここで踏みがちです。 - パスワード変更でタスクが黙って死ぬ事故を避けるには、実行アカウントの設計(サービスアカウントの棚卸し、ドメイン環境なら gMSA の検討)が必要です。4
- 多重起動の制御(既定は「新しいインスタンスを開始しない」)、実行時間制限(既定 3 日)、電源条件(既定は AC 電源時のみ)は、既定値のまま気づかず運用してしまう代表的な設定です。登録時に必ず明示的に決めてください。5
この記事の知識マップ
タスクスケジューラの「実行されない」「0x1で終わる」といった事故の大半は、実行アカウントがどのログオン種別で動くかの理解のずれに起因する。Password/S4Uでの実行には「バッチ ジョブとしてログオン」の権利が必要で、ドメイン環境ではパスワードをドメインコントローラーが自動管理するgMSAが第一候補になる。原因の切り分けは既定で無効なタスク履歴を有効にしたうえでイベントIDを追うのが起点で、0x1のような小さい値は起動したプログラム自身の終了コードであり、robocopyのように正常時でも非ゼロを返す規約には注意が要る。電源条件・StartWhenAvailable・多重起動制御(MultipleInstances)・実行時間の上限はいずれも既定値のまま気づかず運用されがちな設定で、別タスクや手動実行との衝突は名前付きミューテックスによる排他で補う必要がある。
flowchart LR
accTitle: タスクスケジューラの安定運用の知識マップ
accDescr: タスクスケジューラのログオン種別・gMSA・電源条件や多重起動制御などの既定値、イベントIDや前回の実行結果を使った切り分け、名前付きミューテックスによる排他の関係を示す図。
task_scheduler["タスクスケジューラの無人実行"]
task_logon_type["ログオン種別(LogonType)"]
batch_logon_right["「バッチ ジョブとしてログオン」の権利"]
gmsa["gMSA(group Managed Service Account)"]
domain_controller["ドメインコントローラー"]
scheduledtasks_module["PowerShellのScheduledTasksモジュール"]
task_history["タスク履歴(Operationalログ)"]
task_event_id["タスクスケジューラのイベントID"]
task_result_code["「前回の実行結果」(終了コード)"]
robocopy_exit_code["robocopyの終了コード規約"]
task_power_condition["電源条件(AC電源時のみ実行)"]
start_when_available["StartWhenAvailable(開始時刻を逃した場合の実行)"]
multiple_instances_policy["多重起動制御(MultipleInstances)"]
execution_time_limit["実行時間の上限(ExecutionTimeLimit)"]
named_mutex["名前付きMutex"]
admin_rights["管理者権限"]
task_scheduler -->|"で構成できる"| task_logon_type
task_logon_type -.->|"前提とする"| batch_logon_right
gmsa -.->|"前提とする"| batch_logon_right
gmsa -.->|"で構成できる"| task_logon_type
gmsa -->|"前提とする"| domain_controller
task_scheduler -.->|"利用する"| gmsa
task_scheduler -->|"で構成できる"| scheduledtasks_module
gmsa -.->|"で構成できる"| scheduledtasks_module
task_scheduler -->|"で確認できる"| task_history
task_history -->|"利用する"| task_event_id
task_result_code -.->|"で確認できる"| task_event_id
robocopy_exit_code -.->|"原因になり得る"| task_result_code
task_scheduler -->|"利用する"| task_result_code
task_scheduler -->|"で構成できる"| task_power_condition
task_scheduler -->|"で構成できる"| start_when_available
task_scheduler -->|"で構成できる"| multiple_instances_policy
task_scheduler -->|"で構成できる"| execution_time_limit
named_mutex -->|"推奨される対応"| multiple_instances_policy
admin_rights -->|"用いるのは非推奨"| task_scheduler
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全19件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2. タスクスケジューラの構造 ── トリガー・操作・条件・設定
タスクスケジューラのタスクは、大きく 4 つの要素でできています。
| 要素 | 内容 | 事故につながりやすい点 |
|---|---|---|
| トリガー | いつ起動するか(時刻、ログオン時、イベント発生時など) | 時刻トリガーを逃したときの扱い(後述の StartWhenAvailable) |
| 操作 | 何を実行するか(プログラム、引数、開始フォルダー) | 引数のクォート、開始フォルダーの指定ミス |
| 条件 | 実行してよい状況か(電源、ネットワーク、アイドル) | 既定で「AC 電源時のみ」が有効 |
| 設定 | 実行中の振る舞い(多重起動、時間制限、再試行) | 既定値を確認せずに運用開始してしまう |
GUI(taskschd.msc)で作ったタスクは XML としてエクスポートできます。タスク定義を Git で管理したい場合や、複数台に同じタスクを配る場合は、XML エクスポート+schtasks /Create /XML、あるいは PowerShell の ScheduledTasks モジュール(New-ScheduledTaskAction / New-ScheduledTaskTrigger / New-ScheduledTaskSettingsSet / Register-ScheduledTask)でスクリプト化しておくのがおすすめです。5
$action = New-ScheduledTaskAction -Execute 'pwsh.exe' `
-Argument '-NoProfile -NonInteractive -ExecutionPolicy Bypass -File "C:\Jobs\Cleanup-Logs.ps1"' `
-WorkingDirectory 'C:\Jobs'
$trigger = New-ScheduledTaskTrigger -Daily -At '06:00'
# 電源条件の既定は「AC電源時のみ開始・バッテリーに切り替わったら停止」。
# ノートPCや現場端末でも動かすジョブなら、ここで明示的に許可しておく
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable `
-MultipleInstances IgnoreNew `
-ExecutionTimeLimit (New-TimeSpan -Hours 2) `
-AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
# パスワードを画面に表示させないよう Get-Credential 経由で受け取る
$cred = Get-Credential -UserName 'DOMAIN\svc-batch' -Message '実行アカウントの資格情報'
Register-ScheduledTask -TaskName 'KS-Cleanup-Logs' `
-Action $action -Trigger $trigger -Settings $settings `
-User $cred.UserName -Password $cred.GetNetworkCredential().Password
タスク定義がコードになっていれば、検証機で試したものをそのまま本番に持っていけますし、「どの設定で動いているか分からない」という状態も避けられます。
複数台への展開なら、GUI で作り込んだタスクを XML にエクスポートして schtasks で配る方法も実績があります。
rem 検証機で作ったタスクをエクスポート
schtasks /Query /TN "KS-Cleanup-Logs" /XML > KS-Cleanup-Logs.xml
rem 各端末でインポート(実行アカウントとパスワードは登録時に指定)
schtasks /Create /TN "KS-Cleanup-Logs" /XML KS-Cleanup-Logs.xml /RU DOMAIN\svc-batch /RP *
XML にはトリガー・条件・設定がすべて含まれるので、リポジトリに入れておけばタスク定義のレビューも差分管理もできます。逆に、手作業で 10 台に同じタスクを GUI 登録する運用は、1 台だけ設定が違う「はぐれタスク」を必ず生みます。台数が 2 桁になる前にコード化しておくのが安全です。
3. 実行アカウントとログオン種別 ── 一番の事故ポイント
タスクのプロパティで選ぶ「ユーザーがログオンしているときのみ実行する」「ユーザーがログオンしているかどうかにかかわらず実行する」は、内部的にはログオン種別(LogonType)の選択です。ここの理解がずれていると、「手動では動くのに定期実行では動かない」の大半を説明できないまま迷走することになります。1
3.1 3つのモードの違い
| 選択 | 内部の仕組み | 特徴・制約 |
|---|---|---|
| ユーザーがログオンしているときのみ実行 | 対話トークン(InteractiveToken) | ログオン中の画面でウィンドウが見える。ログオフ中はそもそも起動しない |
| ログオンしているかどうかにかかわらず実行 | パスワード保存(Password) | パスワードを登録時に保存。画面は見えない(非対話)。パスワード変更で起動失敗するようになる |
| 同上+「パスワードを保存しない」 | S4U | パスワードを保存しない代わりに、ネットワーク上のリソースへのアクセスと暗号化ファイル(EFS)へのアクセスができない1 |
実務での典型的な事故はこうです。
- 共有フォルダーにアクセスするスクリプトを「パスワードを保存しない」(S4U)で登録した。ローカルのテストでは動いたが、本番では共有フォルダーへのアクセスだけが失敗する。→ S4U にはネットワーク資格情報がないため。
- 「ログオンしているかどうかにかかわらず実行」で登録した数か月後、ドメインのパスワード有効期限が来てパスワードを変更した。以後タスクはログオン失敗(
0x8007052E)で止まり続けたが、誰も気づかなかった。 - GUI アプリを起動するタスクを「かかわらず実行」で登録した。アプリは起動しているが画面がどこにも表示されず、「動いていない」と誤解した。→ 非対話セッションで動いているため。対話的な画面が必要な処理は、この構成では原則動かせません。
また、Password / S4U で実行するアカウントには「バッチ ジョブとしてログオン」の権利(SeBatchLogonRight)が必要です。Administrators には既定で付与されていますが、専用の一般ユーザーをサービスアカウントにする場合はローカル セキュリティ ポリシー側の設定も確認してください。6
3.2 どのアカウントで動かすか
- SYSTEM: パスワード管理が不要で強力ですが、権限が強すぎます。ローカル完結の保守処理には便利でも、業務データを触るジョブを何でも SYSTEM にするのは避けるべきです。管理者権限が本当に必要かどうかの考え方は、別記事「Windowsアプリに管理者権限が必要なのはどんなときか」で整理しています。
- 専用のサービスアカウント(一般ユーザー): 最小権限にできる反面、パスワード変更のたびにタスクを更新する運用が必要です。パスワード有効期限とタスクの棚卸しをセットで管理してください。
- gMSA(グループ管理サービスアカウント): ドメイン環境なら第一候補です。パスワードはドメインコントローラーが自動管理するため、「パスワード変更でタスクが死ぬ」問題そのものがなくなります。タスクスケジューラは gMSA での実行をサポートしています。4
なお「最上位の特権で実行する」チェックは、UAC で分割されたトークンのうち管理者側(昇格済み)トークンで実行するという意味です。管理者権限が不要なジョブでは付けないでください。
3.3 gMSAでタスクを登録する最小手順
gMSA を「第一候補」と書いた以上、実際にどう登録するかまで示します。タスクスケジューラのタスクは、公式に gMSA をサポートする構成の 1 つとして明記されています。4
前提条件は次のとおりです。4
- ドメインとフォレストの機能レベルが Windows Server 2012 以降であること
- ドメインに KDS ルートキーが作成済みであること(
KdsSvcの Operational ログのイベント ID 4004 で作成を確認できます) - gMSA の作成・管理には Domain Admins または Enterprise Admins のメンバーであること
- gMSA 名はドメイン単位ではなくフォレスト単位で一意である必要があります。同名が別ドメインにあると作成に失敗します
手順は 3 ステップです。1〜2 はドメイン管理者が、3 はタスクを動かす端末ごとに実行します。
# --- 1. ドメイン側: gMSAを作る。パスワードを取得してよいホストをセキュリティグループで指定する ---
# <SecurityGroup> には、タスクを動かすサーバーのコンピューターアカウントを入れたグループを指定する
New-ADServiceAccount -Name 'svc-batch' -DNSHostName 'svc-batch.contoso.local' `
-PrincipalsAllowedToRetrieveManagedPassword 'GG-BatchHosts'
# --- 2. タスクを動かす端末ごとに: gMSAをインストールし、パスワードを取得できるか確認する ---
Install-ADServiceAccount -Identity 'svc-batch'
Test-ADServiceAccount -Identity 'svc-batch' # True が返れば使える
3 ステップ目が、タスクの登録です。ポイントは 2 つあります。
# --- 3. タスクを動かす端末で: gMSAをプリンシパルにしてタスクを登録する ---
$action = New-ScheduledTaskAction -Execute 'pwsh.exe' `
-Argument '-NoProfile -NonInteractive -ExecutionPolicy Bypass -File "C:\Jobs\Cleanup-Logs.ps1"' `
-WorkingDirectory 'C:\Jobs'
$trigger = New-ScheduledTaskTrigger -Daily -At '06:00'
# ポイント1: アカウント名の末尾に $ を付ける(gMSAの名前の形式)
# ポイント2: LogonType は Password。ただし -Password は渡さない
# (gMSAのパスワードはドメインコントローラーが管理し、ホストが取得するため)
$principal = New-ScheduledTaskPrincipal -UserId 'CONTOSO\svc-batch$' `
-LogonType Password -RunLevel Limited
Register-ScheduledTask -TaskName 'KS-Cleanup-Logs' `
-Action $action -Trigger $trigger -Principal $principal
New-ScheduledTaskPrincipal の -LogonType に指定できる値は None / Password / S4U / Interactive / Group / ServiceAccount / InteractiveOrPassword です。7 第 3.1 節の表で見たとおり S4U はネットワークリソースにアクセスできないので、共有フォルダーを触るジョブで安易に選ばないでください。
補足を 2 点。まず、この gMSA にも「バッチ ジョブとしてログオン」の権利が必要です(第 3.1 節末尾と同じ話で、gMSA だから免除されるわけではありません)。6 次に、schtasks.exe は実行アカウントのパスワードを /RP で渡す前提のコマンドで、gMSA での登録手順は公式には案内されていません。gMSA を使うなら、タスク登録は PowerShell の Register-ScheduledTask 側に寄せるのが確実です。第 2 章で書いた「XML をエクスポートして schtasks で配る」方式と併用する場合は、プリンシパル部分だけは PowerShell で上書きする構成になります。
4. 「実行されない」を切り分ける手順
4.1 履歴を有効にしてから疑う
タスクスケジューラの右ペインにある「すべてのタスク履歴を有効にする」は、既定で無効です。履歴が無効のままだと、失敗したという事実すら記録に残りません。運用に乗せる前に必ず有効化してください。手順は次のとおりです。
- タスク スケジューラを起動します(
taskschd.msc、またはスタートメニューで「タスク スケジューラ」を検索)。管理者権限で起動してください。 - 左ペインのツリーで、最上位の「タスク スケジューラ (ローカル)」を選択します。個別のタスクを選んだ状態では、この項目は出てきません。
- 右ペインの「操作」の一覧にある「すべてのタスク履歴を有効にする」をクリックします。すでに有効なら、この項目は「すべてのタスク履歴を無効にする」という表示に変わっています。
履歴の実体は、イベント ビューアーの アプリケーションとサービス ログ > Microsoft > Windows > TaskScheduler > Operational ログです。2 個別タスクの「履歴」タブは、このログを対象のタスクで絞り込んで見せているものなので、複数タスクをまたいで時系列で追いたいときはイベント ビューアー側を開きます。
切り分けの基本手順は Microsoft のトラブルシューティングガイドの流れそのままで十分機能します。2
- スクリプトを単体でテストする ── タスクに載せる前に、実行アカウントと同じ条件(可能なら
runasや検証機)でスクリプト自体が完走することを確認する。 - 状態列と履歴タブを見る ── そもそもトリガーされたのか、起動したが失敗したのかを区別する。トリガーされていなければトリガー設定・条件(電源・ネットワーク)を疑い、手動実行(右クリック → 実行)で操作自体は動くかを確認する。
- 「ユーザーがログオンしているときのみ実行」に一時変更してみる ── これで動くなら、原因は非対話セッションや資格情報まわり(前章)にあると絞り込めます。
4.2 履歴タブに何が出たら何を疑うか ── イベントIDの早見表
履歴タブ(と Operational ログ)の行は、すべてイベント ID を持っています。この ID を見れば「どこまで進んだか」が一発で分かります。正常なタスク 1 回分は、おおむね「開始(100)→ プロセス起動(129)→ 操作開始(200)→ 操作完了(201)→ 完了(102)」の順に並びます。
| イベント ID | メッセージの意味 | 出たときに疑うこと |
|---|---|---|
| 106 | ユーザーがタスクを登録した8 | 登録の記録。「いつ誰が変えたか」を追うときの起点 |
| 140 / 141 | ユーザーがタスクを更新した / 削除した8 | 「昨日まで動いていた」の犯人探しはここ |
| 113 | タスクは登録できたが、一部のトリガーがタスクを開始しない8 | トリガー定義の不備。登録時点で警告されている |
| 116 | タスクの構成は保存できたが、実行に使う資格情報を保存できなかった8 | 実行アカウントとパスワードの指定。ここが出ていると当然動かない |
| 100 | タスクを開始した9 | ここが無ければ、そもそもトリガーされていないか、101 で開始に失敗している |
| 101 | タスクを開始できなかった。エラー値つき9 | トリガーは発火したが起動に失敗している。実行アカウントの資格情報(0x8007052E など)や権限を疑う。100 は出ない |
| 129 | プロセス ID つきでタスクを起動した9 | プロセスは生成された。ここから先はスクリプト側の話 |
| 200 / 201 | 操作(action)を開始した / 操作が完了した9 | 201 は「起動したプログラムが終了した」という意味で、中身の成否は表していません。現在の Windows の 201 は本文とイベントデータに戻り値(ResultCode)を持つので、そこを見ます(4.3 節) |
| 202 | タスクスケジューラが操作を完了できなかった。エラー値つき9 | タスクスケジューラ側の失敗。プログラムが 0x1 で終わったときにここが出るとは限りません |
| 203 | 操作の起動そのものに失敗した。エラー値つき9 | 実行ファイルのパス誤り、「開始(オプション)」の指定不正、権限不足 |
| 102 | タスクが正常に終了した9 | 正常系の終端 |
| 111 | 実行時間の上限を超えたのでタスクを終了させた9 | 「停止するまでの時間」(既定 3 日)に到達。7 章へ |
| 322 | 同じタスクの別インスタンスが実行中のため起動しなかった10 | 多重起動制御が効いている。前回が終わっていない。7 章へ |
| 323 | 新しいインスタンスを起動するため、実行中のインスタンスを停止した9 | MultipleInstances が「既存のインスタンスを停止する」になっている |
| 327 | 電源がバッテリーに切り替わったためインスタンスを停止した9 | 電源条件(4.4 節)。ノート PC・現場端末で頻出 |
| 328 | コンピューターがアイドルでなくなったためインスタンスを停止した9 | アイドル条件が有効になっている |
| 329 | タスクがタイムアウトしたためインスタンスを停止した9 | 111 と同じく実行時間の設計を見直す |
| 330 | ユーザーの要求によりインスタンスを停止した9 | 誰かが手で止めている |
読み方の要点は 3 つです。
- 100 が無いなら、まず 101(タスクを開始できなかった)が出ていないかを見ます。出ていればトリガーは発火していて、起動に失敗しているので、エラー値と実行アカウントを疑います(第3章)。101 も無ければ原因はタスクより手前(トリガー・条件・タスクの無効化)で、322 が出ていれば前回のインスタンスが終わっていないことがそのまま理由です。
- 100 はあるが 102 が無いなら、起動はしたが終わっていません。111 / 329 なら時間切れ、203 なら起動そのものの失敗、327 / 328 なら電源やアイドルの条件で実行中のインスタンスが止められたということです(327 / 328 はどちらも「開始しなかった」ではなく「止めた」記録なので、100 の後に出ます)。
- 100 も 102 もあるのに結果がおかしいなら、タスクスケジューラの責任範囲は完走しています。以降はスクリプト側のログ(6 章)でしか追えません。
flowchart TD
S["実行されない・結果がおかしい"] --> Q1{"イベント 100(開始)があるか"}
Q1 -->|"ない"| Q1b{"イベント 101 があるか"}
Q1b -->|"ある"| A0["トリガーは発火したが起動に失敗<br/>101 のエラー値と<br/>実行アカウントを見る(3章)"]
Q1b -->|"ない"| A1["原因はタスクより手前<br/>トリガー・条件・無効化(4.4節)<br/>322 なら前回が終わっていない"]
Q1 -->|"ある"| Q2{"イベント 102(正常終了)があるか"}
Q2 -->|"ない"| B["起動はしたが終わっていない<br/>203 = 起動そのものの失敗<br/>111・329 = 時間切れ<br/>327・328 = 電源・アイドル条件で停止<br/>202 = タスクスケジューラ側の失敗"]
Q2 -->|"ある"| C["タスクスケジューラ側は完走している<br/>0x1 ならスクリプトが<br/>終了コード 1 を返している<br/>以降はスクリプト側のログで追う(6章)"]
図1: イベント100と102があるかどうかで、調べる先がタスクの設定側かスクリプト側かに分かれる
ここで一点、間違えやすいところがあります。プログラムが 0x1 のような非ゼロで終わっても、タスクスケジューラから見れば「起動して、終了した」ので 201(ACTION_SUCCESS)が出ます。202 は「タスクスケジューラが操作を完了できなかった」ときのイベントで、プログラムの非ゼロ終了の受け皿ではありません。9 したがって 0x1 を追うときに 202 を探しても見つからないことがあります。見るべきは 201 の戻り値と、タスクの「前回の実行結果」列(4.3 節)です。なお 201 の ResultCode と「前回の実行結果」は必ずしも一致しないので、確実なのは 6 章のようにスクリプト側で自分の終了コードを記録しておくことです。
4.3 「前回の実行結果」の読み方
| 表示 | 意味 |
|---|---|
0x0 |
正常終了(起動したプログラムが終了コード 0 を返した) |
0x1 |
起動したプログラムが終了コード 1 を返した(タスクスケジューラ自身のエラーではない) |
0x41300 |
次回のスケジュール実行を待機中(SCHED_S_TASK_READY) |
0x41301 |
現在実行中(SCHED_S_TASK_RUNNING) |
0x41303 |
まだ一度も実行されていない(SCHED_S_TASK_HAS_NOT_RUN) |
0x8007010B |
開始フォルダー(「開始(オプション)」)の指定が不正。引用符を入れた場合の典型症状 |
0x8007052E |
ログオン失敗。保存されたパスワードが古い、権利がない等 |
0x413xx 系はタスクスケジューラの状態コード、0x8007xxxx は Windows のエラーコード、そして 0x1 や 0x2 のような小さい値は起動されたプログラム自身の終了コードです。3 この区別がつくと、調べる場所(タスク設定か、スクリプトか)を最初から間違えなくなります。
flowchart TB
R["「前回の実行結果」に出ている値"]
R -->|"0x0 / 0x1 / 0x2 のような小さい値"| P["起動されたプログラム自身の終了コード<br/>→ 調べる先はスクリプト"]
R -->|"0x413xx"| ST["タスクスケジューラの状態コード<br/>(待機中・実行中・未実行)<br/>→ そもそも失敗を表していない"]
R -->|"0x8007xxxx"| Q{"操作は起動したか<br/>(201 があるか、203 が出ていないか)"}
Q -->|"起動していない"| W["Windows のエラーコード<br/>(開始フォルダーの指定不正、ログオン失敗など)<br/>→ 調べる先はタスクの設定"]
Q -->|"起動している"| W2["子プロセスが返した終了コード。<br/>アプリが HRESULT 形式で返すこともある<br/>→ 調べる先はスクリプト"]
図2: 同じ欄に3系統の値が混ざって出る。ただし 0x8007xxxx は接頭辞だけでは決まらない ── 操作が起動していれば、それは子プロセスが返した値のほうなので、イベント201と203を突き合わせて発生元を判定する
4.4 条件・設定の既定値に注意
- 電源条件: 既定では「コンピューターを AC 電源で使用している場合のみタスクを開始する」が有効です。ノート PC を検証機にすると、バッテリー駆動時だけ動かない「再現しない不具合」になります。さらに Windows 10 以降、バッテリー節約機能が有効な間は多くのタスクのトリガーが遅延されます。11
- 開始時刻を逃した場合: PC がシャットダウンしていて開始時刻を過ぎた場合、既定では次のスケジュールまで実行されません。「スケジュールされた時刻にタスクを開始できなかった場合、すぐにタスクを実行する」(
-StartWhenAvailable)を明示的に有効にするか、逃してよいジョブなのかを設計として決めておきます。5 - スリープ解除: 夜間ジョブでスリープ運用の PC なら「タスクを実行するためにスリープを解除する」(
-WakeToRun)の要否も決めます。
ここまでに出てきた設定が GUI のどこにあるかを、タブ単位でまとめておきます。タスクを右クリック →「プロパティ」で開くダイアログの構成です。
| タブ | ここで決めるもの | 本記事の該当箇所 |
|---|---|---|
| 全般 | タスク名、実行アカウント(「ユーザーまたはグループの変更」)、「ユーザーがログオンしているときのみ実行する」/「ログオンしているかどうかにかかわらず実行する」、「パスワードを保存しない」、「最上位の特権で実行する」 | 3 章 |
| トリガー | いつ起動するか。「新規」から時刻・ログオン時・イベント時などを追加 | 4.5 節 |
| 操作 | 「プログラム/スクリプト」「引数の追加(オプション)」「開始(オプション)」の 3 欄。「開始(オプション)」に引用符を付けないのはここ | 5 章 |
| 条件 | 電源条件(AC 電源時のみ/バッテリーに切り替わったら停止)、アイドル条件、ネットワーク条件 | 上の箇条書き |
| 設定 | 「スケジュールされた時刻にタスクを開始できなかった場合、すぐにタスクを実行する」、「タスクが既に実行中の場合に適用される規則」、「停止するまでの時間」 | 上の箇条書き・7 章 |
| 履歴 | そのタスクのイベント一覧。既定では無効で、4.1 節の手順で有効化するまで空のまま | 4.1〜4.2 節 |
4.5 トリガー設計そのものの注意
「実行されない」と思ったら、そもそもトリガーの設計が意図とずれていた、というケースもあります。
- 「毎月 31 日」は 31 日がない月には実行されません。 月末処理なら「毎月最終日」を意図した設計(月初に前月分を処理する、あるいはスクリプト側で日付判定する)に寄せたほうが安全です。
- 時刻はタスクを登録したマシンのローカル時刻です。 海外拠点の端末や、まれに UTC 設定で運用されているサーバーに同じ XML を配ると、実行時刻が拠点ごとにずれます。「全拠点で日本時間の朝 6 時」なのか「各拠点の朝 6 時」なのかを仕様として決めておいてください。
- 短い間隔の繰り返し(5 分ごとなど)をタスクスケジューラでやり始めたら要注意。 「1 日 1 回のバッチ」の道具立てとしては優秀ですが、分単位のポーリングや常時監視が必要になってきたら、それは常駐プロセスの領域です(後述の第 8 章)。
- イベントトリガーは強力ですが、対象イベントが本当に安定して記録されるかを先に確認する。 アプリケーションログの特定イベント ID をトリガーにする構成は、アプリの更新でイベントの出方が変わると黙って動かなくなります。時刻トリガー+スクリプト内での条件判定のほうが、結果的に追いやすいことも多いです。
5. 0x1 で終わる典型パターンと PowerShell の正しい呼び出し方
0x1 はスクリプトが失敗したという結果でしかないので、原因はスクリプトの実行環境の差にあります。手動実行と定期実行で違うのは、主に次の点です。
- カレントディレクトリが違う: 「開始(オプション)」を指定しなければ
C:\Windows\System32などで動きます。相対パスで書かれたスクリプトはここで壊れます。スクリプト側は$PSScriptRoot基準でパスを組み立て、タスク側は「開始(オプション)」に作業フォルダーを指定します。このとき「開始(オプション)」欄に引用符を付けてはいけません。スペースを含むパスでも引用符なしで書きます(付けると0x8007010Bで失敗します)。 - 環境変数・プロファイルが違う: ログオンスクリプトやユーザープロファイルで設定される環境変数、マップされたネットワークドライブ(X: など)は、非対話セッションには存在しないと考えてください。UNC パス(
\\server\share\...)を直接使い、-NoProfileでプロファイル差を排除します。 - 実行ポリシーが違う: ユーザーには
RemoteSignedを設定していても、サービスアカウントでは未設定ということがあります。タスクの引数で-ExecutionPolicy Bypassを明示します。 - ツールの終了コード規約が特殊: たとえば
robocopyは「すべてのファイルを正常にコピーした」場合に 1 を返します。終了コードをそのまま返すラッパーだと、正常なのに0x1に見える、あるいはその逆が起きます。使う外部コマンドの終了コード規約は必ず確認してください。
robocopy の場合、公式の終了コード表では 0〜7 が「失敗なし」の組み合わせで、8 以上が「コピー処理中に少なくとも 1 件の失敗があった」ことを示します。12 つまり、そのまま返すのではなく 0/1 に正規化するラッパーを挟むのが正解です。
# 引数は自分で受け取る。呼び出し側の変数に暗黙に依存しないこと
param(
[Parameter(Mandatory)][string]$Source,
[Parameter(Mandatory)][string]$Destination
)
# robocopy は $LASTEXITCODE に終了コードを返す。
# $ErrorActionPreference = 'Stop' を設定していても、ネイティブコマンドの
# 非ゼロ終了は例外にならないので、自分で判定する必要がある
robocopy $Source $Destination /E /R:2 /W:5 /NP
$rc = $LASTEXITCODE
if ($rc -ge 8) {
Write-Error "robocopy が失敗しました。終了コード: $rc"
exit 1
}
# 0〜7 は失敗なし。何が起きたかはログに残しつつ、タスクスケジューラには成功を返す
Write-Host "robocopy 正常終了。終了コード: $rc"
exit 0
-ge 8 の 1 行が本体です。if ($rc -ne 0) と書いてしまうと、正常にコピーできた回(1)まで失敗扱いになります。これが「毎朝バックアップが失敗しましたと通知が来るが、実際にはファイルはコピーされている」という定番の相談の正体です。
PowerShell 呼び出しの基本形は次のとおりです。
プログラム/スクリプト: pwsh.exe (Windows PowerShell なら powershell.exe)
引数の追加: -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "C:\Jobs\Cleanup-Logs.ps1"
開始 (オプション): C:\Jobs (引用符なし)
-Command ではなく -File を使うのは、引数のエスケープが素直になることに加えて、スクリプトの exit n がそのままプロセスの終了コードになり、タスクスケジューラの「前回の実行結果」から成否を判別できるようになるためです。スクリプト側でも、成功なら 0、失敗なら 0 以外を明示的に返す設計にしておきます。
# コマンドレットの「非終了エラー」も catch に落とすため Stop に設定する。
# これがないと Copy-Item などの失敗が素通りして exit 0 になり得る
$ErrorActionPreference = 'Stop'
try {
Main
exit 0
}
catch {
Write-Error $_
exit 1
}
例外をどこで捕まえてどう記録するかの考え方は、別記事「例外の捕捉とログ設計」でも詳しく書いています。
6. ログは自分で残す
タスクスケジューラの履歴は「起動したか・終了コードは何か」までしか教えてくれません。スクリプトが何をどこまでやったかは、スクリプト自身がログとして残す必要があります。
最低限なら、タスクの引数でリダイレクトするのではなく(タスクスケジューラの「引数」欄でのリダイレクト記法はシェル経由でないため機能しません)、スクリプト内でトランスクリプトを取るのが手軽です。
$logDir = 'C:\Jobs\logs'
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
Start-Transcript -Path (Join-Path $logDir ("cleanup-{0:yyyyMMdd}.log" -f (Get-Date))) -Append
try {
# 本処理
}
finally {
Stop-Transcript
}
ログ自体が溜まり続ける問題への対処(世代管理・アーカイブ)は、まさに「PowerShellスクリプト応用 ── ログ調査・アーカイブ・レポート化を安全に自動化する」で書いた内容がそのまま使えます。
一歩進めるなら、Windows イベントログへの書き込みも検討してください。ファイルログと違って、運用側が既に見ている場所(イベント ビューアー、既存の監視ツール)に成否が届くのが利点です。
# --- セットアップ時に一度だけ、管理者権限で実行する(インストーラーや初期設定スクリプト)---
if (-not [System.Diagnostics.EventLog]::SourceExists('KS-Jobs')) {
[System.Diagnostics.EventLog]::CreateEventSource('KS-Jobs', 'Application')
}
# --- ジョブ本体(最小権限アカウントで実行)は書き込みだけを行う。
# SourceExists は全ログの探索に管理者権限を要求し得るので、実行時には呼ばない。
# 以下は Main の失敗ハンドラ(catch)内で呼び出す想定 ---
catch {
$err = $_
try {
[System.Diagnostics.EventLog]::WriteEntry('KS-Jobs',
"Cleanup-Logs failed: $($err.Exception.Message)",
[System.Diagnostics.EventLogEntryType]::Error, 1001)
}
catch {
# ログに書けないことを、元の失敗を握り潰す理由にしない
Write-Warning "イベントログへの書き込みに失敗: $_"
}
exit 1
}
2 点補足します。まず、イベントソースの登録(CreateEventSource)には管理者権限が必要です。ジョブ本体に登録処理を混ぜると、最小権限のサービスアカウントで動く本番の初回失敗時に「登録しようとして例外 → 肝心のイベントが書けない」という二重の失敗になります。上のように登録はセットアップ側へ分離し、実行時は書き込みだけにしてください。次に、この記事のタスク登録例のように実行エンジンを pwsh.exe にしている場合、Windows PowerShell 5.1 時代の New-EventLog / Write-EventLog コマンドレットは使えません(コマンドが見つからずスクリプトごと失敗します)。上のように .NET クラスを直接呼ぶ形なら 5.1 / 7 のどちらでも動きます。
そのうえで、「失敗したら人に届く」仕組み──メールや Teams / Slack への通知──を一つ入れておくと、「数か月止まっていたことに棚卸しで気づく」事故を防げます。凝った通知基盤は不要で、失敗時だけ Webhook に POST する数行でも十分に機能します。逆に「成功のたびに通知」は早晩読まれなくなるので、成功は週次のサマリー程度に抑え、失敗と「実行されなかった」(前回実行時刻が古い)を検知対象にするのがおすすめです。ログに何を書くべきかの基準は「例外の捕捉とログ設計」でも整理しています。
7. 多重起動と長時間実行の制御
前回の実行が長引いているうちに次のスケジュール時刻が来たらどうなるか。これは設定タブの「タスクが既に実行中の場合に適用される規則」で決まり、PowerShell では -MultipleInstances に対応します。5
| 設定値 | 動作 | 向いている用途 |
|---|---|---|
| IgnoreNew(GUI 既定: 新しいインスタンスを開始しない) | 実行中なら新規起動をスキップ | 冪等な定期バッチ全般。まずこれ |
| Queue | 実行中なら終了後に順番に実行 | 取りこぼしが許されない集計系 |
| Parallel | 並行して起動 | 原則避ける。並行安全が保証できる場合のみ |
あわせて「停止するまでの時間」(-ExecutionTimeLimit、既定 3 日)を現実的な値(想定実行時間の 2〜3 倍程度)に設定しておくと、ハングしたプロセスが翌日のジョブを道連れにする事故を防げます。5
注意したいのは、IgnoreNew や Queue が守ってくれるのは同じタスク定義の中だけだという点です。別のタスクが同じスクリプトを呼んでいる場合や、障害対応で人が手動実行した場合の衝突までは防げません。同じ資源(ファイル、DB、外部システム)を触る経路が複数あるなら、スクリプト側にも排他を持たせます。定石は名前付きミューテックスです。
$mutex = New-Object System.Threading.Mutex($false, 'Global\KS-Cleanup-Logs')
$acquired = $false
try {
try {
$acquired = $mutex.WaitOne(0)
}
catch [System.Threading.AbandonedMutexException] {
# 前回のジョブがミューテックスを持ったまま強制終了した(タスクの
# 「停止するまでの時間」超過、プロセスのkill、電源断など)。
# このとき WaitOne は false を返すのではなく例外を投げ、
# 所有権はこちらに渡っている。捕まえずに落ちると、以後の実行が
# 毎回ここで止まり、ジョブが二度と動かなくなる
$acquired = $true
Write-Warning '前回の実行が異常終了しています。中断された作業の後始末を確認してください。'
# 途中まで書いたファイルや中途半端なレコードが残っていないかを、
# ここで検査してから本処理へ進む
}
if (-not $acquired) {
Write-Warning '別のインスタンスが実行中のため終了します。'
exit 0 # 「実行しなかった」を失敗にしない場合は 0、失敗扱いなら非 0 に
}
# 本処理
}
finally {
if ($acquired) { $mutex.ReleaseMutex() }
$mutex.Dispose()
}
AbandonedMutexException は「前の持ち主が解放しないまま消えた」ことを知らせる例外で、投げられた時点で所有権はこちらに移っています。だからここで exit してしまうと、解放されないまま次回も同じ例外が出て、ジョブが永久に動かなくなります。捕まえて、中断された作業の状態を確認したうえで続行するのが正しい扱いです。
名前の先頭に Global\ を付けると、別セッション(別ユーザーのタスクと手動実行など)間でも排他が効きます。ロック取得を待つのか(WaitOne にタイムアウトを渡す)、即座にあきらめるのかは、ジョブの性質に合わせて決めてください。なお Global\ の名前付きオブジェクトはマシン上の誰からも見える点には注意が必要です。複数の利用者がログオンする共有サーバーでは、悪意や事故で同名のミューテックスを先に握られると、ジョブが永遠にスキップされ続ける(しかも exit 0 なら正常に見える)ことになります。そうした環境では、ミューテックスに ACL(MutexSecurity)を設定して取得できるアカウントを絞るか、少なくとも「取得できずにスキップした」ことを前節の通知・イベントログに乗せて、スキップの連続を監視で検知できるようにしてください。ファイルを介した連携での排他制御は「ファイル連携とロックのベストプラクティス」で詳しく扱っています。
8. タスクスケジューラの「やめどき」 ── 常駐サービスとの使い分け
タスクスケジューラは万能ではありません。要件が育ってきたときに、無理に使い続けるより仕組みを乗り換えたほうがよい境界があります。
| 要件 | 向いている仕組み |
|---|---|
| 1 日数回までの定時バッチ | タスクスケジューラ |
| 起動契機が人・イベント・時刻の混在で、フロー全体を見せたい | Power Automate(別記事) |
| 分単位のポーリング、常時監視、キュー処理 | Windows サービス / 常駐プロセス |
| 処理間で状態を保持したい、リトライ・バックオフを細かく制御したい | Windows サービス / 常駐プロセス |
「5 分ごとのタスク」でポーリングを始めると、起動のたびにプロセス生成・モジュール読み込みのコストがかかるうえ、前回の状態をファイルなどに退避する仕組みが必要になり、実質的に常駐プロセスを細切れに再実装することになります。この段階に来たら、.NET の Generic Host と BackgroundService で常駐化するのが素直です。実装パターンは「Generic HostとBackgroundServiceをデスクトップアプリで使う」で解説しています。
逆に、月次・日次のバッチをわざわざサービス化して自前でタイマー管理するのも過剰です。「実行間隔が時間単位以上・処理が独立・状態を持たない」ならタスクスケジューラ、それを外れ始めたら常駐化を検討する、という線引きで大きく間違いません。
9. 運用に乗せる前のチェックリスト
登録前に、次の項目を一度ずつ確認することをおすすめします。
- 実行アカウントは決めたか(SYSTEM を惰性で選んでいないか。ドメインなら gMSA を検討したか)
- ログオン種別の制約を理解したか(S4U ならネットワークアクセスなし。Password ならパスワード変更時の運用を決めたか)
- スクリプトを実行アカウント相当の条件で単体テストしたか
-NoProfile -NonInteractive -ExecutionPolicy Bypass -Fileの形で呼んでいるか- スクリプト内のパスは
$PSScriptRoot/ UNC 基準か(マップドライブ・相対パスに依存していないか) - 「開始(オプション)」に引用符を入れていないか
- 終了コードを設計したか(成功 0 / 失敗非 0。外部コマンドの終了コード規約を確認したか)
- タスク履歴を有効にしたか。スクリプト自身のログと失敗通知はあるか
- 電源条件・StartWhenAvailable・多重起動・実行時間制限を明示的に設定したか
- タスク定義を XML または PowerShell スクリプトとしてリポジトリに保存したか
10. まとめ
タスクスケジューラは「スクリプトを書けば終わり」ではなく、実行アカウント・セッション・既定値という 3 つの前提を設計して初めて安定運用に乗ります。逆に言えば、この記事で挙げたポイント──ログオン種別の選択、履歴の有効化、終了コードとログの設計、多重起動と時間制限の明示──を登録時に一度押さえてしまえば、その後は驚くほど手がかからなくなります。
「手動なら動くのに定期実行だと動かない」は、ほぼ確実にセッションと環境の差が原因です。闇雲に設定をいじる前に、履歴タブでどこまで進んでいるかを確認し、この記事の切り分け手順を上から試してみてください。
関連記事
- PowerShellスクリプト応用 ── ログ調査・アーカイブ・レポート化を安全に自動化する
- PesterによるPowerShellのテスト整備 ── 運用スクリプトを壊しにくくする実務の型
- Power Automateで業務を自動化する ── クラウドフロー・デスクトップフローの使い分けとエラー処理設計
- Windowsアプリに管理者権限が必要なのはどんなときか
関連する相談領域
合同会社小村ソフトでは、PowerShell・タスクスケジューラによる業務自動化の設計レビューや、「動いてはいるが誰も直せない」状態になった定期ジョブの立て直しの相談を扱っています。
参考リンク
-
Microsoft Learn, logonType Simple Type (Task Scheduler). ログオン種別の定義。S4U ではパスワードが保存されない代わりに、ネットワークおよび暗号化ファイルへのアクセスができないことについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Troubleshoot issues with scheduled tasks not running. スクリプト単体テスト → 状態・履歴確認 → セキュリティオプション変更、という切り分け手順と、TaskScheduler Operational イベントログの場所について。 ↩ ↩2 ↩3
-
Microsoft Learn, Task Scheduler error and success constants. SCHED_S_TASK_READY (0x41300)、SCHED_S_TASK_RUNNING (0x41301)、SCHED_S_TASK_HAS_NOT_RUN (0x41303) などの状態・エラーコード定義について。 ↩ ↩2
-
Microsoft Learn, Manage group Managed Service Accounts. gMSA のパスワードをドメインコントローラーが管理しホストが取得すること、タスクスケジューラのタスクが gMSA をサポートすること、ドメイン・フォレストの機能レベルが Windows Server 2012 以降であること、KDS ルートキーが必要であること(KdsSvc Operational ログのイベント ID 4004 で確認)、gMSA 名がフォレスト単位で一意である必要があること、
New-ADServiceAccountの-PrincipalsAllowedToRetrieveManagedPassword、各ホストでのInstall-ADServiceAccountとTest-ADServiceAccountについて。 ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, New-ScheduledTaskSettingsSet. MultipleInstances(Parallel / Queue / IgnoreNew)、StartWhenAvailable、ExecutionTimeLimit(既定 3 日)などタスク設定オブジェクトのパラメーターについて。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Security Contexts for Tasks. タスクのセキュリティコンテキストと、Password / S4U で登録したタスクの実行に「バッチ ジョブとしてログオン」権利が必要なことについて。 ↩ ↩2
-
Microsoft Learn, New-ScheduledTaskPrincipal.
-UserIdで実行アカウントを、-LogonTypeでログオン方法(None/Password/S4U/Interactive/Group/ServiceAccount/InteractiveOrPassword)を指定すること、-RunLevelがLimitedとHighestを取ることについて。 ↩ -
Microsoft Learn(アーカイブ), General Task Registration. Microsoft-Windows-TaskScheduler のイベント 106(タスクの登録)・113(登録できたが一部トリガーが開始しない)・116(構成は保存できたが資格情報を保存できない)・140(更新)・141(削除)のメッセージ定義について。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn(アーカイブ), Task Monitoring and Control. Microsoft-Windows-TaskScheduler のイベント 100(タスク開始)・102(正常終了)・111(実行時間超過による終了)・129(プロセスID付きの起動)・200/201(操作の開始・完了)・202/203(操作の完了失敗・起動失敗)・323(新インスタンス起動のための停止)。とくに 201 はシンボル名が
ACTION_SUCCESSで「Task Scheduler successfully completed task … and action …」、202 は「Task Scheduler failed to complete the … instance of the … task with action … The error value is: …」であり、202 はタスクスケジューラ側が操作を完了できなかったことを示すこと。現在の Windows が出す 201 はバージョン 2 で、本文が「… with return code N」となり、イベントデータにResultCodeを持つこと(この値がタスクの「前回の実行結果」と一致しない場合があることを含む)・327(バッテリー切替による停止)・328(アイドルでなくなったための停止)・329(タイムアウト)・330(ユーザー要求による停止)のメッセージ定義について。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 -
Microsoft Learn(アーカイブ), Event ID 322 — Task Properties. イベント 322(シンボル名
NEW_INSTANCE_IGNORED)が「同じタスクの別インスタンスが既に実行中のため起動しなかった」ことを示すこと、条件・設定の見直し手順について。 ↩ -
Microsoft Learn, What’s New in Task Scheduler. Windows 10 以降、バッテリー節約機能が有効な間は対話型以外のタスクのトリガーが遅延されることについて。 ↩
-
Microsoft Learn, robocopy. 終了コード表(0 はコピー対象なし、1 は全ファイルを正常にコピー、2 以降は追加ファイル・不一致の組み合わせ)と、8 以上がコピー処理中に少なくとも 1 件の失敗があったことを示すことについて。 ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
Power AutomateとPowerShell+タスクスケジューラの使い分け ── 自動化の道具を混ぜずに適材適所でつなぐ
PowerShell+タスクスケジューラの夜間バッチとPower Automateフローが社内に混在し始めた中小企業の情シス向けに、両者の得意分野の違い、どちらで作るかの判断表、SharePoint経由で疎結合につなぐ連携パターン、ライセンスと保守の注意点まで整理します。
Get-WinEventでイベントログを実務的に調べる ── 絞り込みの速さが調査時間を決める
Windowsのイベントログ調査をPowerShellで効率化する方法をまとめます。Where-Objectで絞ると遅い理由、FilterHashtableとXPathの使い分け、再起動やログオン・アプリ異常終了の調査レシピ、複数台からの収集までを解説します。
PowerShellから外部exeを正しく呼ぶ ── 引数のクォート・終了コード・文字化けの落とし穴
PowerShellからrobocopyや社内EXEを呼ぶと引数が壊れる、終了コードが取れない、出力が文字化けする。PowerShell 7.3の引数渡し変更、停止解析トークン--%、Start-Processの使い分けまでを実務目線で整理します。
PowerShellのエラー処理と再実行設計 ── try/catchが効かない罠からexit code・リトライの定石まで
PowerShellの終了エラーと非終了エラーの違い、try/catchが効かない罠と-ErrorAction Stopの定石、$LASTEXITCODEによる成否判定、exit code設計、指数バックオフのリトライまでを実務目線で整理します。
Process Monitor(ProcMon)実践ガイド ── 「設定が読まれない」「ACCESS DENIED」を10分で特定する
「設定を直したのに反映されない」などの不具合は、Process Monitor(ProcMon)でファイル・レジストリアクセスの実態から原因を特定できます。フィルタの実務的な使い方、NAME NOT FOUND等の読み方まで解説します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
技術相談・設計レビュー
改修方針、設計レビュー、既存資産の扱いを整理するための技術相談です。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- タスクスケジューラの「前回の実行結果」に出る0x1は何を意味しますか?
- 0x1はタスクスケジューラ自身のエラーではなく、起動したプログラムが終了コード1を返したという意味です。原因はスクリプト側にあります。手動実行と定期実行では、カレントディレクトリ、環境変数やプロファイル、実行ポリシーが異なるのが典型的な原因です。またrobocopyのように正常時でも1を返す外部コマンドの終了コード規約にも注意が必要です。0x413xx系はタスクスケジューラの状態コード、0x8007xxxxはWindowsのエラーコードという区別を知っておくと、調べる場所を間違えなくなります。
- 手動なら動くのにタスクスケジューラだと動かないのはなぜですか?
- ほぼ確実に実行アカウントとセッション・環境の差が原因です。「ユーザーがログオンしているかどうかにかかわらず実行」を選ぶと非対話セッションで動くため、マップされたネットワークドライブやユーザープロファイルの環境変数が存在しません。さらに「パスワードを保存しない」(S4U)ではネットワーク上のリソースへアクセスできません。切り分けは、履歴タブの確認、スクリプトの単体テスト、「ログオンしているときのみ実行」への一時変更、という手順が有効です。タスク履歴は既定で無効なので、運用前に必ず有効化してください。
- タスクスケジューラでPowerShellスクリプトを呼ぶ正しい書き方は?
- プログラムにpwsh.exe(またはpowershell.exe)を指定し、引数は -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "フルパス" の形が基本です。-Commandではなく-Fileを使うと、スクリプトのexit nがそのままプロセスの終了コードになり成否を判別できます。スクリプト内のパスは$PSScriptRoot基準にし、「開始(オプション)」欄には引用符を付けてはいけません(付けると0x8007010Bで失敗します)。スクリプト側では成功なら0、失敗なら0以外を明示的に返す設計にします。
- パスワード変更でタスクが止まる事故はどう防ぎますか?
- 「ログオンしているかどうかにかかわらず実行」で登録するとパスワードが保存されるため、パスワード変更後はログオン失敗(0x8007052E)で止まり続けます。ドメイン環境ならパスワードをドメインコントローラーが自動管理するgMSA(グループ管理サービスアカウント)が第一候補で、この問題そのものがなくなります。専用サービスアカウントを使う場合は、パスワード有効期限とタスクの棚卸しをセットで管理してください。あわせて失敗時にメールやTeamsへ通知する仕組みを入れておくと、数か月止まっていたことに気づかない事故を防げます。