PowerShell командлет Copy-Item используется для копирования файлов между локальными, сетевыми каталогами или между компьютерами по сети через WinRM. Командлет Copy-Item предоставляет большое количество опций, которые можно использовать в разных сценариях копирования файлов и каталогов (по своим возможностям этот командлет почти не уступает утилите robocopy). Например:
- перезапись файлов (override)
- фильтрация по имени/шаблону
- исключение по имени/шаблону
- Verbose режим
- Копирование файлов с/на удаленные компьютеры
Начнем с простых примеров использования Copy-Item и будем переходить к более сложным.
Копирование файлов и каталогов
Чтобы скопировать один файл 1.txt из каталога C:\SourceFolder\ в F:\DestFolder\, выполните:
Copy-Item -Path "C:\SourceFolder\1.txt" -Destination "F:\DestFolder\1.txt"
Можно использовать сокращенный синтаксис командлета, пропустив указание параметров Path и Destination:
cpi "C:\SourceFolder\1.txt" "F:\DestFolder\1.txt"
Теперь скопируем каталог C:\SourceFolder\folder в F:\DestFolder\folder. В папке folder находится файл 1.txt. Обратите внимание что без ключа –Recurse, папка folder копируется без содержимого:
Copy-Item -Path "C:\SourceFolder\folder" -Destination "F:\DestFolder\folder" -Recurse
С помощью Copy-Item также можно просто объединить файлы из несколько директорий в одну (слияние директории), для этого нужно перечислить директории в ключе –Path:
Copy-Item -Path "C:\SourceFolder\*", "C:\SourceFolder2\*", "C:\SourceFolder3\*" -Destination "F:\DestFolder\"
Копирование с заменой и копирование с заменой read-only файлов
Copy-Item по умолчанию при копировании заменяет файлы в целевом каталоге. Никаких дополнительных параметров указывать не нужно. При копировании каталога, если нужно заменить каталог в целевой папке, нужно использовать ключ –Force, иначе будет ошибка “Элемент folder с указанным именем уже существует — DirectoryExists”.
Для перезаписи файла с атрибутом read-only, нужно использовать ключ -Force. Если его не использовать, вы получите ошибку “отказано в доступе по пути… CopyFileInfoItemUnauthorizedAccessError”.
Чтобы скопировать файл с перезаписью файла с read-only атрибутом используйте параметр Force.
Copy-Item -Path "C:\SourceFolder\1.txt" -Destination "F:\DestFolder\1.txt" -Force
Чтобы Copy-Item скопировал файлы из одной папки в другую без замены существующих файлов, можно использовать этот простой скрипт
Copy-Item (Join-Path "C:\SourceFolder\" "*") "F:\DestFolder\" -Exclude (Get-ChildItem "F:\DestFolder\") -Recurse
Этот скрипт скопирует все файлы и папки из C:\SourceFolder в F:\DestFolder без замены файлов уже существующих в F:\DestFolder
Копирование с фильтрацией по шаблону
С помощью Copy-Item можно скопировать файлы/директории выбранные с помощью wildcard символа * или с помощью символа ?. Также поддерживаются некоторые регулярные выражения
- * — обозначает любое количество любых символов
- ? – обозначает 1 любой символ
- [a-z], [0-9] – символы между a-z и цифры между 0 и 9
Для примера возьмём такую структуру файлов:
Выполним копирование командой:
Copy-Item -Path "C:\SourceFolder\fol*" -Destination "F:\DestFolder\"
Результат в F:\DestFolder\
Теперь чистим папку назначения и выполняем:
Copy-Item -Path "C:\SourceFolder\folder[0-3]" -Destination "F:\DestFolder\"
Результат:
Папка без цифры в окончании не скопировалась, потому что folder[0-3] подразумевает что после folder будет как минимум еще 1 символ между 0 и 3
Исключение файлов при копировании
С помощью ключа –Exclude можно исключить файлы при копировании. Например, следующай команда скопирует все файлы кроме файлов с расширением txt.
Copy-Item -Path "C:\SourceFolder\*" -Destination "F:\DestFolder\" -Recurse -Force -Exclude "*.txt"
Аналогичным же образом можно применить ключ –Include, например
Copy-Item -Path "C:\SourceFolder\*" -Destination "F:\DestFolder\" -Recurse -Force -Include "*.txt"
Скопирует только txt файлы. Хотя для простоты гораздо удобнее использовать при копировании вид
-Path "C:\SourceFolder\*.txt"
.
Копирование файлов на удаленный компьютер по сети
Copy-File может копировать не только по SMB протоколу, но и через WinRM (WSMan).
Создайте новую сессию с компьютером testnode1 и выполните копирование в её контексте:
$session = New-PSSession -ComputerName testnode1
Copy-Item -Path "C:\SourceFolder\*" -ToSession $session -Destination "C:\SourceFolder\" -Recurse -Force
Эта команда скопирует файлы с локального компьютера из директории C:\SourceFolder на компьютер testnode1 в C:\SourceFolder\.
Test-WSMan -ComputerName testnode1
Если WSMan не настроен, вы можете выполнить его быструю конфигурацию. Для этого откройте командную строку с правами администратора и выполните
winrm quickconfig
Также можно копировать и через обычные сетевые SMB шары, для этого просто используйте UNC формат сетевого пути.
Copy-Item -Path "C:\SourceFolder\*" -Destination "\\testnode1\C$\copy_tutorial\"
Можно скопировать файл с удаленного компьютера. Принцип такой же, как и при копировании файлов на удаленный компьютер, за исключением параметра –ToSession, вместо него нужно использовать –FromSession:
$session = New-PSSession -ComputerName testnode1
Copy-Item -FromSession $session -Path "C:\SourceFolder\*" -Destination "F:\DestFolder\" -Recurse -Force
Эта команда скопирует содержимое папки C:\SourceFolder\ с компьютера testnode1 на локальный компьютер в директорию F:\DestFolder
Ключ PassThru
Командлет Copy-Item (как и многие другие командлеты PowerShell) не возвращает результатов в консоль. Параметр PassThru применяется скриптах, или для лог-файлов, когда нужно получить список скопированных файлов и работать с ним дальше. Рассмотрим пример
$items = Copy-Item -Path "C:\SourceFolder\*" –Destination "\\testnode1\C$\copy_tutorial\" -PassThru
Переменная
$items
будет содержать список скопированных файлов, с которым вы можете работать дальше.Это значит что вы можете напрямую работать с этими файлами. Например выполнив команду
Remove-Item $items[0]
, вы удалите директорию folder.
Ключ Verbose
При использовании ключа -Verbose вы получите подробный лог операций копирования. Например, вывод команды
Copy-Item -Path "C:\SourceFolder\*.txt" -Destination "F:\DestFolder\" -Recurse -Force -Verbose
Несколько полезных скриптов с Copy-Item
Скопировать только файлы:
Get-ChildItem "C:\SourceFolder" -File -Recurse | Copy-Item -Destination "F:\DestFolder"
Скопировать структуру папок, без файлов:
$path = Get-ChildItem "C:\SourceFolder" -Recurse | ?{$_.PsIsContainer -eq $true}
$dest = "F:\DestFolder\"
$parent = $path[0].Parent.Name
$path | foreach {
$_.FullName -match "$parent.+"
New-Item -ItemType directory ($dest + $Matches[0])
}
Copy-Item очень простой и удобный в использовании командлет PowerShell для выполнения операций копирования и перемещения файлов. В сочетании с другими инструментами PowerShell, Copy-Item также является мощным инструментом для написания скриптов.
Здравствуйте. Столкнулся с непонятками:
gci $VSCPath | ? {$_.PSIsContainer -eq $true} | Copy-Item -Destination $dest -Recurse
содержимое первой по порядку папки высыпается напрямую в Destination, остальные копируются нормально, вместе с содержимым.
На другом хосте тоже самое.
gci $VSCPath | ? {$_.PSIsContainer -eq $true}
djpdhfoftnПодскажите, как можно это вылечить?
Добрый день. Попробуйте пройтись по папкам через цикл for-each, передавая каждую папку как аргумет для copy-item. Убедитесь что пути директорий которые Вы передаёте корректные (подебажьте через write-host, например)
Так вот он выше список каталогов.
Дело не в пути. Дело в том что он первый.
При
gci $VSCPath |sort -Descending | ? {$_.PSIsContainer -eq $true}
высыпается содержимое другой папки, которая до этого копировалась нормальноюНе могу Вам конкретно ответить в чём проблема, так как для этого нужно разбираться с дебагом Вашего скрипта. Возможно дело в том, что первая директория по какой-то причине не так передается в пайплайн. Попробуйте использовать get-childitem
То же самое. Первый по порядку высыпается в корень.
$Files = gci $VSCPath | ? {$_.PSIsContainer -eq $true}|
Select -Property Name,@{label=”Path”;Expression ={$_.FullName}} | Select -Property Path # | Copy-Item -Destination $dest -Recurse
foreach ($sFile in $Files)
{
#Copy-Item -LiteralPath $sFile.Path -Destination $dest -Recurse
$sFile.Path +" -- "+ $dest
}
Я так понял, что Copy-Item не создаёт директорию, если её нет.
Copy-Item -LiteralPath «C:\testPS\1\222.jpg» -Destination «C:\testPS\2\222.jpg»
(ошибка)
«Не удалось найти часть пути «C:\testPS\2\222.jpg».»
Приходится директорию отделять от файла каждый раз в цикле.
Печально, что «Copy-item» не умеет копировать права NTFS папок и файлов , а также переподключаться при обрывах в сети.
Спасибо за приведенные примеры
Был бы интересен вариант копирования с одной сетевой шары в другую а после окончания операции проверить на соответствие и в случае если в источнике добавились файлы или изменились то провести копирование только этих объектов .
Добрый день. Помогите с поиском решения для переноса файлов.
Есть csv файл в который выгружен список файлов, которые не изменялись в течении 2 лет, в файле порядка 3000000 строк. Задача перенести на новый диск все файлы кроме .xl*.
Написал вот такой скрипт, который еще попутно ведет лог того что перенесено.
$Paths = Import-Csv -Path ‘C:\temp\OldFiles.csv’ -Delimiter ‘;’
$Paths = $Paths.FullName
$Copylog = «C:\temp\copylog_all.csv»
foreach ($Path in $Paths){
foreach ( $Newpath in $Path){
If ($Path.Substring(0,2) -eq «\\») {$Newpath = («\\?\Y:» + $Path.Remove(0,12))}
$Destpath = Split-Path $Newpath -Parent
$Item = Move-Item -Path $Path -Destination $Destpath -Exclude *.xl* -PassThru -Verbose
$Item |Select-Object fullname | Export-Csv -Force -Path $Copylog -Encoding UTF8 -Delimiter «;»
-NoTypeInformation -Append
}
}
путь в файле примерно такого вида
«\\?\D:\_Dept\111111\2222\33333\44444\55555\6666\777777\888888.pdf»
Структура папок на новом диске полностью перенесена со всеми группами доступа.
Проблема в том что PowerShell обрабатывает этот скрипт очень медленно, за 2 недели прошел порядка 1кк строк.
Есть ли способ его ускорить? Или какие-нибудь решения с помощью Robocopy?
Что означает знак «+» в последнем примере?
$_.FullName -match «$parent.+»
Добрый день!
Как копировать когда я удалённо уже подключился через Enter-PSSession к себе на локальный комп ?
Вопрос.
Когда объявляю переменную она сразу отрабатывает.
Т.е.
$copy = Copy-Item "$folders_on" -Destination "\\$computer\$folders_in" -Recurse -Force
и начинается копирование файлов.
Хотя копирование должно начаться, когда я напишу её после, т.е.
$copy
Подскажете, как сделать так, чтобы копирование не начиналось при объявлении переменной, а только после того, как она выла вызвана.
Copy-Item "$folders_on" -Destination "\\$computer\$folders_on" -Recurse -Force
Вопрос:
Т.к. есть ключ
-Force
, то должна быть перезапись файлов.Но если на ПК назначения уже есть папка $folders_on, то всё будет копироваться в подпапку $folders_on.
Т.е. если конечная папка например называется 123, то при её наличии в пути назначения, всё будет копироваться в 123\123,
т.е. если на ПК источнике есть папка
С:\123
и на ПК назначения есть папкаC:\123
, ($folders_on = "C:\123"
), то при запуске скрипта всё копируется на ПК назначения в C:\123\123.Как сделать так, чтобы копировалось в C:\123 c перезаписью? Не в подпапку C:\123\123.
Как сделать так, чтобы папка $folders_on перезаписывалась и не было копирования в подпапку $folders_on?
UPD
Ошибся в предыдущем коде:
Copy-Item «$folders_on» -Destination «\\$computer\$folders_in» -Recurse -Force
где
$folders_on = 'C:\123'
$folders_in = 'C$\123
Вопрос 2.
А если копировать так (со звёздочкой):
Copy-Item "С:\123\*" -Destination "\\$computer\C$\123" -Recurse -Force
, то на ПК назначения создаётся файл в папке C:\123 c именем 123 без расширения, хотя это должна быть папка с фалами. В чём может быть ошибка?Народ, а есть способ скопировать файл с помощью powershell на пару десятков машин в сети разом? либо перечислив их через запятую или указав файл от куда брать имена машин?