夜間バッチは、失敗したときだけ急に存在感を出します。
前日の退勤前に手で実行したら動いた。ところが翌朝、タスクスケジューラの前回の実行結果だけが0x1になっていて、CSVは出ていない。利用部門からは「朝の取込ができません」と連絡が来る。
このとき、設定画面を上から順に眺めてもなかなか進みません。先に分けるべきなのは、バッチそのものの失敗なのか、タスクスケジューラで動かしたときの環境差なのかです。手動実行、履歴、操作タブ、実行ユーザー、ログ、終了コードの順に見ると、原因候補をかなり絞れます。
この記事では、業務システムのCSV出力バッチを例にします。夜間に売上データを出力し、別システムが朝に取り込む想定です。手で実行すると動くのに、タスクスケジューラから実行すると失敗する、という保守でよくある場面を追います。
まず手動実行とタスク実行を分けて考える
ダブルクリックで動くことは成功条件の一部でしかない
バッチをダブルクリックして動いた場合、少なくともbatファイルの文法や処理の大枠は通っています。これは大事な確認です。ただし、それだけでタスクスケジューラでも動くとは言えません。
手動実行では、ログイン中のユーザー、現在の作業フォルダ、割り当て済みのネットワークドライブ、画面に出るエラー表示を使えます。タスク実行では、これらが変わります。特に相対パスでファイルを読んでいるバッチは、ここで崩れやすいです。
たとえば、次のようなバッチがあるとします。
@echo off
copy input\sales.csv \\fileserver\share\sales.csv作業フォルダがbatファイルの場所なら動きます。しかしタスクスケジューラで開始フォルダを空にしたままだと、input\sales.csvがどこを指すかが変わります。昨日は手動で動いたのに夜間だけ失敗する、という話になりがちです。
tomo「手で動きました」は悪い報告ではありません。そこから、手動とタスク実行で何が違うかを一つずつ外していくのが早いです。
タスクスケジューラでは実行ユーザーと作業フォルダが変わる
タスクスケジューラは、登録されたアカウントと設定に従ってプログラムを起動します。普段ログインしている自分の環境とは別物として見た方が安全です。
最初にメモするのは、次の4つです。
タスク名: ExportSalesCsv
実行ユーザー: DOMAIN\batch_user
プログラム: C:\batch\export_sales.bat
開始フォルダ: C:\batch
前回の実行結果: 0x1この4つが分かると、後の確認がかなり楽になります。逆に、前回の実行結果だけを見て原因を決めると外します。0x1は原因名ではなく、バッチや呼び出したコマンドが正常終了しなかった結果として扱います。
タスクの履歴と前回の実行結果を見る
履歴が無効なら先に有効化する
タスクスケジューラを開いたら、まず該当タスクの「前回の実行時刻」と「前回の実行結果」を見ます。履歴が無効になっている環境では、右側の操作から履歴を有効化します。
履歴を有効化しても、過去にさかのぼって詳細が出るわけではありません。次回実行からの記録になります。だから、失敗した直後に何度も設定を変えて実行する前に、いま見えている情報をメモしておきます。
2026-08-03 06:00
ExportSalesCsv
前回の実行結果: 0x1
出力ファイル: \\fileserver\share\sales.csv は更新なし
アプリログ: なしこの程度でも、後で効きます。保守でつらいのは、原因が分からないことそのものより、朝のばたばたで「最初どうなっていたか」が消えることです。
0x1だけで原因を決めつけない
0x1はよく見ます。だからこそ雑に扱われます。「開始フォルダでし」と決め打ちしたくなりますが、実行ユーザーの権限、ファイルパス、ネットワーク共有、bat内の最後のコマンドの終了コードでも出ます。
たとえば、削除対象がなかっただけで、最後に実行したコマンドが1を返すことがあります。業務上は問題ないのに、タスクスケジューラ上は異常終了に見えるケースです。
0x1を見たら、原因を決める前に「どのコマンドが何を返したか」をログで確認します。 タスクスケジューラの画面だけでは、batの中でどこまで進んだかまでは分かりません。
操作タブのパスと開始フォルダを確認する
プログラムと引数を分けて指定する
操作タブでは、「プログラム/スクリプト」「引数の追加」「開始」を分けて確認します。
batファイルを直接指定しても動くことはありますが、調査しやすさを優先するなら、cmd.exeを使って呼び出しを明示する形にします。
プログラム/スクリプト:
C:\Windows\System32\cmd.exe
引数の追加:
/c "C:\batch\export_sales.bat"
開始:
C:\batchこの形なら、何を起動し、どのbatを実行し、どのフォルダを基準にするかが分かれます。設定を見直す人にも伝わりやすいです。
開始フォルダが空だと相対パスで失敗しやすい
開始フォルダは地味ですが、かなり効きます。bat内でinput\sales.csvやlogs\export.logのような相対パスを使っているなら、開始フォルダを空にしない方がよいです。
NG例です。
プログラム/スクリプト:
C:\batch\export_sales.bat
引数の追加:
開始:
bat内:
copy input\sales.csv \\fileserver\share\sales.csv修正版です。
プログラム/スクリプト:
C:\Windows\System32\cmd.exe
引数の追加:
/c "C:\batch\export_sales.bat"
開始:
C:\batch
bat内:
copy input\sales.csv \\fileserver\share\sales.csvさらに確実にするなら、bat内でも自分の場所へ移動します。
@echo off
cd /d "%~dp0"
copy "input\sales.csv" "\\fileserver\share\sales.csv"
exit /b %ERRORLEVEL%%~dp0は、実行中のbatファイルが置かれているフォルダです。タスクの開始フォルダを明示しつつ、bat側でも基準フォルダを固定しておくと、後から別の人が手動実行したときも挙動が揃います。
設定画面だけに頼らず、bat側でもcd /d "%~dp0"を入れておくと、作業フォルダのズレに強くなります。保守では、この一行で翌朝の調査時間がかなり変わることがあります。
実行ユーザーと権限を確認する
手動実行したユーザーとタスクの実行ユーザーを合わせる
手動では自分のアカウントで実行し、タスクではDOMAIN\batch_userで実行している。これはよくあります。この場合、自分で実行して成功しても、バッチ用ユーザーで成功するとは限りません。
確認では、タスクに設定されている実行ユーザーで同じコマンドを実行します。ログインできない運用なら、管理者に依頼して一時的に確認するか、タスクからwhoamiをログに出します。
@echo off
cd /d "%~dp0"
echo [%date% %time%] user=%USERNAME% >> logs\export_sales.log
whoami >> logs\export_sales.log
copy "input\sales.csv" "\\fileserver\share\sales.csv" >> logs\export_sales.log 2>&1
exit /b %ERRORLEVEL%これで、実際にどのユーザーとして動いたかが残ります。思っていたユーザーと違う場合、権限の話をする前に設定を直します。
共有フォルダやネットワークドライブは特に疑う
タスクスケジューラで失敗するバッチは、共有フォルダが絡むと一段ややこしくなります。手動実行時にZ:ドライブを割り当てていても、タスク実行ユーザーにはその割り当てがないことがあります。
できるだけUNCパスで書きます。
避けたい指定:
Z:\sales\sales.csv
使いたい指定:
\\fileserver\share\sales\sales.csvただし、UNCパスにしただけで解決するとは限りません。タスクの実行ユーザーに、共有フォルダとNTFSの両方の権限が必要です。ファイルサーバー側のログも確認できるなら、アクセス拒否が出ていないか見ます。
本番の連携先に対して、原因不明のまま何度も再実行しないよう注意しましょう。 コピー、削除、送信、取込のバッチは、二重実行でファイルを上書きしたり、同じデータを複数回送ったりすることがあります。
バッチ側でログと終了コードを残す
標準出力と標準エラーをファイルに出す
タスクスケジューラの履歴だけでは、batの中で何が起きたか分かりません。最初からログを残します。最低限、開始時刻、実行ユーザー、処理したファイル、コマンド結果、終了コードを残します。
@echo off
setlocal
cd /d "%~dp0"
if not exist logs mkdir logs
set LOG=logs\export_sales.log
echo -------------------------------------------------- >> "%LOG%"
echo [%date% %time%] start export_sales >> "%LOG%"
whoami >> "%LOG%"
copy "input\sales.csv" "\\fileserver\share\sales.csv" >> "%LOG%" 2>&1
set RESULT=%ERRORLEVEL%
echo [%date% %time%] result=%RESULT% >> "%LOG%"
exit /b %RESULT%>> "%LOG%" 2>&1で、標準出力と標準エラーを同じログへ出します。エラーメッセージが画面に一瞬だけ出て消える、という状態を避けるためです。
現場でよく困るのは、夜間に失敗したバッチのログが何も残っていない状態です。タスクの結果は0x1。出力ファイルはない。batを手で動かすと成功する。こうなると、失敗時の環境を再現するしかありません。ログが一行でもあれば、そこから戻れます。
exit /bで終了コードを明示する
batファイルの終了コードは、最後に実行したコマンドの影響を受けます。業務上は問題ないケースでも、最後のコマンドが1を返して、タスクスケジューラ上は失敗に見えることがあります。
処理結果をタスクスケジューラへ正しく返したいなら、最後にexit /bで明示します。
copy "input\sales.csv" "\\fileserver\share\sales.csv" >> "%LOG%" 2>&1
set RESULT=%ERRORLEVEL%
if not "%RESULT%"=="0" (
echo copy failed. errorlevel=%RESULT% >> "%LOG%"
exit /b %RESULT%
)
echo copy completed. >> "%LOG%"
exit /b 0ここで大事なのは、何でもexit /b 0にして成功扱いにしないことです。失敗しているのに正常終了へ丸めると、朝の確認では成功に見えます。正常扱いにしてよい条件を決めてから、終了コードを制御します。



「対象ファイルがない日は正常」なら、その条件をbat内で判定して0を返します。何が正常で何が異常かを、タスクスケジューラ任せにしない方が後で説明しやすいです。



最初から完璧なバッチに直せなくても大丈夫です。まずログと終了コードだけ整えると、次に失敗したときの見え方が変わります。
再実行する前に確認すること
二重実行で壊れる処理かを見る
タスクを右クリックして「実行」を押す前に、そのバッチが二重実行に耐えられるかを見ます。CSV出力だけなら上書きで済む場合もあります。けれど、送信、削除、DB更新、処理済みフラグ更新が入ると話が変わります。
再実行前の確認メモは、このくらいで十分です。
処理内容: 売上CSVを作成し、共有フォルダへコピーする
DB更新: なし
送信処理: なし
削除処理: なし
出力先: \\fileserver\share\sales.csv
再実行前の退避: 既存sales.csvをsales_20260803_0830.csvへコピー削除や送信があるなら、処理済みデータの範囲、送信先の受信状況、前回途中まで進んだ場所を先に確認します。ここを飛ばすと、原因調査のつもりで業務データをさらに汚すことがあります。
出力ファイルと途中データを退避する
再実行する前に、出力ファイル、ログ、一時フォルダを退避します。上書きされると、最初の失敗時に何が残っていたかが分からなくなります。
Copy-Item "\\fileserver\share\sales.csv" "\\fileserver\share\backup\sales_20260803_0830.csv"
Copy-Item "C:\batch\logs\export_sales.log" "C:\batch\logs\export_sales_20260803_0830.log"ファイルが存在しない場合も、その事実をメモします。「なかった」と分かるだけでも、コピー前に失敗したのか、コピー後に消されたのかを考える材料になります。
復旧を急ぐときほど、最初の状態を残します。ログ、出力ファイル、一時ファイル、前回実行結果を残してから再実行すると、あとで原因を説明できます。
まとめ
タスクスケジューラでバッチが動かないときは、設定項目を一気に直そうとせず、順番を決めて見ます。
0x1だけで原因を決めず、前回の実行時刻、履歴、出力ファイル、ログの有無を先に残す- 操作タブでは、
cmd.exe、batファイルのパス、開始フォルダを分けて確認し、相対パスのズレを潰す - タスクの実行ユーザーで共有フォルダへアクセスできるか確認し、ネットワークドライブではなくUNCパスで指定する
- bat側では、
whoami、標準出力、標準エラー、ERRORLEVEL、exit /bをログに残す - 再実行前に、送信、削除、DB更新、処理済みフラグ更新がないかを見て、必要なら出力ファイルとログを退避する
この順番で見れば、手動では動くのにタスクだけ失敗するバッチを、作業フォルダ、権限、パス、終了コードのどこで詰まっているかへ寄せられます。次に直すべきなのは、タスクスケジューラの設定だけではありません。bat側に追跡できるログを入れ、次の失敗時に「どこまで進んだか」を残せる状態にすることです。


