Копирование файлов эффективно с помощью PowerShell Copy-Item: Подробное руководство

Копирование файлов. Это может быть не сексуально, но должно быть сделано. В графическом интерфейсе мы копируем и вставляем с буфером обмена, но в PowerShell у нас есть cmdlet под названием Copy-Item.

Команды для копирования файлов существуют во всех языках оболочки уже целую вечность. В мире PowerShell самым популярным способом скопировать файл или папку в вашем скрипте PowerShell из точки A в точку B является использование cmdlet PowerShell Copy-Item. Этот cmdlet позволяет нам копировать файл и папку, предоставляя возможность рекурсивного копирования файлов в папке, использовать маски для выбора файлов, которые нужно скопировать, и даже использовать удаленное выполнение в PowerShell для копирования файлов!

Этот cmdlet является частью cmdlet’ов поставщика PowerShell. Это универсальное cmdlet, которое распознается по его существительному Item. Большинство этих cmdlet’ов поставщика могут использоваться с различными поставщиками, но за почти 10 лет использования PowerShell я видел, что Copy-Item используется только с поставщиком файловой системы.

Используя этот cmdlet, PowerShell позволяет разработчику копировать файлы и папки разными способами.

Базовое использование

Наиболее базовым образом Copy-Item cmdlet копирует один файл из точки A в точку B, используя параметр Path в качестве исходного пути файла и параметр Destination в качестве пути каталога назначения.

PS> Test-Path -Path C:\PointB\1.txt
False
PS> Copy-Item -Path C:\PointA\1.txt -Destination C:\PointB\
PS> Test-Path -Path C:\PointB\1.txt
True 

Этот cmdlet также может копировать пустые папки. Я перечислю элемент в папке C:\EmptyFolder и затем скопирую их.

PS> Get-ChildItem -Path C:\EmptyFolder\
PS> Test-Path -Path C:\PointB\EmptyFolder -PathType Container
False
PS> Copy-Item -Path C:\EmptyFolder\ -Destination C:\PointB\
PS> Test-Path -Path C:\PointB\EmptyFolder -PathType Container
True 

Возможно, в папке есть файл только для чтения. По умолчанию Copy-Item не будет его перезаписывать. Чтобы принудительно перезаписать, просто добавьте параметр Force.

Выборочное копирование с помощью Copy-Item

Помимо копирования одного файла или папки, мы также можем скопировать все содержимое папки. Параметр Path Copy-Item принимает символы подстановки, такие как звездочка, чтобы сопоставить один или несколько символов, или вопросительный знак, чтобы сопоставить только один символ.

PS> @(Get-ChildItem -Path C:\PointB).Count
0
PS> @(Get-ChildItem -Path C:\PointA).Count
10000
PS> @(Get-ChildItem -Path C:\PointB).Count
0
PS> Copy-Item -Path C:\PointA\* -Destination C:\PointB\
PS> @(Get-ChildItem -Path C:\PointB).Count
10000
PS> @(Get-ChildItem -Path C:\PointB).Count
0
PS> Copy-Item -Path 'C:\PointA\26?0.txt' -Destination C:\PointB\
PS> Get-ChildItem -Path C:\PointB\

Directory: C:\PointB
Mode                LastWriteTime         Length Name
-a----        8/11/2017   8:59 AM              5 2600.txt
-a----        8/11/2017   8:59 AM              5 2610.txt
-a----        8/11/2017   8:59 AM              5 2620.txt
-a----        8/11/2017   8:59 AM              5 2630.txt
-a----        8/11/2017   8:59 AM              5 2640.txt
-a----        8/11/2017   8:59 AM              5 2650.txt
-a----        8/11/2017   8:59 AM              5 2660.txt
-a----        8/11/2017   8:59 AM              5 2670.txt
-a----        8/11/2017   8:59 AM              5 2680.txt
-a----        8/11/2017   8:59 AM              5 2690.txt

Объединение нескольких папок

Еще одна отличная особенность Copy-Item – его способность копировать несколько папок вместе одновременно. Передачей нескольких путей параметру Path Copy-Item будет рассматривать каждый из них, копировать либо папку, либо файл(ы) в зависимости от пути, и “сливать” их все в один пункт назначения.

PS> Copy-Item -Path C:\PointB\*,C:\PointC\*,C:\PointD\* -Destination C:\PointE
PS> Get-ChildItem -Path C:\PointE

Directory: C:\PointE
Mode                LastWriteTime         Length Name
-a----       11/11/2017  12:15 PM              2 PointBFile.txt
-a----       11/11/2017  12:15 PM              2 PointCFile.txt
-a----       11/11/2017  12:16 PM              4 PointDFile.txt

Рекурсивное копирование файлов

Вероятно, вам не повезет и вы не получите все файлы в одной папке без вложенных папок. Обычно мы сталкиваемся с ситуациями, когда у нас много подпапок в родительской папке, в которых также есть файлы, которые мы хотели бы скопировать. Используя параметр Recurse в Copy-Item, он с радостью будет просматривать каждую подпапку и копировать все файлы и папки рекурсивно.

Обратите внимание, что я направляю файлы и папки непосредственно из Get-ChildItem в Copy-Item. Copy-Item поддерживает конвейер!

PS> (Get-ChildItem -Path C:\PointB\ -Recurse).Count
5
PS> Get-ChildItem -Path C:\PointB\ | Copy-Item -Destination C:\PointC -Recurse
PS> (Get-ChildItem -Path C:\PointC\ -Recurse).Count
5

Преимущества использования параметра PassThru

У многих cmdlet в PowerShell есть параметр PassThru. Cmdlet, которые обычно ничего не возвращают, могут вернуть объекты, которыми они манипулируют, с использованием параметра PassThru. Этот cmdlet не исключение. Когда я впервые начал писать сценарии, я никогда не использовал этот параметр, потому что не чувствовал его необходимости.

Например, если мне нужно скопировать файл в удаленное местоположение, а затем ссылаться на этот файл позже в своем сценарии, я бы сделал что-то вроде этого:

$remoteFilePath = '\WEBSRV1\c$\File.txt'
Copy-Item -Path C:\File.txt -Destination $remoteFilePath
Write-Host "I've just copied the file to $remoteFilePath"

Этот метод работает, но может быть лучше. Вместо того чтобы определять переменную для удаленного пути, почему бы просто не захватить объект, который возвращается из cmdlet Copy-Item при использовании параметра PassThru? Возвращаемые объекты всегда будут иметь путь к файлу назначения.

$copiedFile = Copy-Item -Path C:\File.txt -Destination '\WEBSRV1\c$'

Копирование файлов с использованием сеанса удаленного управления PowerShell

Одна из крутых особенностей, появившихся в PowerShell v5, это возможность этого cmdlet не использовать протокол SMB по умолчанию для передачи файла, а вместо этого использовать WinRM и удаленный сеанс PowerShell. Путем использования параметра Session Copy-Item использует существующий сеанс PowerShell и передает файлы таким образом. Это отличный способ обойти брандмауэры и обеспечить дополнительный уровень безопасности при шифровании сеанса обмена данными.

PS> $session = New-PSSession -ComputerName WEBSRV1
PS> Invoke-Command -Session $session -ScriptBlock { Test-Path -Path C:\File.txt }
False
PS> Copy-Item -Path C:\File.txt -ToSession $session -Destination 'C:\'
PS> Invoke-Command -Session $session -ScriptBlock { Test-Path -Path C:\File.txt }
True

Мы могли бы скопировать файл File.txt через SMB и надеяться, что административная общая папка C$ была доступна, и использовать путь назначения \\WEBSRV1\c$. Поскольку мы вместо этого использовали параметр ToSession, путь назначения всегда будет путем, локальным для компьютера, на котором выполняется удаленный сеанс.

Сводка

Команда Copy-Item – одна из основных команд PowerShell, которую вы будете использовать снова и снова. В PowerShell можно копировать файлы и папки несколькими различными способами благодаря ее простоте и мощности, особенно ее способности использовать подстановочные символы, объединять несколько папок файлов вместе и использовать существующие сеансы удаленного управления PowerShell!

Дополнительное чтение

Copy-item

Source:
https://adamtheautomator.com/copy-item/