robocopyによるバックアップ#2 ジャンクション

前回の投稿では、古いPCから新しいPCへ乗り換えるにあたり、バックアップするフォルダーとバックアップ方法の導入部分まで説明しました。今回は、robocopyを使ってバックアップするときに、エラーの発生を少なるくするためのちょっとした方法について説明します。

前回の投稿でバックアップにはWindows標準で利用できるrobocopy.exeを使うことにしました。

robocopy.exe

robocopy.exeは、Windows標準で利用できるコマンドラインツールです。コマンドプロンプトやWindows PowerShellのコンソールで、robocopy.exeを引数なしで実行すると、簡単な使い方が表示されます。

C:\Users\admin>robocopy

-------------------------------------------------------------------------------
   ROBOCOPY     ::     Windows の堅牢性の高いファイル コピー
-------------------------------------------------------------------------------

  開始: 2021年3月20日 22:18:19
       簡易な使用法 :: ROBOCOPY コピー元 コピー先 /MIR

           コピー元 :: コピー元ディレクトリ (ドライブ:\パスまたは \\サーバー
                       \共有\パス)。
           コピー先 :: コピー先ディレクトリ (ドライブ:\パスまたは \\サーバー
                       \\共有\パス)。
               /MIR :: 完全なディレクトリ ツリーをミラー化します。

    詳細な使用方法については、ROBOCOPY /? を実行してください。


****  /MIR はファイルをコピーできるだけでなく、削除もできます。

C:\Users\admin>

指定のフォルダーだけコピー

バックアップ(コピー)をしたいだけなら、コピー元とコピー先を指定して実行すればよいです。

robocopy {コピー元フォルダー} {コピー先フォルダー}

です。しかし、これでは、サブフォルダーがコピーされません。

指定のフォルダーをサブフォルダーも含めてコピー

サブフォルダーも含めてコピーしたいので、/MIR もしくは /E のオプションも必要です。ここでは、/MIRを使います。

robocopy {コピー元フォルダー} {コピー先フォルダー} /MIR

この指定で実行すると、ユーザーが作成したフォルダーであれば、多くの場合に成功します。しかし、アクセス権限が足りない、コピー元のファイルが使用中などの理由でコピーができず、コピーのエラーが発生したとき、コピーが進まず、ずっと待ち状態になります。

アクセス権限が足りずコピーできない問題の回避

上記のコマンドラインでコピーを開始すると下記のようにアクセス拒否のエラーが発生することがあります。

>robocopy C:\Users\admin\ D:\backup\Users\admin\ /MIR
...
       新しいディレクトリ       0      C:\Users\admin\AppData\Local\Application Data\
2021/03/29 22:37:22 エラー 5 (0x00000005) コピー先ディレクトリにタイムスタンプを追加しています D:\backup\Users\admin\AppData\Local\Application Data\
アクセスが拒否されました。
30 秒間待機しています... 再試行しています...
...

このようなアクセス拒否によるコピー時のエラーを減らすためには、管理者権限に昇格してrobocopy.exeを実行してバックアップを行います。具体的には、robocopy.exeを実行するコマンドプロンプトまたはWindows PowerShellを管理者権限で実行します。

コマンド プロンプト (cmd.exe)

通常の権限でコマンドプロンプトを起動した場合は、ウィンドウのタイトルは「コマンド プロンプト」です。

コマンド プロンプト(通常権限時)

コマンドプロンプトを管理者として起動すると、ウィンドウのタイトルは「管理者:コマンド プロンプト」になります。コマンドプロンプトを管理者権限で起動したかどうかを忘れたときは、ウィンドウタイトルで確認できます。

コマンド プロンプト(権限昇格時)

管理者権限のコマンド プロンプトの起動方法

Windowsのスタート画面から検索して権限昇格したコマンドプロンプトを起動する場合は、Windows 10の場合、以下の手順で起動できます。

  1. 「Widowsキー + Q」 で検索画面を開く
  2. 検索画面で「cmd 」と入力
  3. コマンドプロンプトが見つかるので、「管理者として実行」をクリック

また、通常のコマンドラインから権限昇格したコマンドプロンプトを起動したい場合は、以下のように実行します。

C:\Users\admin> PowerShell.exe start cmd.exe -verb runas

Windows PowerShell (PowerShell.exe)

通常の権限でWindows PowerShellを起動した場合は、ウィンドウのタイトルは「Windows PowerShell」です。

パワーシェル(通常権限時)

Windows PowerShellを管理者として起動すると、ウィンドウのタイトルは「管理者:Windows PowerShell」になります。Windows PowerShellを管理者権限で起動したかどうかを忘れたときは、ウィンドウタイトルで確認できます。

パワーシェル(権限昇格時)

管理者権限のWindows PowerShell の起動方法

Windowsのスタート画面から検索して権限昇格したWindows PowerShellを起動する場合は、Windows 10の場合、以下の手順で起動できます。

  1. 「Widowsキー + Q」 で検索画面を開く
  2. 検索画面で「powershell」と入力
  3. Windows PowerShellが見つかるので、「管理者として実行」をクリック

また、通常のコマンドラインから権限昇格したWindows PowerShellを起動したい場合は、以下のように実行します。

C:\Users\admin> PowerShell.exe start PowerShell.exe -verb runas

コピーの失敗時の待機時間と試行回数

robocopyでのコピーが失敗したとき既定の動作は、ある時間待機した後に、再試行です。そして、待機時間と再試行回数の既定値は、30秒と1,000,000回(100万回)です。もし、コピーの失敗の原因が、時間をあけて再実行しても解消しない場合、一つのファイルのコピーの再試行を347.2日間(30秒×100万回)も行うことになります。

このままだとコピーが現実的な時間で完了することができません。古いPCから新しいPCの移行のためのバックアップなので、エラーが回復できないようなファイルはスキップしたいです。そのために、待機時間は3秒、再試行回数は3回とし、一つのファイルのエラーでは最大でも9秒しか待たないようにし、現実的な時間で終わるようにします。

待機時間は/Wオプション、再試行回数は/Rオプションで指定できます。すると、コマンドラインは以下のようになります。

robocopy {コピー元フォルダー} {コピー先フォルダー} /MIR /R:3 /W:3

フォルダー階層の無限コピーの回避

先の待機時間と再試行回数の設定を追加することで、ファイルの使用中やそれ以外の原因でコピーに失敗するファイルを現実的な時間でスキップすることができるようになりました。

通常のユーザーフォルダーなどのコピーにおいては、これで問題ありません。

ところが、C:\Users\{ユーザ名}\のフォルダーをバックアップのためにrobocopy.exeでコピーしていたところ、問題が発生しました。なぜか、フォルダー階層が異なる同じファイルを何個もコピーし続け、処理が終わらないのです。

たとえば、以下のようにIconCache.dbファイルがフォルダー階層違いで何度もコピーし続きます。

  • C:\Users\{ユーザ名}\AppData\Local\IconCache.db
  • C:\Users\{ユーザ名}\AppData\Local\Application Data\IconCache.db
  • C:\Users\{ユーザ名}\AppData\Local\Application Data\Application Data\IconCache.db
  • C:\Users\{ユーザ名}\AppData\Local\Application Data\Application Data\Application Data\IconCache.db

なぜ、このような現象が起きるかというと、Application Dataフォルダーは通常のフォルダーではないからです。このフォルダーは過去Windowsの互換性を維持するための特別な種類のフォルダーです。

実際、dir /aコマンドで確認してみます。

C:\Users\admin\AppData\Local>dir /a
 ドライブ C のボリューム ラベルは Windows です
 ボリューム シリアル番号は FAFA-1212 です

 C:\Users\admin\AppData\Local のディレクトリ

2021/03/20  20:52    <DIR>          .
2021/03/20  20:52    <DIR>          ..
2021/03/31  23:23    <DIR>          .IdentityService
2019/12/07  22:00    <DIR>          Adobe
2020/11/19  21:11    <JUNCTION>     Application Data [C:\Users\admin\AppData\Local]
2019/10/13  00:53    <DIR>          Apps

Application Dataフォルダーのところは、<DIR>ではなく、<JUNCTION>となっています。また、[C:\Users\admin\AppData\Local]とも表示されています。

JUNCTION(ジャンクション)とは、ファイルやフォルダーの実体を表すものではなく、ファイルやフォルダーの実際の場所を示すリンクみたいなものです。ただし、アプリからJUNCTIONにアクセスすると、システム側でリンク先の実体に変換されます。アプリから見たら、JUNCTIONの場所にファイルやフォルダーがあるのと変わりません。

Application Dataのジャンクションで特徴的なことは、C:\Users\admin\AppData\LocalにあるApplication DataApplication Dataがあるフォルダー(C:\Users\admin\AppData\Local)にリンクされていることです。その結果、アプリから見た場合、Application Dataフォルダーの下に、再度、ジャンクションのApplication Dataフォルダーがあるように見えます。

すなわち、

  • C:\Users\{ユーザ名}\AppData\Local\
  • C:\Users\{ユーザ名}\AppData\Local\Application Data\
  • C:\Users\{ユーザ名}\AppData\Local\Application Data\Application Data\
  • C:\Users\{ユーザ名}\AppData\Local\Application Data\Application Data\Application Data\

Application Dataフォルダーの階層が延々に続く状態になります。結果として、バックアップのコピーが延々に続くことになります。

ジャンクションは、ファイルやフォルダーの実体ではなく、それらへのリンクです。そのため、ファイルやフォルダーの実体がバックアップされていれば、ジャンクションそのもの(リンク情報)はバックアップをしなくても特に問題ありません。

Application Dataフォルダーの階層が深くなりコピーが延々に続く問題を回避するために、robocopy.exeの指定で、ジャンクションのファイルやフォルダーをコピーの対象から外すことにします。

ジャンクションのファイルをコピー対象から外すときは/XJFオプションを使います。ジャンクションのフォルダーをコピー対象から外すときは、/XJDオプションを使います。すると、コマンドラインは以下のようになります。

robocopy {コピー元フォルダー} {コピー先フォルダー} /MIR /R:3 /W:3 /XJD /XJF /SL

なお、/XJD/XJFの両方を指定するときは、代わりに/XJオプションを使うこともできます。ここでは、リンクもターゲットをそのままコピーしないように/SLオプションも追加しています。

オンラインファイルのダウンロードの回避

Windowsには、オンラインファイルという機能があります。オンラインファイルは、ネットワーク上にファイルの本体があり、ローカルストレージ上にはファイルの実体はなく、ファイル名の情報のみがあるファイルです。アプリがオンラインファイルを開こうとしたとき、ネットワーク上のファイルの実体がローカルストレージ上にダウンロードされます。

オンラインファイルの身近の例は、OneDriveの同期フォルダーです。システムのストレージの空き領域を逼迫させないために、通常、OneDriveの同期フォルダーにはファイル本体はダウンロードされていません。アプリがOneDriveの同期フォルダーにあるファイルを開こうとしたとき、Windowsが自動的にネットワーク上のOneDriveからファイルをダウンロードします。

このオンラインファイルがrobocopy.exeを使ったバックアップのときに問題を引き起こします。

ネットワークをつながずにバックアップをする場合、ローカルストレージ上に実体が存在しないオンラインファイルについて、コピーが失敗します。ネットワーク上のファイル本体をダウンロードできないからです。コピーが失敗すると、先に説明した待機時間や再試行が発生し、無駄な時間を費やします。

ネットワークをつないでバックアップをする場合、ローカルストレージ上に実体が存在しないオンラインファイルはその都度ダウンロードすることになり、バックアップに時間がかかってしまいます。

そもそも、オンラインファイルの実体がローカルストレージ上に存在しないときでも、ネットワーク上に元ファイルの実体が存在します。そのため、ネットワーク上に元ファイルの実体が存在するのであれば、ローカルファイルとしてバックアップする必要はありません。

そこでrobocopy.exeでのバックアップ時にオンラインファイルをコピーしようとする問題を回避するために、オンラインファイルをコピーの対象から外すことにします。

オンラインファイルをコピーの対象から外すときは/XA:Oオプションを使います。すると、コマンドラインは以下のようになります。

robocopy {コピー元フォルダー} {コピー先フォルダー} /MIR /R:3 /W:3 /XJD /XJF /SL /XA:O

robocopy.exeの最終的なコマンドライン

最終的にrobocopy.exeのコマンドラインは以下のようになりました。

robocopy {コピー元フォルダー} {コピー先フォルダー} /MIR /R:3 /W:3 /XJD /XJF /SL /XA:O

このコマンドラインでバックアップをすると、現実的な時間で、フォルダーのバックアップをすることができます。私も、このコマンドラインで、フォルダーのバックアップを取ることができました。


以上、robocopy.exeを使ってフォルダーのバックアップをとるときの注意点の投稿でした。

“robocopyによるバックアップ#2 ジャンクション” への1件の返信

コメントを残す