Como fazer upload de arquivos via FTP com o PowerShell

0
38


File Transfer Protocol (FTP) é um serviço comum usado para transferir arquivos entre clientes e servidores. Muitas vezes, é útil automatizar essas transferências de arquivos, e os scripts do PowerShell podem ser úteis para acelerar esse processo.

Como usar o FTP no PowerShell

Existem algumas maneiras diferentes de realizar transferências FTP no PowerShell.

O mais fácil é usar WebClient.UploadFile. O PowerShell é uma linguagem de script orientada a objetos e tem acesso total a .NET bibliotecas padrão com New-Object. Com isso, você pode criar um novo WebClientdefina as credenciais para ele e carregue um arquivo.

$client = New-Object System.Net.WebClient
$client.Credentials = New-Object System.Net.NetworkCredential("username", "password")
$client.UploadFile("ftp://example.com/path/archive.zip", "C:archive.zip")

Isso funcionará bem, mas não poderá lidar com solicitações TLS/SSL criptografadas ou realizar transferências FTP “ativas”. Vestindo FtpWebRequestcoberto abaixo resolverá este problema.

No entanto, não é uma boa prática armazenar seu nome de usuário e senha em um script, especialmente se esse script estiver sendo enviado para um repositório Git compartilhado. Em vez disso, você pode definir variáveis ​​de ambiente como FtpUsername e acessá-los no script.

function uploadToFTPServer($remote, $local) {
    $client = New-Object System.Net.WebClient
    $client.Credentials = New-Object System.Net.NetworkCredential($Env:FtpUsername, $Env:FtpPassword)
    $client.UploadFile($remote, $local)
}

uploadToFTPServer "ftp://example.com/path/archive.zip", "C:archive.zip"

Converter isso em uma função também permitirá que você faça várias transferências facilmente chamando a função com parâmetros diferentes.

Transferências avançadas de FTP com PowerShell

Se você precisar de mais controle, você deve usar FtpWebRequest. Isso oferecerá suporte a transferências TLS e também permitirá que você desative o modo passivo. A maneira mais fácil de usá-lo é abrir um fluxo de arquivos e copiá-lo para o fluxo de FTP.

function uploadToFTPServer($remote, $local) {
    $request = [System.Net.FtpWebRequest]::Create($remote)
    $request.Credentials = New-Object System.Net.NetworkCredential($Env:FtpUsername, $Env:FtpPassword)
    $request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
    $request.UsePassive = $true

    $fileStream = [System.IO.File]::OpenRead($local)
    $ftpStream = $request.GetRequestStream()

    $fileStream.CopyTo($ftpStream)

    $ftpStream.Dispose()
    $fileStream.Dispose()
}

uploadToFTPServer "ftp://example.com/archive.zip" "C:archive.zip"

Como ele usa fluxos de arquivos e não lê todos os bytes, isso tem a vantagem de funcionar melhor com grandes transferências de arquivos.

Enviando transferências SFTP com Posh-SSH

O SFTP é um protocolo alternativo de FTP que opera em cima do SSH. É um pouco mais complicado de usar do que o FTP normal, já que você não pode simplesmente enviar um nome de usuário e senha, e ele não oferece suporte ao PowerShell nativo.

Você precisará instalar o Posh-SSH pacote para se comunicar via SFTP:

Install-Module -Name Posh-SSH

Você poderá então iniciar uma nova sessão, usando um novo objeto de credencial. Isso funciona da mesma maneira que as transferências de solicitações da Web, exceto que você também precisará fazer logout no final.

Import-Module Posh-SSH

$Password = ConvertTo-SecureString $Env:FtpPassword -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($Env:FtpUsername, $Password)

$FilePath = "C:archive.zip"
$SftpPath="/folder"

$ThisSession = New-SFTPSession -ComputerName '1.2.3.4' -Credential $Credential

Set-SFTPFile -SessionId ($ThisSession).SessionId -LocalFile $FilePath -RemotePath $SftpPath
Get-SFTPSession | % { Remove-SFTPSession -SessionId ($_.SessionId) }

Enviando arquivos enormes com uma barra de progresso no PowerShell

Usando o fluxo de arquivos CopyTo é simples, mas para transferências longas você pode querer algum tipo de monitoramento do progresso. Isso é um pouco complicado de adicionar, pois você mesmo terá que copiar os fluxos, mas funciona bem com o seguinte script:

$request = [Net.WebRequest]::Create("ftp://example.com/path/archive.zip")
$request.Credentials =
New-Object System.Net.NetworkCredential($Env:FtpUsername, $Env:FtpPassword)
$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile

$fileStream = [System.IO.File]::OpenRead("C:archive.zip")
$ftpStream = $request.GetRequestStream()

$buffer = New-Object Byte[] 10240
while (($read = $fileStream.Read($buffer, 0, $buffer.Length)) -gt 0)
{
    $ftpStream.Write($buffer, 0, $read)
    $pct = ($fileStream.Position / $fileStream.Length)
    Write-Progress `
        -Activity "Uploading" -Status ("{0:P0} complete:" -f $pct) `
        -PercentComplete ($pct * 100)
}

$ftpStream.Dispose()
$fileStream.Dispose()