この記事は以下のシリーズの11番目の記事です。
この記事でやること
PowerShellスクリプトをタスクスケジューラに登録したのに、なぜか動かないことがあります。
手動では動く。
でもタスクスケジューラでは動かない。
ログが出ない。
ファイルが見つからない。
共有フォルダにアクセスできない。
画面が一瞬出るだけで終わる。
このようなトラブルは、PowerShellそのものよりも、実行ユーザー・作業フォルダ・権限・パス指定・ログ設計が原因になっていることが多いです。
この記事では、タスクスケジューラでPowerShellが動かないときに確認するポイントを10個に整理します。
前提:今回の基本形
タスクスケジューラでPowerShellを実行する場合、基本形は次の通りです。
| 設定項目 | 入力例 |
|---|---|
| プログラムまたはスクリプト | powershell.exe |
| 引数の追加 | -NoProfile -ExecutionPolicy Bypass -File "C:\work\ps-task-test\task-sample.ps1" |
| 開始場所 | C:\work\ps-task-test |
PowerShell 7を使う場合は、powershell.exe ではなく pwsh.exe を指定します。
pwsh.exe
この記事では、主に Windows PowerShell 5.1 の powershell.exe を前提に説明します。
1. まず手動実行で動くか確認する
最初に確認すべきことは、タスクスケジューラ以前に、.ps1 が手動で動くかどうかです。
PowerShellを開いて、次のように実行します。
Set-Location "C:\work\ps-task-test"
.\task-sample.ps1
これで失敗する場合、タスクスケジューラの問題ではありません。
スクリプトの内容、パス、実行ポリシー、ファイル権限などに問題があります。
タスクスケジューラに登録する前に、次の順番で確認します。
# 1. フォルダ移動
Set-Location "C:\work\ps-task-test"
# 2. ファイル確認
Get-ChildItem
# 3. スクリプト実行
.\task-sample.ps1
まず手動で動く状態を作ることが重要です。
2. タスクと同じコマンドを手動で実行する
次に、タスクスケジューラに設定している内容と同じコマンドを、手動で実行します。
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\work\ps-task-test\task-sample.ps1"
このコマンドで動くなら、.ps1 の内容は概ね問題ありません。
その場合は、タスクスケジューラ側の設定を疑います。
逆に、このコマンドでも失敗する場合は、引数、実行ポリシー、PowerShellの種類、スクリプトのパスなどを確認します。
PowerShell 7で動かしたい場合は、次のようにします。
pwsh.exe -NoProfile -ExecutionPolicy Bypass -File "C:\work\ps-task-test\task-sample.ps1"
powershell.exe と pwsh.exe は別物です。
手元ではPowerShell 7で試していたのに、タスクではWindows PowerShell 5.1で動かしている、というズレもよくあります。
3. 「プログラムまたはスクリプト」にps1を直接指定していないか
よくあるミスが、タスクスケジューラの「プログラムまたはスクリプト」に .ps1 ファイルを直接指定してしまうことです。
よくない例:
C:\work\ps-task-test\task-sample.ps1
基本的には、ここには powershell.exe を指定します。
よい例:
powershell.exe
そして、「引数の追加」に .ps1 のパスを指定します。
-NoProfile -ExecutionPolicy Bypass -File "C:\work\ps-task-test\task-sample.ps1"
設定は次のように分けます。
| 設定項目 | 入力内容 |
|---|---|
| プログラムまたはスクリプト | powershell.exe |
| 引数の追加 | -NoProfile -ExecutionPolicy Bypass -File "C:\work\ps-task-test\task-sample.ps1" |
| 開始場所 | C:\work\ps-task-test |
この3つを分けて入力するのが基本です。
4. 「開始場所」が空欄になっていないか
タスクスケジューラでは、「開始場所」が空欄でも登録できます。
しかし、開始場所が空欄だと、相対パスを使っているスクリプトで問題が起きやすくなります。
たとえば、スクリプト内で次のように書いている場合です。
Add-Content -Path ".\log.txt" -Value "処理開始"
この場合、どこに log.txt が作られるかは、実行時のカレントディレクトリに依存します。
そのため、開始場所にはスクリプトを置いたフォルダを指定します。
C:\work\ps-task-test
ただし、実務ではスクリプト側でも $PSScriptRoot を使う方が安全です。
$logPath = Join-Path $PSScriptRoot "log.txt"
Add-Content -Path $logPath -Value "処理開始"
$PSScriptRoot は、実行中の .ps1 が置かれているフォルダを表します。
タスクスケジューラで動かすスクリプトでは、なるべく $PSScriptRoot を使うのがおすすめです。
5. パスにスペースがあるのに引用符で囲んでいないか
パスにスペースが含まれている場合、引用符で囲まないと正しく解釈されません。
よくない例:
-NoProfile -ExecutionPolicy Bypass -File C:\work\ps task test\task-sample.ps1
よい例:
-NoProfile -ExecutionPolicy Bypass -File "C:\work\ps task test\task-sample.ps1"
特に次のようなパスでは注意が必要です。
C:\Program Files\
C:\Users\User Name\
C:\work\ps task test\
パスにスペースがある場合は、必ず引用符で囲みます。
6. 実行ユーザーが想定と違っていないか
タスクスケジューラは、指定したユーザーで処理を実行します。
手動実行しているユーザーと、タスクスケジューラの実行ユーザーが違うと、動作も変わります。
確認すべき項目は次の通りです。
| 確認項目 | 内容 |
|---|---|
| 実行ユーザー | どのユーザーでタスクを実行しているか |
| フォルダ権限 | そのユーザーが対象フォルダにアクセスできるか |
| 共有フォルダ権限 | そのユーザーが共有フォルダにアクセスできるか |
| 環境変数 | 手動実行時と同じ環境か |
| 資格情報 | パスワード変更などで失敗していないか |
スクリプト内で実行ユーザーをログに出しておくと、切り分けしやすくなります。
Add-Content -Path $logPath -Value "実行ユーザー: $env:USERNAME"
より詳しく見るなら、次のようにします。
Add-Content -Path $logPath -Value "USERDOMAIN: $env:USERDOMAIN"
Add-Content -Path $logPath -Value "USERNAME: $env:USERNAME"
手動実行では自分のユーザーで動いていても、タスクでは別ユーザーで動いている場合があります。
その場合、ファイルアクセス権限や共有フォルダ権限で失敗することがあります。
7. 「ログオンしているときのみ」と「ログオンしているかどうかにかかわらず」の違いを確認する
タスクスケジューラには、次の2つの実行方法があります。
ユーザーがログオンしているときのみ実行する
ユーザーがログオンしているかどうかにかかわらず実行する
検証時は、まず「ユーザーがログオンしているときのみ実行する」で試すと原因を追いやすいです。
一方、夜間実行や無人実行では「ユーザーがログオンしているかどうかにかかわらず実行する」を使うことがあります。
ただし、この設定では次のような違いが出ます。
| 項目 | ログオン時のみ | ログオンに関係なく |
|---|---|---|
| 画面表示 | 見える場合がある | 基本的に見えない |
| 対話入力 | 試しやすい | 向かない |
| 無人実行 | 不向き | 向いている |
| 権限問題 | 比較的追いやすい | 切り分けが必要 |
| 共有フォルダ | ユーザー状態に依存する場合あり | 資格情報・権限確認が重要 |
タスクスケジューラで使うPowerShellは、基本的に無人実行を前提にするべきです。
そのため、Read-Host や画面操作を求める処理は避けます。
避けたい例:
$name = Read-Host "名前を入力してください"
必要な値は、CSVや設定ファイルから読み込む設計にします。
8. ネットワークドライブを使っていないか
手動実行では Z: ドライブが見えているのに、タスクスケジューラでは見えないことがあります。
よくない例:
Copy-Item -Path "Z:\input\data.csv" -Destination "C:\work\backup"
タスクスケジューラでは、ログオン時に割り当てたネットワークドライブが使えないことがあります。
可能であれば、UNCパスを使います。
Copy-Item -Path "\\server\share\input\data.csv" -Destination "C:\work\backup"
ただし、UNCパスにしても、実行ユーザーに共有フォルダへのアクセス権が必要です。
共有フォルダを使う場合は、次を確認します。
| 確認項目 | 内容 |
|---|---|
| UNCパスでアクセスしているか |
\\server\share 形式 |
| 実行ユーザーに権限があるか | 読み取り・書き込み権限 |
| 手動実行とタスク実行のユーザーが同じか | ユーザー差異 |
| ログにアクセス結果を残しているか | 失敗原因の確認 |
共有フォルダ操作では、パスよりも権限が原因になることが多いです。
9. 実行ポリシーで止まっていないか
.ps1 が実行できない場合、実行ポリシーで止まっている可能性があります。
現在の実行ポリシーは、次のコマンドで確認できます。
Get-ExecutionPolicy
Get-ExecutionPolicy -List
タスクスケジューラでは、引数に次のように指定することがあります。
-ExecutionPolicy Bypass
全体の例です。
-NoProfile -ExecutionPolicy Bypass -File "C:\work\ps-task-test\task-sample.ps1"
ただし、Bypass は便利ですが、意味を理解せずに常用するものではありません。
会社PCでは、グループポリシーで実行ポリシーが制御されていることもあります。
その場合、個人で設定を変えられないことがあります。
Get-ExecutionPolicy -List
で、MachinePolicy や UserPolicy に設定が入っていないか確認します。
10. ログを出しているか
最後に、もっとも重要なのがログです。
タスクスケジューラでPowerShellが動かないとき、ログがないと原因が追えません。
最低限、次の情報をログに出すと切り分けしやすくなります。
| ログ項目 | 目的 |
|---|---|
| 処理開始時刻 | タスクが起動したか確認する |
| 処理終了時刻 | 最後まで到達したか確認する |
| 実行ユーザー | 権限問題の確認 |
| スクリプト配置場所 | パス問題の確認 |
| 対象ファイル | 処理対象の確認 |
| 成功・失敗 | 結果確認 |
| エラーメッセージ | 原因確認 |
最小のログテンプレートは次の通りです。
$logDir = Join-Path $PSScriptRoot "logs"
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
$today = Get-Date -Format "yyyyMMdd"
$logPath = Join-Path $logDir "task_$today.log"
function Write-Log {
param(
[string]$Message
)
$now = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $logPath -Value "[$now] $Message" -Encoding UTF8
}
Write-Log "タスク開始"
Write-Log "実行ユーザー: $env:USERDOMAIN\$env:USERNAME"
Write-Log "PSScriptRoot: $PSScriptRoot"
Write-Log "CurrentDirectory: $(Get-Location)"
try {
# ここに実際の処理を書く
Write-Log "処理本体を実行しました"
Write-Log "タスク成功"
}
catch {
Write-Log "エラー発生: $($_.Exception.Message)"
}
finally {
Write-Log "タスク終了"
}
このログで、少なくとも次のことが分かります。
タスクが起動したか
どのユーザーで動いたか
どのフォルダを基準に動いたか
どこでエラーになったか
タスクスケジューラでは、画面を見て確認できないことが多いです。
そのため、ログ出力はほぼ必須です。
追加確認:タスクスケジューラの履歴を見る
タスクスケジューラには履歴機能があります。
対象タスクを選択し、「履歴」タブを確認します。
履歴が無効な場合は、右側メニューから次を選びます。
すべてのタスク履歴を有効にする
履歴では、タスクが開始されたか、終了したか、エラーになったかを確認できます。
ただし、タスクスケジューラの履歴だけでは、PowerShellスクリプト内の詳しいエラーまでは追いにくいです。
そのため、タスクスケジューラの履歴と、スクリプト側のログを両方確認するのがよいです。
確認ポイント一覧
タスクスケジューラでPowerShellが動かないときは、次の順番で確認すると切り分けやすいです。
| No | 確認ポイント | 見る場所 |
|---|---|---|
| 1 | 手動でps1が動くか | PowerShell |
| 2 | タスクと同じコマンドで動くか | PowerShell |
| 3 | ps1を直接指定していないか | 操作タブ |
| 4 | 開始場所が空欄でないか | 操作タブ |
| 5 | パスを引用符で囲んでいるか | 操作タブ |
| 6 | 実行ユーザーが正しいか | 全般タブ |
| 7 | ログオン条件が適切か | 全般タブ |
| 8 | ネットワークドライブを使っていないか | スクリプト内 |
| 9 | 実行ポリシーで止まっていないか | 引数・PowerShell |
| 10 | ログを出しているか | スクリプト内 |
実務でおすすめの切り分け順
個人的には、次の順で確認するのがおすすめです。
1. ps1を手動実行する
2. powershell.exe -File の形で手動実行する
3. タスクの「操作」設定を見る
4. 開始場所を見る
5. ログが出ているか確認する
6. 実行ユーザーと権限を見る
7. 共有フォルダやネットワークドライブを疑う
8. タスクスケジューラの履歴を見る
最初からタスクスケジューラの細かい設定を疑うより、まずは手動実行で問題を切り分ける方が早いです。
まとめ
タスクスケジューラでPowerShellが動かない場合、原因はPowerShellの文法ミスだけではありません。
よくある原因は、次のようなものです。
実行ユーザーが違う
開始場所が違う
相対パスがずれている
共有フォルダにアクセスできない
実行ポリシーで止まっている
ログがないため原因が見えない
まず確認すべき基本形は次の通りです。
プログラムまたはスクリプト:
powershell.exe
引数の追加:
-NoProfile -ExecutionPolicy Bypass -File "C:\work\ps-task-test\task-sample.ps1"
開始場所:
C:\work\ps-task-test
そして、スクリプト側では $PSScriptRoot とログ出力を使うのがおすすめです。
$logPath = Join-Path $PSScriptRoot "task.log"
Add-Content -Path $logPath -Value "タスク開始: $(Get-Date)"
タスクスケジューラでPowerShellを安定して動かすには、手動実行、同一コマンドでの確認、開始場所、実行ユーザー、ログ出力の5つを押さえることが重要です。