Powershell copy item обработка ошибок

PowerShell командлет Copy-Item используется для копирования файлов между локальными, сетевыми каталогами или между компьютерами по сети через WinRM. Командлет Copy-Item предоставляет большое количество опций, которые можно использовать в разных сценариях копирования файлов и каталогов (по своим возможностям этот командлет почти не уступает утилите robocopy). Например:

  • перезапись файлов (override)
  • фильтрация по имени/шаблону
  • исключение по имени/шаблону
  • Verbose режим
  • Копирование файлов с/на удаленные компьютеры

Начнем с простых примеров использования Copy-Item и будем переходить к более сложным.

Содержание:

  • Копирование файлов и каталогов
  • Копирование с заменой и копирование с заменой read-only файлов
  • Копирование с фильтрацией по шаблону
  • Исключение файлов при копировании
  • Копирование файлов на удаленный компьютер по сети
  • Ключ PassThru
  • Ключ Verbose
  • Несколько полезных скриптов с Copy-Item

Копирование файлов и каталогов

Чтобы скопировать один файл 1.txt из каталога C:SourceFolder в F:DestFolder, выполните:

Copy-Item -Path "C:SourceFolder1.txt" -Destination "F:DestFolder1.txt"

Можно использовать сокращенный синтаксис командлета, пропустив указание параметров Path и Destination:

cpi "C:SourceFolder1.txt" "F:DestFolder1.txt"

Теперь скопируем каталог C:SourceFolderfolder в F:DestFolderfolder. В папке folder находится файл 1.txt. Обратите внимание что без ключа –Recurse, папка folder копируется без содержимого:

Copy-Item -Path "C:SourceFolderfolder" -Destination "F:DestFolderfolder" -Recurse

С помощью Copy-Item также можно просто объединить файлы из несколько директорий в одну (слияние директории), для этого нужно перечислить директории в ключе –Path:

Copy-Item -Path "C:SourceFolder*", "C:SourceFolder2*", "C:SourceFolder3*" -Destination "F:DestFolder"

Копирование с заменой и копирование с заменой read-only файлов

Copy-Item по умолчанию при копировании заменяет файлы в целевом каталоге. Никаких дополнительных параметров указывать не нужно. При копировании каталога, если нужно заменить каталог в целевой папке, нужно использовать ключ –Force, иначе будет ошибка “Элемент folder с указанным именем уже существует — DirectoryExists”.

copy-item DirectoryExists

Для перезаписи файла с атрибутом read-only, нужно использовать ключ -Force. Если его не использовать, вы получите ошибку “отказано в доступе по пути… CopyFileInfoItemUnauthorizedAccessError”.

copy-item CopyFileInfoItemUnauthorizedAccessError

Чтобы скопировать файл с перезаписью файла с read-only атрибутом используйте параметр Force.

Copy-Item -Path "C:SourceFolder1.txt" -Destination "F:DestFolder1.txt" -Force

Совет. Чтобы не путаться, ключ –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

Для примера возьмём такую структуру файлов:

source

Выполним копирование командой:

Copy-Item -Path "C:SourceFolderfol*" -Destination "F:DestFolder"

Результат в F:DestFolder

copy-item replace

Теперь чистим папку назначения и выполняем:

Copy-Item -Path "C:SourceFolderfolder[0-3]" -Destination "F:DestFolder"

Результат:

result

Папка без цифры в окончании не скопировалась, потому что 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.

Примечание. Доступность WSMan на удаленном компьютере можно проверить с помощью командлета Test-WSMan.

Test-WSMan -ComputerName testnode1

Test-WSMan

Если WSMan не настроен, вы можете выполнить его быструю конфигурацию. Для этого откройте командную строку с правами администратора и выполните
winrm quickconfig

winrm quickconfig

Также можно копировать и через обычные сетевые SMB шары, для этого просто используйте UNC формат сетевого пути.

Copy-Item -Path "C:SourceFolder*" -Destination "\testnode1C$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 "\testnode1C$copy_tutorial" -PassThru

Переменная
$items
будет содержать список скопированных файлов, с которым вы можете работать дальше.Это значит что вы можете напрямую работать с этими файлами. Например выполнив команду
Remove-Item $items[0]
, вы удалите директорию folder.

copy-item passthru

Ключ Verbose

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

Copy-Item -Path "C:SourceFolder*.txt" -Destination "F:DestFolder" -Recurse -Force -Verbose

copy-item 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 также является мощным инструментом для написания скриптов.

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

Copy-Item : Access to the path 'E:BackupLocDOzOLD_Under Review for NOT USED_keep for now2006-06N.doc' is denied.
At C:UsersmeDocumentspowershellFilesBackup.ps1:13 char:4
+    Copy-Item -Path $SourcePath -Destination $DestinationPath -Force - ...
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (N.doc:FileInfo) [Copy-Item], UnauthorizedAccessException
    + FullyQualifiedErrorId : CopyDirectoryInfoItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.CopyItemCommand

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

Кроме того, преодоление этих ошибок копирования занимает очень много времени. Если бы я мог избежать попыток скопировать эти файлы, это было бы намного быстрее. Там, вероятно, 200 из этих файлов, которые заархивированы.

Однако я копирую папку, а не имена файлов по отдельности. Есть те, которые не заархивированы в этой папке. Там нет плана, чтобы очистить их. Я пытаюсь определить, когда происходит ошибка, но она достигает моей точки останова только в том случае, если оператор $error.Exception -ne $null после того, как он записывает ошибки на экран и принимает их навсегда (см. Комментарий).

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

Я смотрел на проверку ошибок во время копирования, но я не вижу, как применить это к моей проблеме.

Это метод копирования:

function CopyFileToFolderUNC($SourcePath, $DestinationPath){
   if(-Not (Test-Path $SourcePath)) 
   {
      $global:ErrorStrings.Add("Exception: No such path, $SourcePath;;  ")
      write-output  "++ Error: An error occured during copy operation. No such path, $SourcePath ++"
   }
   Copy-Item -Path $SourcePath -Destination $DestinationPath -Force -Recurse -errorVariable errors 
   foreach($error in $errors)
   {
        if ($error.Exception -ne $null)
        {
            $global:ErrorStrings.Add("Exception: $($error.Exception);;  ")
            write-output  "++ Error: An error occured during copy operation. Exception: $($error.Exception) ++" #this breakpoint is hit after giving errors on screen and taking a long time/failing to copy files it can't reach
        }
        write-output  "Error: An error occured during copy operation. Exception: $($error.Exception)"
    }
}

Это моя последняя попытка, основанная на том, что было предложено @theo, но она пытается скопировать файлы, которые я не проверял, для файла, который я могу скопировать, только каталог над ним:

function CopyFileToFolderUNC($SourcePath, $DestinationPath, $exclude){
   if(-Not (Test-Path $SourcePath )) #-PathType Container
   {
      $global:ErrorStrings.Add("Exception: No such path, $SourcePath;;  ")
      write-output  "++ Error: An error occured during copy operation. No such path, $SourcePath ++"
   }
   #$tempFileName = [System.IO.Path]::GetFileName($SourcePath)
   #$tempDestFileNamePath = "$DestinationPath$tempFileName"
   Get-ChildItem -Path $SourcePath -Recurse -Force | ForEach {$_} {
      #test if maybe we are dealing with an off-line file here
      #or use the enum name 'Offline'
      # or use the numeric value: 4096
      #$oldAttribs = $null
      $attr = $_.Attributes.value__
      write-output  "++ $_ $attr ++"
      if (($_.Attributes -eq [System.IO.FileAttributes]::Offline) -or ($_.Attributes.value__ -eq "4096")) {
         $_.Attributes=[System.IO.FileAttributes]::Normal
         #$oldAttribs = $_.Attributes
         #make it a 'normal' file with only the Archive bit set
         #$_.Attributes = [System.IO.FileAttributes]::Archive
         #log that the file was an issue and copy the other ones
         $global:ErrorStrings.Add("Found offline file in backup dir, $_. Logging info and not copying this file. Offline. Please investigate.;;  ")
         write-output  "++ Error: An error occured during copy operation. No such path or file, Offline $_ ++"
      } #if
      elseif(($_.Attributes -eq [System.IO.Fileattributes]::Archive) -or ($_.Attributes.value__ -eq "32")) {
         $global:ErrorStrings.Add("Found offline file in backup dir, $_. Logging info and not copying this file. Archive. Please investigate.;;  ")
         write-output  "++ Error: An error occured during copy operation. No such path or file, Archive $_ ++"
      } #elseif
      elseif(($_.Attributes -eq [System.IO.Fileattributes]::SparseFile) -or ($_.Attributes.value__ -eq "512")) {
         $global:ErrorStrings.Add("Found offline file in backup dir, $_. Logging info and not copying this file. SparseFile. Please investigate.;;  ")
         write-output  "++ Error: An error occured during copy operation. No such path or file, SparseFile $_ ++"
      } #elseif
      elseif(($_.Attributes -eq [System.IO.Fileattributes]::ReparsePoint) -or ($_.Attributes.value__ -eq "1024")) {
         $global:ErrorStrings.Add("Found offline file in backup dir, $_. Logging info and not copying this file. ReparsePoint. Please investigate.;;  ")
         write-output  "++ Error: An error occured during copy operation. No such path or file, ReparsePoint $_ ++"
      } #elseif
      else {

         #the file is not or no longer off-line, so proceed with the copy
         $_ | Copy-Item -Destination $DestinationPath -Force -Recurse -ErrorVariable errors
         foreach($error in $errors)
         {
           if ($error.Exception -ne $null)
           {
               $global:ErrorStrings.Add("Exception: $($error.Exception);;  ")
               write-output  "++ Error: An error occured during copy operation. Exception: $($error.Exception) ++"
           }
           write-output  "Error: An error occured during copy operation. Exception: $($error.Exception)"
         }
      } #else
      #if ($oldAttribs) {
      #   $_.Attributes = $oldAttribs
      #}
   } #Get-ChildItem

Например, я тестирую каталог в \drivefolderFormsC Forms и он говорит, что это хороший атрибут «16», но в этом каталоге есть файл, который копия пытается скопировать в мою папку dir, и я вижу, что он имеет это для атрибутов: file.pdf Архив, SparseFile, ReparsePoint, Offline. Но я не проверяю этот файл, последней вещью, для которой я проверял атрибуты, был каталог, в котором он находится.

Только вышел из отпуска, и уже аврал на работе, но время для PowerShell я всё равно выкроил 😉

Вот например комрад Camelot подкинул следующую, интересную задачку: Скопировать n файлов, и вывести список нескопированных в текстовый файл (ну либо предварительно попробовать скопировать неудачников еще разок).

Copy-Item .test* c:windowssystem32 -ErrorAction "silentlyContinue" -ErrorVariable Failed

Этой командой файлы будут скопированы из одного места в другое, при этом ошибки не будут выдаваться на экран, но будут помещены в массив $Failed.

Теперь посмотрим содержимое одного из элементов этого массива с помощью команды Format-List с ключем -Force:

$Failed[0] | fl * -force

Станет видно что нам необходимо свойство TargetObject в котором содержится объект файла который не удалось скопировать. Поместим эти объекты в переменную $Files

$Files = $Failed | foreach {$_.TargetObject}

Ну и теперь можно поступать с ними по своему усмотрению, либо просто попробовать скопировать их еще раз:

Copy-Item $Files c:windowssystem32

либо поместить их полные пути в текстовый файл:

$Files | foreach {$_.fullname} | Set-Content log.txt

Вот собственно и всё 🙂

  • Remove From My Forums
  • Question

  • When I used Copy-Item to copy a folder from my local machine to a remote machine, I got the following error. Some files are not copied. But all the files are copied with no error when I copied them by using copy/paste in Windows Explorer. Any suggustion?
    Thanks

     Copy-Item : The specified network name is no longer available.

    At H:ScriptsPowerShellRemoteCopyFiles.ps1:33 char:14
    +     Copy-Item <<<<  $Source $Path -recurse -force
        + CategoryInfo          : WriteError: (RICHED20.DLL:FileInfo) [Copy-Item], IOException
        + FullyQualifiedErrorId : CopyDirectoryInfoItemIOError,Microsoft.PowerShell.Commands.CopyItemCommand
     

По умолчанию Copy-item ничего не возвращает. Есть вариант узнать как прошло копирование, это проверить переменную $error

Copy-item $From $To

IF ($Error[0].CategoryInfo.Activity -eq ‘Copy-Item’)
{
$inf = «==ERROR== Копирование » + $To + » не удачно » + $Error[0]
Write-host $inf -foreground «RED»
}
ELSE
{
$inf = «Копирование » + $To + » Прошло успешно»
Write-host $inf -foreground «green»
}

Есть и другой вариант, смотреть ловушки(trap)

Про ловушки подробней тут и тут

Function Copy-check($From , $To)
{
trap {

$err = «TRAP ###ERROR### » + $error[0] #.FullyQualifiedErrorId
write-host From_trap=== $err
return $err
}

Copy-item $From $To -Recurse -ea 1

Return 0

}

Copy-check $From $To

Об авторе Alex

Работаю Администратором. В основном Windows. Специализируюсь на Hyper-V

Запись опубликована в рубрике Powershell с метками Powershell. Добавьте в закладки постоянную ссылку.

Понравилась статья? Поделить с друзьями:
  • Powerpoint ошибка при запуске приложения 0xc0000142
  • Powerpoint выдает ошибку при открытии презентации
  • Powerpnt exe ошибка при запуске приложения 0xc0000142
  • Powermill ошибка файла авторизации paf error 52 line 17
  • Powermill 2016 ошибка постпроцессора broken connection