45395 - シコウサクゴ -

Windows Task SchedulerのXML定義をテンプレート化してClaude Codeで一括管理する方法

2026-04-08
インフラ
Windows
タスクスケジューラ
自動化
Claude Code
PowerShell
Last updated:2026-04-09
10 Minutes
1909 Words

概要

データ処理パイプラインで6つのプログラム(日次処理3種 + リアルタイム処理3種)をWindows Task Schedulerで定期実行しています。最初は手動でGUIから1つずつ登録していましたが、実行時刻の一括変更やPython環境パスの更新のたびにGUIで6タスクを修正するのは非現実的でした。

そこでTask SchedulerのXML定義をテンプレート化し、PowerShellスクリプトで一括生成・登録する仕組みを構築しました。さらにClaude Codeから一括更新できるワークフローを整備したことで、スケジュール変更が数分で完了するようになりました。


Task SchedulerのXML定義

GUIの限界

Windows Task Schedulerにはリッチなgui画面がありますが、以下の問題があります。

  • タスクが増えると管理不能: 6タスクを手動管理するだけで修正漏れが発生する
  • 一括変更ができない: Python環境パスの変更時に6タスク分の修正が必要
  • バージョン管理できない: いつ誰が何を変更したか追跡できない
  • 再現性がない: 環境を作り直す際にGUI操作を思い出す必要がある

XMLエクスポート

Task Schedulerに登録済みのタスクはXML形式でエクスポートできます。

Terminal window
1
# 既存タスクをXMLとしてエクスポート
2
Export-ScheduledTask -TaskName "DailyBatchA" | Out-File -FilePath ".\DailyBatchA.xml" -Encoding UTF8

エクスポートされたXMLの構造は以下のとおりです。

1
<?xml version="1.0" encoding="UTF-16"?>
2
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
3
<RegistrationInfo>
4
<Description>日次集計バッチ 処理A</Description>
5
<URI>\DataPipeline\DailyBatchA</URI>
6
</RegistrationInfo>
7
<Triggers>
8
<CalendarTrigger>
9
<StartBoundary>2025-01-01T18:00:00+09:00</StartBoundary>
10
<Enabled>true</Enabled>
11
<ScheduleByWeek>
12
<DaysOfWeek>
13
<Monday /><Tuesday /><Wednesday /><Thursday /><Friday />
14
</DaysOfWeek>
15
<WeeksInterval>1</WeeksInterval>
21 collapsed lines
16
</ScheduleByWeek>
17
</CalendarTrigger>
18
</Triggers>
19
<Actions Context="Author">
20
<Exec>
21
<Command>C:\anaconda3\envs\st312\python.exe</Command>
22
<Arguments>-m _dailyBatchA.main</Arguments>
23
<WorkingDirectory>C:\work\data-pipeline</WorkingDirectory>
24
</Exec>
25
</Actions>
26
<Settings>
27
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
28
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
29
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
30
<AllowHardTerminate>true</AllowHardTerminate>
31
<StartWhenAvailable>true</StartWhenAvailable>
32
<RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable>
33
<ExecutionTimeLimit>PT4H</ExecutionTimeLimit>
34
<AllowStartOnDemand>true</AllowStartOnDemand>
35
</Settings>
36
</Task>

テンプレート化

テンプレートXMLの設計

6タスクで異なるのは以下の4つだけです。

可変要素
タスク名DailyBatchA, RealtimeB
説明文「日次集計バッチ 処理A」
実行時刻18:00(日次処理)、毎時00分(リアルタイム処理)
実行モジュール_dailyBatchA.main, _realtimeB.main

これらをプレースホルダーにしたテンプレートを作成します。

1
<?xml version="1.0" encoding="UTF-16"?>
2
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
3
<RegistrationInfo>
4
<Description>{{DESCRIPTION}}</Description>
5
<URI>\DataPipeline\{{TASK_NAME}}</URI>
6
</RegistrationInfo>
7
<Triggers>
8
{{TRIGGER_BLOCK}}
9
</Triggers>
10
<Actions Context="Author">
11
<Exec>
12
<Command>{{PYTHON_PATH}}</Command>
13
<Arguments>-m {{MODULE_NAME}}.main</Arguments>
14
<WorkingDirectory>{{PROJECT_ROOT}}</WorkingDirectory>
15
</Exec>
12 collapsed lines
16
</Actions>
17
<Settings>
18
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
19
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
20
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
21
<AllowHardTerminate>true</AllowHardTerminate>
22
<StartWhenAvailable>true</StartWhenAvailable>
23
<RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable>
24
<ExecutionTimeLimit>PT4H</ExecutionTimeLimit>
25
<AllowStartOnDemand>true</AllowStartOnDemand>
26
</Settings>
27
</Task>

トリガーブロックのテンプレート

日次処理とリアルタイム処理で実行パターンが異なるため、トリガー部分は2種類用意します。

日次処理用(平日の指定時刻に1回実行):

1
<CalendarTrigger>
2
<StartBoundary>2025-01-01T{{EXEC_TIME}}:00+09:00</StartBoundary>
3
<Enabled>true</Enabled>
4
<ScheduleByWeek>
5
<DaysOfWeek>
6
<Monday /><Tuesday /><Wednesday /><Thursday /><Friday />
7
</DaysOfWeek>
8
<WeeksInterval>1</WeeksInterval>
9
</ScheduleByWeek>
10
</CalendarTrigger>

リアルタイム処理用(毎時実行 = 繰り返し):

1
<CalendarTrigger>
2
<StartBoundary>2025-01-01T00:00:00+09:00</StartBoundary>
3
<Enabled>true</Enabled>
4
<Repetition>
5
<Interval>PT1H</Interval>
6
<Duration>P1D</Duration>
7
<StopAtDurationEnd>false</StopAtDurationEnd>
8
</Repetition>
9
<ScheduleByDay>
10
<DaysInterval>1</DaysInterval>
11
</ScheduleByDay>
12
</CalendarTrigger>

PowerShellスクリプトによる一括生成

タスク定義

6タスクの設定値をハッシュテーブルの配列で定義します。

Terminal window
1
$PythonPath = "C:\anaconda3\envs\st312\python.exe"
2
$ProjectRoot = "C:\work\data-pipeline"
3
$TemplateDir = "$ProjectRoot\task_scheduler\templates"
4
$OutputDir = "$ProjectRoot\task_scheduler\generated"
5
6
# 6タスクの定義
7
$Tasks = @(
8
@{
9
Name = "DailyBatchA"
10
Module = "_dailyBatchA"
11
Description = "日次集計バッチ 処理A"
12
Type = "Daily"
13
ExecTime = "18:00"
14
},
15
@{
35 collapsed lines
16
Name = "DailyBatchB"
17
Module = "_dailyBatchB"
18
Description = "日次集計バッチ 処理B"
19
Type = "Daily"
20
ExecTime = "18:15"
21
},
22
@{
23
Name = "DailyBatchC"
24
Module = "_dailyBatchC"
25
Description = "日次集計バッチ 処理C"
26
Type = "Daily"
27
ExecTime = "18:30"
28
},
29
@{
30
Name = "RealtimeA"
31
Module = "_realtimeA"
32
Description = "リアルタイム処理A"
33
Type = "Realtime"
34
ExecTime = "00:00"
35
},
36
@{
37
Name = "RealtimeB"
38
Module = "_realtimeB"
39
Description = "リアルタイム処理B"
40
Type = "Realtime"
41
ExecTime = "00:00"
42
},
43
@{
44
Name = "RealtimeC"
45
Module = "_realtimeC"
46
Description = "リアルタイム処理C"
47
Type = "Realtime"
48
ExecTime = "00:00"
49
}
50
)

XML生成スクリプト

Terminal window
1
function New-TaskXml {
2
param(
3
[hashtable]$TaskDef,
4
[string]$PythonPath,
5
[string]$ProjectRoot,
6
[string]$TemplateDir,
7
[string]$OutputDir
8
)
9
10
# テンプレート読み込み
11
$template = Get-Content "$TemplateDir\task_template.xml" -Raw
12
13
# トリガーブロックの選択
14
$triggerFile = if ($TaskDef.Type -eq "Daily") {
15
"$TemplateDir\trigger_daily.xml"
39 collapsed lines
16
} else {
17
"$TemplateDir\trigger_realtime.xml"
18
}
19
$triggerBlock = Get-Content $triggerFile -Raw
20
$triggerBlock = $triggerBlock -replace '\{\{EXEC_TIME\}\}', $TaskDef.ExecTime
21
22
# プレースホルダー置換
23
$xml = $template `
24
-replace '\{\{TASK_NAME\}\}', $TaskDef.Name `
25
-replace '\{\{DESCRIPTION\}\}', $TaskDef.Description `
26
-replace '\{\{MODULE_NAME\}\}', $TaskDef.Module `
27
-replace '\{\{PYTHON_PATH\}\}', $PythonPath `
28
-replace '\{\{PROJECT_ROOT\}\}', $ProjectRoot `
29
-replace '\{\{TRIGGER_BLOCK\}\}', $triggerBlock
30
31
# 出力
32
$outputPath = Join-Path $OutputDir "$($TaskDef.Name).xml"
33
$xml | Out-File -FilePath $outputPath -Encoding UTF8
34
Write-Host "生成完了: $outputPath"
35
36
return $outputPath
37
}
38
39
# 全タスクのXML生成
40
if (-not (Test-Path $OutputDir)) {
41
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
42
}
43
44
$generatedFiles = @()
45
foreach ($task in $Tasks) {
46
$path = New-TaskXml -TaskDef $task `
47
-PythonPath $PythonPath `
48
-ProjectRoot $ProjectRoot `
49
-TemplateDir $TemplateDir `
50
-OutputDir $OutputDir
51
$generatedFiles += $path
52
}
53
54
Write-Host "`n生成されたXMLファイル: $($generatedFiles.Count)件"

Task Schedulerへの一括登録

Terminal window
1
function Register-AllTasks {
2
param(
3
[string]$OutputDir,
4
[array]$Tasks
5
)
6
7
foreach ($task in $Tasks) {
8
$xmlPath = Join-Path $OutputDir "$($task.Name).xml"
9
10
if (-not (Test-Path $xmlPath)) {
11
Write-Warning "XMLファイルが見つかりません: $xmlPath"
12
continue
13
}
14
15
# 既存タスクがあれば削除
16 collapsed lines
16
$existingTask = Get-ScheduledTask -TaskName $task.Name -ErrorAction SilentlyContinue
17
if ($existingTask) {
18
Unregister-ScheduledTask -TaskName $task.Name -Confirm:$false
19
Write-Host "既存タスク削除: $($task.Name)"
20
}
21
22
# XMLからタスク登録
23
Register-ScheduledTask -TaskName $task.Name `
24
-TaskPath "\DataPipeline\" `
25
-Xml (Get-Content $xmlPath -Raw) `
26
-Force
27
Write-Host "タスク登録完了: $($task.Name)"
28
}
29
}
30
31
Register-AllTasks -OutputDir $OutputDir -Tasks $Tasks

Claude Codeからの一括更新ワークフロー

Claude Codeを使うと、自然言語でスケジュール変更を指示できます。

典型的な変更パターン

パターン1: 実行時刻の一括変更

「日次処理の実行時刻を18:00から17:30に変更して」とClaude Codeに指示すると、以下が自動で行われます。

  1. PowerShellスクリプトの$Tasks配列にあるExecTimeを修正
  2. XMLを再生成
  3. Task Schedulerに再登録

パターン2: Python環境パスの変更

Anacondaの環境を更新した場合、$PythonPathを1行変更してXMLを再生成するだけで6タスク全てに反映されます。

パターン3: 新しい処理パターンの追加

$Tasks配列にハッシュテーブルを1つ追加し、対応するモジュールを作成すれば、スケジューラ登録まで自動化できます。

Claude Codeとの連携のポイント

1
重要なルール:
2
1. テンプレートとスクリプトはGit管理する
3
2. Claude Codeが変更するのは設定値($Tasks配列)のみ
4
3. XML生成と登録はPowerShellスクリプト経由で行う(直接XML編集はしない)
5
4. 変更後は必ず Get-ScheduledTask で登録状態を確認する
Terminal window
1
# 変更後の確認コマンド
2
Get-ScheduledTask -TaskPath "\DataPipeline\" | Format-Table TaskName, State, @{
3
Name = "NextRunTime"
4
Expression = {
5
(Get-ScheduledTaskInfo -TaskName $_.TaskName).NextRunTime
6
}
7
}

出力例:

1
TaskName State NextRunTime
2
-------- ----- -----------
3
DailyBatchA Ready 2026-04-09 17:30:00
4
DailyBatchB Ready 2026-04-09 17:45:00
5
DailyBatchC Ready 2026-04-09 18:00:00
6
RealtimeA Ready 2026-04-08 13:00:00
7
RealtimeB Ready 2026-04-08 13:00:00
8
RealtimeC Ready 2026-04-08 13:00:00

テンプレート化のメリット

Before(GUIで個別管理)

操作時間リスク
1タスクの時刻変更2分入力ミス
6タスクの一括変更12分修正漏れ
Pythonパス変更12分修正漏れ
環境再構築30分以上手順忘れ

After(テンプレート + PowerShell)

操作時間リスク
1タスクの時刻変更1分なし(スクリプト経由)
6タスクの一括変更1分なし(設定値1箇所変更)
Pythonパス変更1分なし(変数1箇所変更)
環境再構築2分なし(スクリプト実行のみ)

注意点

ExecutionTimeLimit

<ExecutionTimeLimit>PT4H</ExecutionTimeLimit>(最大実行時間4時間)を設定しています。この設定がないと、スクリプトがハングした場合にTask Schedulerがプロセスを終了しません。デフォルト値の72時間は長すぎるため、処理内容に合わせて適切な値を設定すべきです。

StartWhenAvailable

<StartWhenAvailable>true</StartWhenAvailable>を設定すると、予定時刻にPCがスリープ中だった場合、復帰後に遅延実行されます。ノートPCで運用する場合は必須の設定です。

RunOnlyIfNetworkAvailable

<RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable>を設定しています。API経由でデータを取得するため、ネットワーク未接続時に実行しても意味がないためです。


まとめ

Windows Task SchedulerのXML定義をテンプレート化するメリットは以下の3点です。

  1. 一括変更が1箇所で完結: PowerShellスクリプトの設定値を1箇所変更するだけで、6タスク全てに反映される
  2. Git管理でバージョン追跡可能: テンプレートとスクリプトをGitで管理することで、変更履歴が残る
  3. Claude Codeとの親和性: テンプレートのプレースホルダー構造は、AIによるコード修正と相性が良い。自然言語で「実行時刻を変更して」と指示するだけで済む

手動のGUI操作を排除し、設定をコードとして管理する(Infrastructure as Code)アプローチは、タスクが少ないうちから導入しておくと、後からタスクが増えたときに効いてきます。

Article title:Windows Task SchedulerのXML定義をテンプレート化してClaude Codeで一括管理する方法
Article author:45395
Release time:2026-04-08

記事へのご質問・ご感想をお聞かせください

フィードバックを送る