Copiar arquivos eficientemente com Copy-Item do PowerShell: Um Guia Completo

Copiando arquivos. Não é sexy, mas precisa ser feito. Na GUI, copiamos e colamos com a área de transferência, mas no PowerShell temos um cmdlet chamado Copy-Item.

Comandos para copiar arquivos existem há muito tempo em todas as linguagens de shell. Na terra do PowerShell, a maneira mais popular de obter uma cópia de um arquivo ou pasta em seu script PowerShell de A para B é usando o cmdlet Copy-Item. Este cmdlet nos permite copiar um arquivo e uma pasta, dando-nos a capacidade de percorrer arquivos em uma pasta, usar curingas para selecionar os arquivos que precisamos copiar e até mesmo usar PowerShell Remoting para uma cópia de arquivo!

Esse cmdlet faz parte dos cmdlets do provedor PowerShell. É um cmdlet genérico reconhecido pelo seu substantivo Item. A maioria desses cmdlets de provedor pode ser usada em diferentes provedores, mas em quase 10 anos usando PowerShell, só vi o Copy-Item sendo usado com o provedor de sistema de arquivos.

Ao usar este cmdlet, o PowerShell permite que um desenvolvedor copie arquivos e pastas de várias maneiras diferentes.

Uso Básico

Na sua forma mais básica, o cmdlet Copy-Item copia um único arquivo de A para B, usando o parâmetro Path como o caminho do arquivo de origem e o parâmetro Destination como o caminho da pasta de destino.

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 

Este cmdlet também pode copiar pastas vazias. Vou listar o item na pasta C:\EmptyFolder e depois copiá-los.

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 

Talvez haja um arquivo somente leitura na pasta. Por padrão, Copy-Item não o substituirá. Para forçar a substituição, basta adicionar o parâmetro Force.

Ficando Seletivo com Copy-Item

Além de copiar um único arquivo ou pasta, também podemos copiar todo o conteúdo de uma pasta. O parâmetro Path de Copy-Item aceita caracteres curinga como o asterisco para corresponder a um ou mais caracteres ou o ponto de interrogação para corresponder apenas a um único caractere.

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

Mesclando Múltiplas Pastas Juntas

Outra característica legal do Copy-Item é sua capacidade de copiar várias pastas juntas ao mesmo tempo. Passando múltiplos caminhos para o parâmetro Path, Copy-Item irá analisar cada um, copiar tanto a pasta quanto o(s) arquivo(s) dependendo do caminho e “mesclar” todos eles no único destino.

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

Copiando Arquivos de Forma Recursiva

O mais provável é que você não tenha sorte e tenha todos os arquivos em uma única pasta sem subpastas também. Normalmente nos deparamos com situações em que temos muitas subpastas na pasta principal com arquivos nelas também que gostaríamos de copiar. Usando o parâmetro Recurse em Copy-Item, ele prontamente olhará em cada subpasta e copiará todos os arquivos e pastas em cada uma recursivamente.

Observe aqui que estou encaminhando arquivos e pastas de Get-ChildItem diretamente para Copy-Item. Copy-Item tem suporte para pipeline!

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

Vantagens de usar o parâmetro PassThru

Muitos cmdlets no PowerShell possuem um parâmetro PassThru. Cmdlets que normalmente não retornam nada podem retornar os objetos que estão manipulando usando o parâmetro PassThru. Este cmdlet não é diferente. Quando comecei a escrever scripts, nunca usei esse parâmetro porque não achava que precisava.

Por exemplo, se eu quisesse copiar um arquivo para um local remoto e depois referenciar esse arquivo mais tarde no meu script, eu faria algo assim:

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

Esse método funciona, mas pode ser melhor. Em vez de definir uma variável para o caminho remoto, por que não simplesmente capturar o objeto retornado pelo cmdlet Copy-Item ao usar o parâmetro PassThru? Os objetos retornados sempre terão o caminho do arquivo de destino.

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

Copiando arquivos usando uma sessão de remoting do PowerShell

Uma funcionalidade legal que veio com o PowerShell v5 é a capacidade desse cmdlet de não usar o protocolo SMB padrão para transferir um arquivo, mas sim usar o WinRM e uma sessão remota do PowerShell. Ao usar o parâmetro Session, Copy-Item utiliza uma sessão do PowerShell existente e transfere os arquivos dessa maneira. Isso é uma ótima maneira de contornar firewalls e, quando a comunicação da sessão está criptografada, também é uma camada extra de segurança.

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

Nós poderíamos ter copiado o arquivo File.txt usando SMB e esperado que o compartilhamento de administração C$ estivesse disponível e usado o caminho de destino \\WEBSRV1\c$. Como usamos o parâmetro ToSession em vez disso, o caminho de destino será sempre o caminho local ao computador em que a sessão remota está sendo executada.

Resumo

O cmdlet Copy-Item é um daqueles cmdlets essenciais do PowerShell que você vai usar repetidamente. No PowerShell, copie arquivos, pastas de várias maneiras diferentes com sua simplicidade, mas poder especialmente com sua capacidade de usar curingas, para mesclar várias pastas de arquivos juntas e para usar sessões de Remoting do PowerShell existentes!

Leitura Adicional

Copy-item

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