WindowsでPythonがタスクスケジューラからだけ失敗する原因と切り分け|作業フォルダ・PATH・権限を確認する

スケジューラ実行時の作業フォルダと実行結果の切り分けフロー図

WindowsでPythonがタスクスケジューラからだけ失敗する原因と切り分け|作業フォルダ・PATH・権限を確認する

手動でPowerShellから実行すると成功するPythonスクリプトが、Windowsのタスクスケジューラ経由では失敗することがあります。この場合、まず「Pythonの処理内容」だけを疑うのではなく、手動実行とスケジュール実行で何が変わっているかを分けて確認します。

主に確認するのは、実際に起動されたPython、PATH、作業フォルダ、相対パス、実行ユーザーと権限、そして標準出力・標準エラーです。以下は、環境固有の値を決めつけずに切り分ける順序です。

目次

まず症状を固定する

次の2通りを同じスクリプトで比較します。

  1. いつものPowerShellから実行する。
  2. タスクスケジューラから同じスクリプトを実行する。

「Schedulerから失敗した」という結果だけでは、Python本体、import、ファイルの場所、権限、ネットワーク、終了コードのどれが原因かは分かりません。スクリプトの開始直後に、実行時情報と例外を記録できる状態を作ってから比較します。

1. 実際に選ばれたPythonを確認する

python という文字列は、常に同じ実行ファイルを意味するとは限りません。PowerShellのコマンド探索結果と、WindowsのPATH上の候補を別々に確認します。

Get-Command python
Get-Command python -All
where.exe python

Get-Command はPowerShellから利用できるコマンドの情報を返し、-All で同名候補も確認できます。where.exe は指定した名前に一致するファイルの場所を表示します。候補が複数あれば、先頭の表示だけで判断せず、タスクで意図したPythonが含まれているかを確認します。

次に、起動中のPython自身へ実行ファイルを表示させます。

python -c "import sys; print(sys.executable)"
python -c "import sys; print(sys.executable); print(sys.prefix != sys.base_prefix)"

sys.executable は、実行中のPythonインタープリターの絶対パスです。venvの判定は補助的に sys.prefix != sys.base_prefix を使えますが、最終確認では実際の sys.executable のパスを基準にします。

venvを使う場合は、activate済みかどうかに依存せず、対象環境のPythonを直接指定して比較します。

& 'C:\path\to\project\.venv\Scripts\python.exe' --version
& 'C:\path\to\project\.venv\Scripts\python.exe' -c "import sys; print(sys.executable)"

上の C:\path\to\project は説明用の例です。実際の環境では、対象プロジェクトに存在するvenvのパスへ置き換えてください。

2. pythonとpipの組み合わせを揃える

ModuleNotFoundError が出ても、すぐに「パッケージが未インストール」とは判断しません。別のPythonへインストールしていた可能性があるため、同じインタープリターからpipを呼び出します。

python -c "import sys; print(sys.executable)"
python -m pip --version
python -m pip show <package-name>

対象venvを直接指定する場合も同じです。

& 'C:\path\to\project\.venv\Scripts\python.exe' -m pip --version
& 'C:\path\to\project\.venv\Scripts\python.exe' -m pip show <package-name>

手動実行とScheduler実行の両方で、sys.executable と python -m pip --version の結果を保存して比較します。パッケージの有無を比較する前に、Python本体が同じかを確定させるのがポイントです。

3. Task Schedulerの3つの入力を分ける

タスクスケジューラのアクションでは、次の項目を混ぜないようにします。

Program/script

可能なら python という名前ではなく、対象Pythonの実行ファイルをフルパスで指定します。

Program/script:
C:\path\to\project\.venv\Scripts\python.exe

これは説明用のパスです。実在する環境固有パスとして記事からコピーして断定しないでください。MicrosoftのTask SchedulerはExec Actionとして実行するコマンドを持ち、schtasks でも実行対象には完全修飾パスを指定できます。

Add arguments

Pythonの引数にはスクリプトのパスを渡します。空白を含むパスは引用符で囲みます。

Add arguments:
"C:\path\to\project\scripts\job.py" --mode scheduled

引数欄へPython実行ファイルまで重ねて書くと、Program/scriptとの責任範囲が分かりにくくなります。まずは実行ファイルとスクリプトを分離した最小構成で動作を確認します。

Start in

相対パスを使うスクリプトでは、作業フォルダを明示します。

Start in:
C:\path\to\project

Task SchedulerのExec ActionにはWorkingDirectoryがあり、実行ファイルや実行対象が使うファイルのディレクトリを指定します。Start in を空欄または誤った場所にすると、.\config.json や logs\job.log のような相対パスが、手動実行時と異なる場所を参照することがあります。

4. 相対パスを絶対パスと比較する

スクリプトの冒頭で、実行時のカレントディレクトリを記録します。

from pathlib import Path
import sys

print("executable:", sys.executable)
print("cwd:", Path.cwd())
print("script_dir:", Path(__file__).resolve().parent)

Path.cwd() と Path(__file__).resolve().parent は同じとは限りません。設定ファイルや出力先を相対パスで組み立てているなら、どちらを基準にする設計なのかを明確にします。Schedulerで再現するための一時診断では、入力・出力・ログを絶対パスにして、作業フォルダ問題と処理問題を分離します。

5. PATHと環境変数の差を確認する

対話シェルとSchedulerでは、起動元、ログオン状態、ユーザー、環境変数が同一とは限りません。Pythonから必要な値だけを安全に記録します。

import os
import sys

print("executable:", sys.executable)
print("PATH:", os.environ.get("PATH", ""))
print("VIRTUAL_ENV:", os.environ.get("VIRTUAL_ENV", ""))

環境変数を全部ログへ出すのではなく、診断に必要な名前だけを選びます。トークン、パスワード、接続文字列などを環境変数から取得する処理がある場合、その値自体はログに出しません。

Pythonのコマンドラインと環境変数は、インタープリターの動作に影響します。Scheduler実行で必要な環境変数が見えない場合は、実行ユーザー、タスクの設定、サービスや資格情報の設計を確認します。環境変数を推測で追加して解決したことにしないでください。

6. 実行ユーザーと権限を比較する

タスクスケジューラでは、手動実行したPowerShellのユーザーと、タスクが実行するユーザーが異なる場合があります。Microsoftの schtasks 仕様でも、/ru によってタスクを実行するユーザーやセキュリティコンテキストを指定できます。

次を比較します。

  • タスクの「ユーザーまたはグループ」
  • 「ユーザーがログオンしているかどうかにかかわらず実行する」の設定
  • 対象フォルダ・ファイルへの読み書き権限
  • ネットワーク共有やドライブ文字への依存
  • 必要な資格情報が、その実行コンテキストから利用できるか

権限不足を疑うときは、いきなり管理者権限へ変更せず、まず失敗したファイル操作の対象とエラーをログで特定します。ドライブ文字やユーザー固有のプロファイルに依存している場合は、同じユーザーでの絶対パス検証も行います。

7. stdout / stderrを残す

タスクスケジューラの画面を見られない場合、終了コードだけでは原因を特定できません。アプリケーション側でログファイルを設定し、標準出力・標準エラーも必要な期間だけファイルへ残します。

Python側の最小例です。

from pathlib import Path
import logging
import sys

log_path = Path(r"C:\path\to\logs\job.log")
log_path.parent.mkdir(parents=True, exist_ok=True)
logging.basicConfig(filename=log_path, level=logging.INFO, encoding="utf-8")
logging.info("executable=%s", sys.executable)
logging.info("cwd=%s", Path.cwd())

C:\path\to\logs\job.log は説明用の例です。実際の保存先へ置き換え、実行ユーザーが書き込めるかを確認します。ラッパーを使う場合は、コマンドプロンプトのリダイレクトを使えます。

"C:\path\to\project\.venv\Scripts\python.exe" "C:\path\to\project\scripts\job.py" 1>>"C:\path\to\logs\stdout.log" 2>>"C:\path\to\logs\stderr.log"

ログに秘密情報や環境変数の全量を出さないこと、ログフォルダ自体の権限を確認することが重要です。

8. 切り分けの順序

次の順番なら、原因の候補を一つずつ狭められます。

  1. Schedulerを介さず、Program/scriptとAdd argumentsの組み合わせをPowerShellからフルパスで実行する。
  2. Get-Command python、where.exe python、sys.executable を記録する。
  3. 同じPythonで python -m pip --version と必要パッケージを確認する。
  4. Task SchedulerのProgram/script、Add arguments、Start inを確認する。
  5. Path.cwd()、__file__、入力・出力・ログの実パスを記録する。
  6. タスクの実行ユーザーと対象ファイルの権限を比較する。
  7. stdout / stderr とアプリケーションログで最初の例外を確認する。
  8. 修正後は同じ条件で再実行し、終了コードとログを保存する。

よくある誤判定

「venvをactivateしたから大丈夫」

activateの表示だけでは、Schedulerが同じセッションを使うとは確認できません。sys.executable を手動とSchedulerの両方で比較します。Python公式ドキュメントにも、venvをactivateせずフルパスのインタープリターを指定して実行できるとあります。

「pipでインストール済みだから大丈夫」

pip 単体の場所ではなく、同じPythonから python -m pip を呼び出して確認します。異なるPythonへインストールしていた場合、手動とSchedulerで結果が分かれます。

「権限を管理者にすれば解決する」

管理者権限への変更は原因の特定ではありません。まず、どのパスでどの操作が拒否されたか、実行ユーザーは誰か、ログに何が出たかを確認します。

「Start inは空でも同じ」

相対パスを使う処理では、作業フォルダが違えば参照先も変わります。Path.cwd() をログに出し、絶対パスで一時検証してから設計を見直します。

「終了コード0なら成功」

終了コードは一つの信号に過ぎません。期待する出力、ログ、更新時刻、処理件数など、業務上の完了条件も確認します。

最終チェックリスト

  • [ ] Get-Command python と Get-Command python -All を確認した
  • [ ] where.exe python の候補を確認した
  • [ ] python -c "import sys; print(sys.executable)" を手動とSchedulerで比較した
  • [ ] Program/script に意図したPythonのフルパスを指定した
  • [ ] Add arguments のスクリプトパスと引用符を確認した
  • [ ] Start in / WorkingDirectory を確認した
  • [ ] 相対パスの基準を Path.cwd() と __file__ で確認した
  • [ ] PATHなど必要な環境差を比較した
  • [ ] 実行ユーザーとファイル権限を確認した
  • [ ] stdout / stderr とアプリケーションログを保存した
  • [ ] 修正後の終了コードだけでなく、期待する成果物も確認した

公式資料

筆者の環境で実際に確認した結果

確認日:2026年10月14日/環境:Windows 11 Home(ビルド26300)、Windows PowerShell 5.1、Python 3.14

同じPythonスクリプト(作業フォルダ・実行中のpython.exe・相対パスで settings.txt を開けるか・PATHの中身を記録するだけのもの)を、PowerShellから実行した場合と、タスクスケジューラに一時的に登録して実行した場合で比べました。python.exe はどれもフルパス(...\Python314\python.exe)で指定しています。

実行のしかた 作業フォルダ(os.getcwd()) 相対パスのファイル読み込み PATHにPythonのフォルダ
PowerShellからスクリプトのフォルダで実行 スクリプトのフォルダ 成功 あり
タスクスケジューラ(「開始(オプション)」が空) C:\WINDOWS\system32 FileNotFoundError なし
タスクスケジューラ(「開始(オプション)」にスクリプトのフォルダ) スクリプトのフォルダ 成功 なし

手動では動くのにタスクからだけ失敗する、という状態をそのまま再現できました。原因は作業フォルダの違いで、「開始(オプション)」にスクリプトのフォルダを入れただけで同じスクリプトが成功しています。ログを見るときは、まず os.getcwd() を1行出力しておくと切り分けが早くなります。

RIN WORK LABのツール:RIN Tools|AIエージェントの事故を減らす 個人開発テンプレ集[Claude Code編]

AIエージェントに作業を任せる前に、変更範囲・禁止事項・完了条件を整理するための指示書テンプレート集です。まずは無料サンプル(5ページPDF+指示書サンプル)で形式を確認できます。

※当サイトの運営者(RIN WORK LAB)がBOOTHで販売している商品です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次