Copy-itemを使ったディレクトリコピーはしないほうが無難なのでは、という話
Copy-itemを使ったディレクトリコピーはコピー先に指定するディレクトリの有無に依存して挙動が変わってしまう。
面倒でもディレクトリコピーはしないほうが無難であり、コピー先フォルダを作成した上で、コピー元フォルダ以下をワイルドカードコピーすべきでは、という話
というか、ディレクトリコピーをするならPowershellにこだわらずrobocopyを使ったほうが良いのだろうと思う*1
環境
PS D:\SandBox> "$((get-wmiobject win32_operatingsystem).caption) ($((get-wmiobject win32_operatingsystem).version))" Microsoft Windows 10 Pro (10.0.10586) PS D:\SandBox> $PSVersionTable.PSVersion Major Minor Build Revision ----- ----- ----- -------- 5 0 10586 494
実際に試してみる
- コピー先のディレクトリが存在しない場合⇒コピー先のディレクトリを作成し、コピー元のディレクトリの内容をコピー先にコピーする
- コピー先のディレクトリが存在しない場合⇒コピー先のディレクトリの下に、コピー元ディレクトリをコピーする(同名で同内容のディレクトリがコピー先に作成される)
PS D:\SandBox> #フォルダ構成 PS D:\SandBox> tree /f D:\SandBox フォルダー パスの一覧 ボリューム シリアル番号は 4641-823A です D:\SANDBOX └─from test1.txt test2.txt PS D:\SandBox> #コピー先ディレクトリが存在しない場合にディレクトリコピーする PS D:\SandBox> Copy-Item .\from .\to -Recurse -Force -PassThru ディレクトリ: D:\SandBox Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2016/09/19 15:35 to ディレクトリ: D:\SandBox\to Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2016/09/19 15:31 14 test1.txt -a---- 2016/09/19 15:31 14 test2.txt PS D:\SandBox> #コピー先フォルダが作成され、ディレクトリがコピーされる PS D:\SandBox> tree /f D:\SandBox フォルダー パスの一覧 ボリューム シリアル番号は 4641-823A です D:\SANDBOX ├─from │ test1.txt │ test2.txt │ └─to test1.txt test2.txt PS D:\SandBox> PS D:\SandBox> #上記のようにコピー先フォルダが存在する状態で、先ほどと同じコマンドでディレクトリコピーする PS D:\SandBox> Copy-Item .\from .\to -Recurse -Force -PassThru ディレクトリ: D:\SandBox\to Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2016/09/19 15:37 from ディレクトリ: D:\SandBox\to\from Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2016/09/19 15:31 14 test1.txt -a---- 2016/09/19 15:31 14 test2.txt PS D:\SandBox> tree /f D:\SandBox フォルダー パスの一覧 ボリューム シリアル番号は 4641-823A です D:\SANDBOX ├─from │ test1.txt │ test2.txt │ └─to │ test1.txt │ test2.txt │ └─from test1.txt test2.txt PS D:\SandBox> #コピー先ディレクトリの配下に、コピー元フォルダが複製される
回避策
コピー先の有無によって挙動が変わるのは再現性がないため避けたい。 以下のように、ディレクトリコピーではなく、ディレクトリ配下をワイルドカードでコピーするようにすると、フォルダが存在しない場合はエラーとなる。
PS D:\SandBox> Copy-Item .\from\* .\to\ -Recurse -Force -PassThru Copy-Item : ファイル名、ディレクトリ名、またはボリューム ラベルの構文が間違っています。 発生場所 行:1 文字:1 + Copy-Item .\from\* .\to\ -Recurse -Force -PassThru + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Copy-Item], IOException + FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.CopyItemCommand PS D:\SandBox> md .\to\ ディレクトリ: D:\SandBox Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2016/09/19 15:46 to PS D:\SandBox> ls ディレクトリ: D:\SandBox Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2016/09/19 15:31 from d----- 2016/09/19 15:46 to PS D:\SandBox> Copy-Item .\from\* .\to\ -Recurse -Force -PassThru ディレクトリ: D:\SandBox\to Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2016/09/19 15:31 14 test1.txt -a---- 2016/09/19 15:31 14 test2.txt PS D:\SandBox> tree /f D:\SandBox フォルダー パスの一覧 ボリューム シリアル番号は 4641-823A です D:\SANDBOX ├─from │ test1.txt │ test2.txt │ └─to test1.txt test2.txt
結論
ディレクトリコピーするときはPowershellを使わないほうが良いと思う(2016/09/19時点)。 なお、このあたりの詳細な挙動については、Copy-Item -Recurse の振舞が詳しい