Поиск по сайту:

Как загружать файлы по FTP с помощью PowerShell


Протокол передачи файлов (FTP) — это распространенная служба, используемая для передачи файлов между клиентами и серверами. Часто полезно автоматизировать эту передачу файлов, и сценарии PowerShell могут пригодиться для ускорения этого процесса.

Как использовать FTP в PowerShell

В PowerShell существует несколько различных способов передачи данных по FTP.

Самый простой способ — использовать WebClient.UploadFile. PowerShell — это объектно-ориентированный язык сценариев, и у вас есть полный доступ к стандартным библиотекам .NET с помощью New-Object. При этом вы можете создать новый WebClient, установить для него учетные данные и загрузить файл.

$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")

Это будет работать нормально, но не сможет обрабатывать зашифрованные запросы TLS/SSL или выполнять «активные» FTP-передачи. Использование FtpWebRequest, описанное ниже, решит эту проблему.

Однако не рекомендуется хранить имя пользователя и пароль в сценарии, особенно если этот сценарий фиксируется в общем репозитории Git. Вместо этого вы можете установить переменные среды, такие как FtpUsername , и получить к ним доступ в скрипте.

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"

Превращение этого в функцию также позволит вам легко выполнять несколько переводов, вызывая функцию с разными параметрами.

Расширенные возможности FTP-передачи с помощью PowerShell

Если вам нужно больше контроля, вы должны использовать FtpWebRequest. Это будет поддерживать передачу TLS, а также позволит вам отключить пассивный режим. Самый простой способ его использования — открыть файловый поток и скопировать его в 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"

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

Отправка SFTP-переводов с помощью Posh-SSH

SFTP — это альтернативный FTP-протокол, работающий через SSH. Его немного сложнее использовать, чем обычный FTP, так как вы не можете просто отправить имя пользователя и пароль, и он не поддерживается родной оболочкой PowerShell.

Вам потребуется установить пакет Posh-SSH для связи по SFTP:

Install-Module -Name Posh-SSH

Затем вы сможете начать новый сеанс, используя новый объект учетных данных. Это работает так же, как передача веб-запросов, за исключением того, что вам также нужно будет закрыть сеанс в конце.

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) }

Отправка огромных файлов с индикатором выполнения в PowerShell

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

$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()