【PowerShell】robocopyでフォルダを同期・バックアップする方法|/MIR・/L・終了コード

【PowerShell】robocopyでフォルダを同期・バックアップする方法|/MIR・/L・終了コード PowerShell

フォルダをまるごとバックアップしたり、2つのフォルダの内容をそろえたり(同期)する作業は、Windows標準のrobocopy(Robust File Copy)が得意とするところです。PowerShellからそのまま呼び出せて、大量のファイルでも高速かつ確実にコピーできます。差分だけのコピーや、コピー先の不要ファイル削除(ミラーリング)にも対応しています。

ただし、いくつか独特な注意点があります。/MIR(ミラー)はコピー先にしかないファイルを削除すること、そしてrobocopyの終了コードは0〜7までが成功で、一般的なコマンドのように「0以外=エラー」と判定するとうまくいかないことです。この記事では、実機のPowerShell 5.1でrobocopyを確認しながら、フォルダの同期・バックアップを整理します。

先に結論

  • 基本はrobocopy コピー元 コピー先 /E(サブフォルダも含めてコピー)。
  • 実行前に/Lを付けてドライラン(コピーせず対象だけ表示)で確認します。
  • 同期(ミラー)は/MIRコピー先の余分なファイルは削除されるので注意します。
  • 終了コードは0〜7が成功1は「コピーした」という意味で、エラーではありません。
  • スクリプトでの成否判定はif ($LASTEXITCODE -ge 8)でエラーとします。
  • Windowsに標準搭載。追加インストールは不要です。

コピー対象の確認はファイル・フォルダ操作(Test-Path・Get-ChildItem)、古いファイルの整理は更新日で古いファイルを削除・移動する、エラー処理はtry-catchでのエラー処理もあわせて参考になります。重複ファイルの検出と組み合わせると、フォルダ管理がより快適になります。

スポンサーリンク

robocopyとは(Copy-Itemとの違い)

robocopyはWindowsに標準で入っているコマンドです。PowerShellのCopy-Itemでもコピーはできますが、robocopy差分コピー(変更があったファイルだけ)・ミラーリング・再試行・ログ出力などに対応し、バックアップ用途では圧倒的に高機能です。大量ファイルや定期バックアップにはrobocopyが向いています。

基本のコピー(/E)

もっとも基本的な使い方は、robocopy コピー元 コピー先です。サブフォルダも含めてコピーするには/Eを付けます。

基本のコピー
# サブフォルダも含めてコピー(空のフォルダも作る)
robocopy "C:\data" "D:\backup\data" /E

# /E … サブフォルダを含む(空フォルダも作成)
# /S … サブフォルダを含む(空フォルダは作らない)

# 2回目以降は、変更があったファイルだけが自動でコピーされる(差分コピー)

実機でも、/Eを付けて実行するとサブフォルダの中身まで含めてコピーされました。robocopyの大きな利点は差分コピーです。同じコマンドを2回目に実行すると、前回から変更されていないファイルはスキップされ、変更・追加されたものだけがコピーされます。そのため、定期バックアップでも毎回すべてをコピーし直す無駄がありません。

【安全第一】/L でドライラン

robocopy、とくに後述の/MIRは、設定を間違えるとファイルを削除してしまうことがあります。実行前には必ず/L(list only)でドライランし、「実際には何もせず、対象だけを表示」して確認しましょう。

/L でドライラン(実行せず確認)
# /L … 実際にはコピー・削除せず、対象の一覧だけ表示する
robocopy "C:\data" "D:\backup\data" /E /L

# 表示内容に問題がないことを確認してから、/L を外して本実行
robocopy "C:\data" "D:\backup\data" /E
/L は robocopy の安全装置

実機で確認したところ、/Lを付けて実行すると、コピー対象として新規ファイルが表示されても実際にはコピーされませんでした(コピー先にファイルが作られないことを確認)。Remove-Item-WhatIfと同じ役割で、「これから何が起きるか」を消さずに確認できます。とくに/MIRを使う前には、/L削除される予定のファイルが無いかを必ず確認してください。これを習慣にするだけで、大事故をほぼ防げます。

同期・ミラーリング /MIR(削除に注意)

2つのフォルダを完全に同じ状態にする(ミラーリングする)には/MIRを使います。コピー元に合わせて、コピー先にしかないファイル・フォルダは削除されます。バックアップを常に最新の鏡像に保ちたいときに使います。

/MIR でミラーリング
# コピー元とコピー先を完全に同じ状態にする
robocopy "C:\data" "D:\backup\data" /MIR

# /MIR は /E(サブフォルダ含む)+ /PURGE(コピー先の余分を削除)と同じ
# → コピー先にしかないファイルは削除される!
/MIR はコピー先のファイルを削除する

実機で確認したところ、コピー先だけに置いたextra_only.txtは、/MIRを実行すると削除されました/MIRは「コピー元の完全な鏡像」を作るため、コピー元に無いものはコピー先からも消します。コピー先(バックアップ先)を間違えて指定すると、そのフォルダの中身が大量に消える事故につながります。とくに、コピー先に大切なファイルが入っている場合は要注意です。/MIRを使うときは、必ず先に/Lでドライランし、削除対象(出力では*EXTRAなどと表示)に消したくないファイルが含まれていないかを確認してから本実行してください。

【最重要】終了コードは0〜7が成功

robocopyでもっとも誤解されやすいのが終了コードです。多くのコマンドは「0=成功、0以外=エラー」ですが、robocopy0〜7までが正常終了で、8以上がエラーです。$LASTEXITCODEで判定するときは、この点に注意します。

終了コードの正しい判定
robocopy "C:\data" "D:\backup\data" /E

# robocopy の終了コード:
#   0 … コピー対象なし(変更なし。すでに同期済み)
#   1 … ファイルをコピーした(成功)
#   2 … コピー先に余分なファイルあり
#   3 … コピー + 余分あり
#   5,6,7 … 上記の組み合わせ(いずれも成功)
#   8以上 … 失敗(コピーできなかったファイルがある等)

# 正しい成否判定(8以上をエラーとする)
if ($LASTEXITCODE -ge 8) {
    Write-Host "エラーが発生しました(コード: $LASTEXITCODE)"
} else {
    Write-Host "正常終了しました(コード: $LASTEXITCODE)"
}
終了コード1はエラーではない

実機で確認したところ、変更がない状態での再実行では終了コード0(コピー対象なし)、ファイルを1つ追加してから実行すると1(コピーした)、/MIRでコピー先の余分を削除したときは3になりました。いずれも正常終了です。$LASTEXITCODEが0以外だからエラー」と判定すると、コピーが成功しているのに失敗扱いになってしまいます。これはバッチやスクリプトでrobocopyを使うときの定番のハマりどころです。成否を判定するならif ($LASTEXITCODE -ge 8)のように、8以上をエラーとして扱ってください。

よく使うオプション

robocopyのよく使うオプションをまとめます。組み合わせて使います。

オプション 働き
/E サブフォルダを含む(空フォルダも作る)
/S サブフォルダを含む(空フォルダは除く)
/MIR ミラーリング(コピー先の余分を削除)
/L ドライラン(実行せず対象表示)
/XO コピー先より古いファイルは除外
/XD / /XF 指定フォルダ / ファイルを除外
/R:n /W:n 失敗時の再試行回数 / 待機秒数
/LOG:ファイル 結果をログファイルに出力

差分だけコピー・除外する

更新されたファイルだけをコピーしたり、特定のフォルダを除外したりもできます。再試行回数を絞ると、ネットワーク先へのコピーで待たされすぎるのを防げます。

除外・再試行の指定
# node_modules と一時ファイルを除外してコピー
robocopy "C:\project" "D:\backup\project" /E /XD "node_modules" /XF "*.tmp"

# 失敗時の再試行を3回・待機5秒に(既定は1百万回・30秒で待たされる)
robocopy "C:\data" "\\server\share\data" /E /R:3 /W:5

# 結果をログに残す
robocopy "C:\data" "D:\backup\data" /E /LOG:"C:\logs\backup.log" 
/R と /W は必ず指定すると安心

robocopyはコピーに失敗すると、既定で百万回・30秒間隔で再試行します。ネットワーク先やロックされたファイルがあると、これで何時間も止まったように見えることがあります。/R:3 /W:5(3回・5秒)のように小さい値を指定しておくと、失敗時もすぐ次へ進みます。定期バックアップのスクリプトでは、/R/Wを明示しておくのがおすすめです。

よくある失敗

終了コード1をエラーと判定する

0〜7は成功です。判定はif ($LASTEXITCODE -ge 8)でエラーとします。

/MIRで意図せずファイルを削除する

/MIRはコピー先の余分を消します。事前に/Lで削除対象を確認します。

コピー元とコピー先を逆にする

順番はrobocopy コピー元 コピー先です。逆にすると、とくに/MIRで大事故になります。

再試行で長時間止まる

既定は百万回再試行します。/R:3 /W:5などで回数と待機を絞ります。

パスにスペースがあるのに引用符で囲まない

スペースを含むパスは"C:\My Data"のように引用符で囲みます。

よくある質問

Qrobocopyの終了コードが1になりました。失敗ですか?
Aいいえ、成功です。1は「ファイルをコピーした」という意味です。robocopyは0〜7までが正常終了で、8以上がエラーです。スクリプトで成否を判定するときはif ($LASTEXITCODE -ge 8)のように、8以上をエラーとして扱ってください。
Q2つのフォルダを完全に同じにするには?
Arobocopy コピー元 コピー先 /MIRでミラーリングします。コピー元に無いファイルはコピー先から削除され、完全な鏡像になります。ただし削除が伴うため、必ず先に/Lを付けたドライランで、消える対象を確認してから実行してください。
Qコピー先のファイルを消したくありません。
A/MIRを使わなければ削除は起きません。/Eだけなら、コピー元のファイルを追加・更新するだけで、コピー先の既存ファイルは消えません。常に最新の鏡像にしたいときだけ/MIRを使い、追加・更新だけでよいなら/Eを使います。
QCopy-Itemとrobocopyはどう使い分けますか?
A少数のファイルの単純なコピーならCopy-Itemで十分です。フォルダまるごとのバックアップ、差分コピー、ミラーリング、ネットワーク越しの大量コピーなど、確実性や高機能が必要な場面ではrobocopyが向いています。robocopyは再試行やログ出力にも対応しています。
Qrobocopyが長時間止まってしまいます。
Aコピーに失敗したファイルがあると、既定で百万回・30秒間隔で再試行するためです。/R:3 /W:5のように再試行回数と待機秒数を小さく指定すれば、失敗時もすぐ次の処理へ進みます。ネットワーク先へのコピーでは特に指定しておくとよいです。

まとめ

  • 基本はrobocopy コピー元 コピー先 /E。2回目以降は差分だけコピーされます。
  • 実行前に/Lでドライランして対象を確認します。
  • 同期は/MIRコピー先の余分なファイルは削除されるので要注意です。
  • 終了コードは0〜7が成功。判定はif ($LASTEXITCODE -ge 8)でエラーとします。
  • /R:3 /W:5で再試行を絞ると、失敗時に長時間止まりません。

robocopyはWindows標準ながら、バックアップ・同期に必要な機能がそろった強力なツールです。「/MIRは削除を伴う」「終了コード0〜7は成功」の2点さえ押さえれば、安全に使いこなせます。/Lでのドライランを習慣にして、フォルダのバックアップを自動化してみてください。