私はrobocopyで、PCのDドライブをNASに、Windowsのバックアップを別のドライブにコピーしている。どちらのスクリプトも、robocopyの終了コードが8以上の時だけ「エラーがありました」と表示するようにしている。
robocopyは、ちゃんとコピーできた時でも0以外の終了コードを返す。普通のコマンドと同じつもりで「0以外ならエラー」と判定すると、成功しているのにエラー扱いになってしまう。
結論から書くと、robocopyの終了コードは8未満なら成功(コピーに失敗したファイルは無い)、8以上なら失敗がある。Microsoftのドキュメントにも「8以上の値は、コピー操作中に少なくとも1つの障害が発生したことを示します」と書かれている。
robocopyの終了コード一覧
robocopyの終了コードは、次の5つの値の足し算になっている。たとえば3は「1(コピーした)+2(コピー先に余分なファイルがある)」だ。
| 値 | 意味 | 判定 |
|---|---|---|
| 0 | コピーするものが無かった。コピー元とコピー先がすでに同じ状態 | 成功 |
| 1 | 1つ以上のファイルをコピーした | 成功 |
| 2 | コピー先に、コピー元に無いファイルやフォルダ(Extras)がある | 成功 |
| 4 | 不一致(Mismatch)のファイルやフォルダがある。同じ名前でコピー元はファイル、コピー先はフォルダ、など | 成功(要確認) |
| 8 | コピーできなかったファイルやフォルダがある(再試行の回数を超えた) | 失敗 |
| 16 | 重大なエラー。1つもコピーしていない。オプションの書き間違いや、コピー元・コピー先にアクセスできない時 | 失敗 |
Microsoftのrobocopy - Microsoft LearnとRobocopy ユーティリティで使用されるリターン コード - Microsoft Learnには、0〜8の組み合わせの説明と「8以上は失敗」が載っている。4と16の個別の意味は、Microsoftの技術者のブログ記事Robocopy exit codes - Microsoft Learn(アーカイブ)を参考にした。
組み合わせで出てくる値の意味は、次のとおり。
| 値 | 内訳 | 意味 |
|---|---|---|
| 3 | 1+2 | コピーした。コピー先に余分なファイルもある |
| 5 | 1+4 | コピーした。不一致のファイルもある |
| 6 | 2+4 | 余分なファイルと不一致のファイルがある。コピーはしていない |
| 7 | 1+2+4 | コピーした。余分なファイルと不一致のファイルもある |
| 9〜15 | 8+α | コピーできたファイルもあるが、失敗したファイルもある |
/MIRや/PURGEを付けている時は、コピー先の余分なファイルは削除される。それでも、削除した分は2として数えられる(下の実験の7番)。
実際に終了コードを出してみた
本当にこの値が返るのか、私のPC(Windows 11 Pro)で、テスト用のフォルダを使って1つずつ試した。/R:0 /W:0(再試行しない)を付けて実行し、PowerShellの$LASTEXITCODEで終了コードを見た。
| やったこと | 終了コード |
|---|---|
| 新しいファイルを2つコピー | 1 |
| もう一度実行(変化なし) | 0 |
| コピー先にだけファイルを置いて実行 | 2 |
| 新しいファイルを1つ追加+コピー先にだけファイルがある | 3 |
| コピー元のファイルと同じ名前のフォルダをコピー先に作って実行(不一致) | 4 |
| コピー先のファイルを別のプロセスで開いたまま、更新したファイルをコピー | 8 |
/MIRで、コピー先にだけあるファイルを削除 |
2 |
| 存在しないフォルダをコピー元にした | 16 |
存在しないオプション(/XYZ)を付けた |
16 |
ファイルを開いたままにした時(終了コード8)の出力は次のとおり(パスは短くした)。集計のFAILED(日本語のログでは「失敗」)の列が1になっている。
Newer 13 a.txt
2026/11/08 19:41:21 ERROR 32 (0x00000020) Copying File D:\test\src\a.txt
The process cannot access the file because it is being used by another process.
------------------------------------------------------------------------------
Total Copied Skipped Mismatch FAILED Extras
Dirs : 1 0 1 0 0 0
Files : 4 0 3 0 1 0
コピー元が無い時はERROR 2 (0x00000002) Accessing Source Directory、オプションを書き間違えた時はERROR : Invalid Parameter #3 : "/XYZ"と出て、どちらも1つもコピーせずに16で終わった。NASやドライブが見えなくてコピー元・コピー先にアクセスできない時も16になるはずだが、それは試していない。
バッチファイルで8以上を判定する
バッチファイルではif errorlevel 8で判定する。Microsoftのif - Microsoft Learnにあるとおり、errorlevel 8は「終了コードが8以上」の時に真になる。8ちょうどではないので、9や16もここに入る。
@echo off robocopy "D:\data" "E:\backup\data" /MIR /R:3 /W:3 /log+:"E:\backup\robocopy.log" /np if errorlevel 8 ( echo コピーに失敗したファイルがあります。ログを確認してください。 exit /b 1 ) echo 完了しました。 exit /b 0
同じことは%errorlevel%を使って次のようにも書ける。GEQは「以上」の比較だ。
if %errorlevel% GEQ 8 echo コピーに失敗したファイルがあります。
注意点が2つある。
if errorlevelは「その直前に実行したプログラム」の終了コードを見る。robocopyとifの間にechoなどを挟まず、robocopyの直後に判定する( )の中で%errorlevel%を使うと、ブロックに入る前の値に展開されてしまう。( )の中でrobocopyを実行して判定する時はif errorlevel 8の方を使う(robocopyでコピー先フォルダが非表示になる原因と直し方のバッチがこの形)
PowerShellで8以上を判定する
PowerShellでは、外部のプログラムの終了コードは$LASTEXITCODEに入る(about_Automatic_Variables - Microsoft Learn)。robocopyの直後に変数に取っておき、-ge 8で判定する。
robocopy "D:\data" "E:\backup\data" /MIR /R:3 /W:3 /log+:"E:\backup\robocopy.log" /np
$rc = $LASTEXITCODE
if ($rc -ge 8) {
Write-Host "コピーに失敗したファイルがあります(終了コード $rc)。ログを確認してください。" -ForegroundColor Red
exit 1
}
Write-Host "完了しました(終了コード $rc)。" -ForegroundColor Green
exit 0
$?は使わない方がよい。$?は外部のプログラムの終了コードが0以外だとFalseになるので、ファイルをコピーできた時(終了コード1)でも「失敗」と判定されてしまう。
私がNASへのバックアップに使っているスクリプトも、この形で判定している(RobocopyでローカルフォルダのデータをID/パスワード付きのNASにバックアップする)。
タスクスケジューラで「失敗」と表示させないために
タスクスケジューラやジョブ管理ツールでrobocopyを動かすと、終了コード1(コピーした)でも「前回の実行結果」が(0x1)になり、失敗したように見える。上のバッチ・PowerShellの例のように、最後にexit /b 0・exit 0(8未満の時)とexit /b 1・exit 1(8以上の時)を返すようにしておくと、本当に失敗した時だけ0以外になる。
8以上になったら、ログの「失敗」を見る
終了コードは「失敗があった」ことしか分からない。どのファイルで失敗したかは、/log+:で残したログを見る。ログの最後の集計の「失敗」(英語の表示ではFAILED)の列が0でなければ、ログの中に「エラー」(ERROR)と書かれた行があり、ファイル名と理由(アクセスが拒否された、別のプロセスが使用中、など)が書かれている。
失敗の原因として、私が実際に当たったものは次の2つ。
/COPYALLでNASにコピーした時の「エラー 1314 (0x00000522) ... クライアントは要求された特権を保有していません。」(NASへのバックアップの記事に書いた)- 管理者として実行しなかった時の「エラー: 監査管理のユーザー権利がありません。」(コピー先フォルダが非表示になる記事に書いた)


コメント