みなさんこんにちは、ヒロポンです!
夜間バッチとか日次の定期処理、タスクスケジューラの GUI でポチポチ手作業登録してませんか??
それ、別のサーバーに移すとき地獄を見るやつなんですよね。
「あれ、前任者がどんな設定で登録したんだっけ」で再現できない。あるあるでしょ。
PowerShell の Register-ScheduledTask を使えば、タスクスケジューラへの登録をまるごとスクリプト化できます。
今回は日次バッチを PowerShell でタスクスケジューラに登録する手順を、コピペで動く形で押さえていきます。サービスアカウントで登録した時にだいたい一回はハマる権限まわりも、まとめておきますね。
結論: Action・Trigger・Principal を組んで Register-ScheduledTask に渡すだけ
先に結論。タスク登録は、4つのパーツを組み立てて1発で登録します。
New-ScheduledTaskAction… 何を実行するか(バッチ本体のスクリプト)New-ScheduledTaskTrigger… いつ動かすか(日次・時刻)New-ScheduledTaskPrincipal… 誰の権限で動かすか(実行ユーザー・特権)Register-ScheduledTask… 上の3つをまとめて登録
サービスアカウントで動かすなら、New-ScheduledTaskPrincipal の -LogonType と、アカウントの「バッチ ジョブとしてのログオン」権限がキモ。
ここを外すと「登録はできたのに実行だけ失敗する」という、一番わかりにくい詰まり方をします。
⚠️ 動作環境の前提: この記事のコマンド(
ScheduledTasksモジュール)は Windows 専用です。Windows PowerShell 5.1、または Windows 上の PowerShell 7 で動きます。Linux / macOS の PowerShell や、コンテナ上の Linux pwsh にはScheduledTasksモジュールが入っていないので動きません。動作確認は Windows Server 上でやってください。
最短: コピペで動く登録スクリプト
まず全体像。4つのパーツがこう繋がって1タスクになります。

基本形: 毎朝2時に日次バッチを回す
一番シンプルな形。今ログオンしている自分(or 管理者)の権限で、毎朝2時にスクリプトを走らせます。
# 1. 何を実行するか(バッチ本体をフルパスで)
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -File C:\batch\daily-batch.ps1"
# 2. いつ動かすか(毎日 2:00)
$trigger = New-ScheduledTaskTrigger -Daily -At 2am
# 3. 設定(PC起動時に時刻を過ぎてたら起動、実行時間の上限2時間)
$settings = New-ScheduledTaskSettingsSet `
-StartWhenAvailable `
-ExecutionTimeLimit (New-TimeSpan -Hours 2)
# 4. まとめて登録(同名タスクがあれば上書き)
Register-ScheduledTask `
-TaskName "DailyBatch" `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-Description "日次バッチ(PowerShellから登録)" `
-Force
-Execute に powershell.exe、-Argument に実際のスクリプトを渡すのがコツ。
.ps1 を直接 -Execute に書くと、ダブルクリック相当の扱いになる。環境によっては「メモ帳で開く」みたいな事故になります。powershell.exe -File ... の形が確実。
-Force を付けておくと、同名タスクが既にあっても上書き登録してくれます。再実行できるスクリプトにしておくと、あとが楽。こんな感じで冪等に書いておくと事故りません。
サービスアカウントで登録する(対話ログオンなしで動かす)
夜間バッチは、誰もログオンしてなくても動いてほしい。そのためにサービスアカウント(専用のドメインアカウント)で登録します。
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -File C:\batch\daily-batch.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At 2am
# 実行ユーザーをサービスアカウントに。最上位の特権で動かす
$principal = New-ScheduledTaskPrincipal `
-UserId "CORP\svc_batch" `
-LogonType Password `
-RunLevel Highest
Register-ScheduledTask `
-TaskName "DailyBatch" `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Description "日次バッチ(サービスアカウント実行)" `
-Force
-LogonType Password は「保存したパスワードでログオンして動かす」モード。-RunLevel Highest で管理者相当の特権を付けます。
パスワードを直接渡したいなら、Principal を使わず Register-ScheduledTask に -User と -Password を直接渡す形でもいけます。
Register-ScheduledTask `
-TaskName "DailyBatch" `
-Action $action `
-Trigger $trigger `
-User "CORP\svc_batch" `
-Password $plainPassword `
-RunLevel Highest `
-Force
ただ、このサービスアカウントで動かす形が一番ハマりが多い。次のハマりポイントで潰していきます。
組み込みアカウント(SYSTEM)で動かす場合
ネットワーク越しのリソースを触らない、ローカル完結のバッチなら、SYSTEM で動かすのが楽です。パスワード管理が要らない。
$principal = New-ScheduledTaskPrincipal `
-UserId "SYSTEM" `
-LogonType ServiceAccount `
-RunLevel Highest
SYSTEM / LOCALSERVICE / NETWORKSERVICE みたいな組み込みアカウントは、Register-ScheduledTask に渡すパスワードも無視されます(そもそも要らない)。
ただし共有フォルダや別サーバーの DB を触るバッチだと、権限が足りないことがある。そこはサービスアカウントの出番です。
ハマりポイント: サービスアカウントでだいたい一回は詰まる3つ
ここからが本番。GUI だと勝手にやってくれてたことが、スクリプト登録だと表に出てきます。
①「バッチ ジョブとしてのログオン」権限がないと、登録できても実行で落ちる
これが一番わかりにくい。
Register-ScheduledTask は成功する。タスクスケジューラにもちゃんと出てくる。なのに、いざ動く時間になると実行結果が 0x80070569(2147943785)になって、何も起きない。
「ん?登録は通ったよね??」って、ここで一回みんな固まります。
エラーの意味はこれ。
Logon failure: the user has not been granted the requested logon type at this computer.
サービスアカウントに「バッチ ジョブとしてのログオン」(SeBatchLogonRight)という権限がないと、タスクスケジューラはそのアカウントでログオンできず、実行時にコケます。
GUI で登録するとこの権限を裏で自動付与してくれることがある。ところが PowerShell 登録+ドメインの GPO 環境だと、GPO 側でこの権限が上書きされて剥がれてることが多いんですよね。
対処は、ローカルセキュリティポリシー(secpol.msc)かグループポリシーで、ローカル ポリシー → ユーザー権利の割り当て → バッチ ジョブとしてのログオン にそのサービスアカウントを追加する。
ここに居ないと、何回登録し直しても実行時に落ち続けます。
② パスワード変更・期限切れでタスクが黙って止まる
-LogonType Password は、登録した瞬間のパスワードを Windows の資格情報ストアに保存して使います。
ということは、AD 側でそのアカウントのパスワードを変えた瞬間、保存済みのパスワードが古くなる。
結果、次の実行から0x8007052E(Logon failure: unknown user name or bad password.)でタスクが止まる。
エラーも出さずにただ動かなくなる。「先週まで動いてた夜間バッチが、気づいたら3日連続で流れてなかった」みたいな事故になります。
対処はいくつか。
- gMSA(グループ管理サービスアカウント)を使う … AD がパスワードを管理して既定30日で自動ローテートしてくれる。登録時もパスワードを渡さなくていい。パスワード変更でタスクが止まる問題を根本から消せるので、これが本命。
- S4U(
-LogonType S4U) … パスワードを保存しないログオン方式。ただしネットワーク越しのリソースにはアクセスできないので、ローカル完結のバッチ向け。 - パスワード無期限のポリシーにする … 運用としては微妙だけど、現場でよく使われる逃げ。
パスワードローテートが必須の組織なら、迷わず gMSA。ここを最初に握っておくと後がめちゃくちゃ楽になります。
③ 手元で動くのにタスク経由だと動かない(作業ディレクトリと実行ポリシー)
登録したバッチが「対話で叩くと動くのに、タスク経由だと途中で失敗する」。これも定番。
原因の8割は作業ディレクトリ。タスクスケジューラは既定で C:\Windows\System32 をカレントにしてスクリプトを動かします。
スクリプト内で .\config.json みたいな相対パスを使ってると、System32 を基準に探しにいって「ファイルがない」で落ちる。
-Fileに渡すスクリプトはフルパスで- スクリプト内で読むファイルもフルパスで(もしくは
$PSScriptRootを基準にする) - 実行ポリシーで止まるなら
-ExecutionPolicy Bypassを付ける
この3点を最初から入れておくと、「手元では動いたのに」の温度差でハマらずに済みます。
現場メモ: スクリプト登録は「移設できる資産」になる
俺が Register-ScheduledTask を本気で使い出したのは、サーバー移設がきっかけでした。
流通系の基幹まわりで、前任者が GUI で手作業登録した夜間バッチが十数本。それを新サーバーに移す仕事です。
ところが GUI 登録だと設定がその1台に閉じてる。どんなトリガーでどのアカウントで動いてるか、1本ずつ画面を開いて目視で写経するしかない。
しかもサービスアカウントの権限まわりが移設先で剥がれてて、①の 0x80070569 を踏んで半日溶かしました。移設当日の夜、家に帰れると思ってたのに。
そこから、タスク登録は全部 PowerShell スクリプトにして Git に置くようにした。
そうすると、別サーバーへの移設が「スクリプトを1本流すだけ」になる。どのアカウントで何時に何を動かしてるかが、コードを読めば一発でわかる。
GUI のポチポチは、その場では速い。でも移設・引き継ぎで一番高くつくやつなんですよね。
ちなみに登録済みタスクは Get-ScheduledTask で一覧、Export-ScheduledTask で XML に吐き出せます。既存タスクの棚卸しから入ると、こんな感じで現状把握もスクリプト化できて捗ります。
まとめ
PowerShell でのタスク登録、要点だけ。
- 基本は4パーツ:
New-ScheduledTaskAction(実行内容)→Trigger(タイミング)→Principal(実行ユーザー)→Register-ScheduledTask(登録)。 - サービスアカウントは「バッチ ジョブとしてのログオン」権限が必須。無いと登録できても実行時に
0x80070569で落ちる。 - パスワード変更で止まる問題は gMSA で根本解決。ローカル完結なら S4U や SYSTEM も手。
- タスク経由は作業ディレクトリが System32。パスはフルパス、実行ポリシーは Bypass。
GUI の手作業をスクリプトに置き換えると、その日は少し手間。でも移設・引き継ぎ・棚卸しが全部楽になります。いい感じに「再現できる自動化」にしていきましょう!!
よくある質問
PowerShell でタスクスケジューラに登録する最小の手順は?
New-ScheduledTaskAction(実行内容)、New-ScheduledTaskTrigger(起動タイミング)、New-ScheduledTaskPrincipal(実行ユーザー)の3つを変数に作り、Register-ScheduledTask にまとめて渡します。Principal を省けば、今ログオン中のユーザー権限で登録されます。この4つが基本セットです。
サービスアカウントで登録はできるのに実行時に失敗するのはなぜ?
実行アカウントに「バッチ ジョブとしてのログオン」(SeBatchLogonRight)の権限がないと、実行時に 0x80070569 のログオンエラーで落ちます。secpol.msc かグループポリシーの「ユーザー権利の割り当て」でこの権限を付与してください。GUI 登録では自動付与されることがありますが、GPO 環境では剥がれがちです。
実行ユーザーのパスワードを変えたらタスクが止まりました。どうすれば?
-LogonType Password はパスワードを保存して使うので、AD 側でパスワードを変更・期限切れにすると 0x8007052E で認証に失敗します。パスワードローテートが必要なら gMSA(グループ管理サービスアカウント)を使うと、AD がパスワードを自動更新してくれるのでタスクが止まりません。
登録したスクリプトが手元では動くのにタスク経由だと動かないのは?
タスクスケジューラの作業ディレクトリは既定で C:\Windows\System32 です。スクリプト内の相対パスがそこを基準に解決されてずれるので、-File もスクリプト内で読むファイルもフルパス(または $PSScriptRoot 基準)で指定してください。実行ポリシーで止まる場合は -ExecutionPolicy Bypass を付けます。
次に読むべき記事




以上!
同じ「夜間バッチが黙って止まってた」で青ざめた経験ある人、どんどんシェア待ってるぜ!!


