sergey vasin

The IT blog

Copy-Item -Destination Unknown

leave a comment »

Если вы часто используете командлет Copy-Item в скриптах или интерактивно, то вы могли заметить, что результат его работы, в части того, как в итоге будут расположены копируемые элементы, в некоторой степени непредсказуем.

Тем не менее, логика здесь есть, и зависит она от существования элемента, указанного в параметре -Destination.

Выражается это в следующем: если элемент, указанный в параметре -Destination, отсутствует, то происходит копирование элемента, указанного в параметре -Path или -LiteralPath в совокупности с его переименованием в значение параметра -Destination.

А если элемент, указанный в параметре -Destination существует, к примеру, некий каталог, то элементы, указанные в параметре -Path или -LiteralPath копируются в этот каталог.

Files

То есть, если мы решим скопировать файл C:\script.ps1 в каталог C:\Scripts, которого еще не существует, и попробуем для этого воспользоваться командой

Copy-Item -Path C:\Script.ps1 -Destination c:\Scripts

то в итоге мы получим копию файла Script.ps1, расположенную в корне диска C:\ и называющуюся Scripts.

Что здесь происходит. Так как каталог C:\Scripts отсутствует, то Copy-Item считает, что значение параметра -Destination — это конечное имя копируемого элемента, а так как исходный элемент является файлом, то таковым должен быть и конечный элемент.

Естественно, это полезно, если мы хотим скопировать файл с одновременным его переименованием, например, так:

Copy-Item -Path C:\Script.ps1 -Destination c:\Scripts\AnotherScript.ps1

Но если нам нужно скопировать его под своим именем в некий, пока еще не существующий, каталог, то сначала нам нужно его создать.

New-Item -Path C:\Scripts -ItemType Directory
Copy-Item -Path C:\Script.ps1 -Destination c:\Scripts

Кроме того, создать каталог нам придется, даже в том случае, если мы намерены скопировать файл в несуществующий каталог с одновременным его, файла, переименованием.

New-Item -Path C:\Scripts -ItemType Directory
Copy-Item -Path C:\Script.ps1 -Destination c:\Scripts\AnotherScript.ps1

Ну и, для полноты картины, если мы введем следующую команду

Copy-Item -Path C:\Scripts -Destination c:\File.txt

то в итоге получим папку с именем File.txt. Логика здесь та же самая — элемент, указанный в параметре -Destination отсутствует, поэтому командлет считает, что File.txt это конечное имя копируемого элемента — C:\Scripts, а так как C:\Scripts — это каталог, то и результирующий элемент должен быть каталогом, вне зависимости от того, присутствует в его имени расширение или нет.

Folders

Теперь давайте рассмотрим копирование каталогов с некоторым содержимым. Для экспериментов создадим следующую структуру папок

New-Item -ItemType Directory -Path C:\RootFolder
New-Item -ItemType File -Path C:\RootFolder\RootFile1.txt
New-Item -ItemType File -Path C:\RootFolder\RootFile2.txt

New-Item -ItemType Directory -Path C:\RootFolder\Folder1
New-Item -ItemType File -Path C:\RootFolder\Folder1\File1.txt

New-Item -ItemType Directory -Path C:\RootFolder\Folder2
New-Item -ItemType File -Path C:\RootFolder\Folder2\File2.txt

Если мы введем следующую команду

Copy-Item -Path C:\RootFolder -Destination C:\AnotherRootFolder

и при этом каталога C:\AnotherRootFolder в файловой системе не существует, это приведет к тому, что каталог C:\RootFolder будет скопирован на диск C: под именем AnotherRootFolder. Так как мы не указали параметр -Recurse, то скопирован будет только сам каталог, его содержимое операция копирования никак не затронет.

Собственно, для того, чтобы скопировать каталог C:\RootFolder со всем его содержимым, а также в процессе переименовать его в AnotherRootFolder, к вышеприведенной команде потрбуется добавить параметр -Recurse.

При этом по-прежнему подразумевается, что на момент выполнения команды каталога C:\AnotherRootFolder не существует.

Copy-Item -Path C:\RootFolder -Destination C:\AnotherRootFolder -Recurse

Теперь предположим, что каталог AnotherRootFolder на диске C: присутствует. Выполнение этой же самой команды

Copy-Item -Path C:\RootFolder -Destination C:\AnotherRootFolder -Recurse

приведет к тому, что каталог C:\RootFolder будет скопирован под своим именем внутрь каталога C:\AnotherRootFolder вместе со всем своим содержимым.

Эта разница в поведении командлета Copy-Item будет особенно заметна, если в отсутствие каталога C:\AnotherRootFolder два раза запустить одну и ту же команду

Copy-Item -Path C:\RootFolder -Destination C:\AnotherRootFolder -Recurse
Copy-Item -Path C:\RootFolder -Destination C:\AnotherRootFolder -Recurse

Результатом будет следующая структура каталогов

C:\AnotherRootFolder
C:\AnotherRootFolder\RootFile1.txt
C:\AnotherRootFolder\RootFile2.txt
C:\AnotherRootFolder\Folder1
C:\AnotherRootFolder\Folder1\File1.txt
C:\AnotherRootFolder\Folder2
C:\AnotherRootFolder\Folder2\File2.txt

C:\AnotherRootFolder\RootFolder
C:\AnotherRootFolder\RootFolder\RootFile1.txt
C:\AnotherRootFolder\RootFolder\RootFile2.txt
C:\AnotherRootFolder\RootFolder\Folder1
C:\AnotherRootFolder\RootFolder\Folder1\File1.txt
C:\AnotherRootFolder\RootFolder\Folder2
C:\AnotherRootFolder\RootFolder\Folder2\File2.txt

Wildcards

Если мы собираемся использовать командлет Copy-Item в скриптах, то понятно, что результаты его выполнения должны быть предсказуемы. Это значит, что перед тем, как начинать копирование, нам стоит удостовериться в наличии папки назначения, и, в том случае, если ее еще не существует — создать.

Конечно, можно зайти с другого конца, и пытаться удостовериться в отсутствии папки, но в случае, если она все же есть, перед нами встанет другая дилемма — что же с ней делать, в особенности если в ней присутствует какое-либо содержимое. Поэтому давайте остановимся на варианте, когда мы используем существующую папку, или создаем ее в случае отсутствия.

Сделать это можно так

if(-not (Test-Path -Path C:\AnotherRootFolder)) {New-Item -ItemType Directory -Path C:\AnotherRootFolder}

Теперь мы можем скопировать нужные нам элементы в каталог назначения. В случае, если мы хотим скопировать только содержимое определенной папки, а не ее саму, мы можем воспользоваться следующей командой

Copy-Item -Path C:\RootFolder\* -Destination C:\AnotherRootFolder -Recurse

О чем тут стоит сказать, так это о том, что, если мы запустим эту команду в отсутствие каталога назначения, результатом будет достаточно выборочное копирование, а также сообщение об ошибке.

Если более детально, результат будет следующим

C:\AnotherRootFolder
C:\AnotherRootFolder\File1.txt
C:\AnotherRootFolder\RootFile1.txt
C:\AnotherRootFolder\RootFile2.txt

Происходит это потому, что использование символа ‘*’ в значении параметра -Path фактически приводит к тому, что операция копирования происходит для каждого элемента каталога C:\RootFolder по отдельности. То есть, сначала копируется каталог C:\RootFolder\Folder1 и, так как на момент запуска командлета элемент, указанный в параметре -Destination, отсутствует, происходит копирование с переименованием, а именно — каталог C:\RootFolder\Folder1 становится каталогом C:\AnotherRootFolder.

Далее то же самое пытается проделать и каталог C:\RootFolder\Folder2, что и вызывает сообщение об ошибке, так как при копировании он пытается переименовать себя в уже существующий каталог.

Таким образом, можно сказать, что количество полученных ошибок будет на единицу меньше количества копируемых каталогов.

-Container:$false

О чем еще стоит поговорить, так это о параметре -Container. Он указывает, что копирование данных должно происходить с учетом структуры каталогов. Так как это является поведением по умолчанию, в обычной ситуации использование параметра -Container не является необходимым.

А пригождается он тогда, когда эту самую структуру каталогов мы сохранять не намерены и в качестве результата хотим получить каталог, содержащий в себе все скопированные файлы, в каких бы вложенных каталогах они до этого не находились.

Copy-Item -Path C:\RootFolder\* -Destination C:\AnotherRootFolder -Recurse -Container:$false

Страницы в социальных сетях:

Twitter: https://twitter.com/vsseth
Facebook: https://fb.com/inpowershell
VKontakte: https://vk.com/inpowershell


Реклама

Written by Сергей Васин

Июнь 21, 2017 в 11:36

Опубликовано в PowerShell

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s