Для того, чтобы использовать PowerShell как FTP-клиент, можно использовать .Net функции FtpWebRequest и WebRequest.
В примере ниже показано, как использовать PowerShell для получения списка содержимого FTP-папки.
#Исходные данные $FTPresource = "ftp://ftpserver.domain.com/upload/" $FTPuser = "UploadUser" $FTPpassword = "qwer1234" $FTPmode = "Unknown" $ItemsCollection = @() # Настрока подключения к ресурсу # Путь к ресурсу $FTPrequest = [System.Net.FtpWebRequest]::Create($FTPresource) # Время ожидани ответа (msec - по умолчанию без ограничений) $FTPrequest.Timeout = 3000 # Время ожидания записи (msec - по умолчанию 300000 - 5 мин) $FTPrequest.ReadWriteTimeout = 1000 # Учетные данные $FTPrequest.Credentials = New-Object System.Net.NetworkCredential($FTPuser, $FTPpassword) # Использовать метод ListDirectoryDetails $FTPrequest.Method = [System.Net.WebRequestMethods+FTP]::ListDirectoryDetails # Не использовать пассивный режим $FTPrequest.UsePassive = $False # Использовать шифрование SSL $FTPrequest.EnableSSL = $True # Не использовать прокси-сервер $FTPrequest.Proxy = $Null # Не держать соединение открытым $FTPrequest.KeepAlive = $False # Принимать все сертификаты [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} # Подключение к ресурсу Try { $FTPresponse = $FTPrequest.GetResponse() } Catch { Write-Host "FAILED: $_" Exit } # Считывание ответа сервера на использованный метод [System.IO.StreamReader]$Stream = $FTPresponse.GetResponseStream() # Чтение первой строки ответа Try { [string]$Line = $Stream.ReadLine() } Catch { $Line = $null } # Разбор строки и считывание остальных строк ответа While ($Line) { If($FTPmode -eq "Compatible" -or $FTPmode -eq "Unknown") { $null, [string]$IsDirectory, [string]$Flag, [string]$Link, [string]$UserName, ` [string]$GroupName, [string]$Size, [string]$Date, [string]$Name = ` [regex]::split($Line,'^([d-])([rwxt-]{9})\s+(\d{1,})\s+([.@A-Za-z0-9-]+' + ` ')\s+([A-Za-z0-9-]+)\s+(\d{1,})\s+(\w+\s+\d{1,2}\s+\d{1,2}:?\d{2})\s+' + ` '(.+?)\s?$',"SingleLine,IgnoreCase,IgnorePatternWhitespace") If($IsDirectory -eq "" -and $FTPmode -eq "Unknown") { $FTPmode = "IIS6" } Else { $FTPmode = "Compatible" #IIS7/Linux } If($FTPmode -eq "Compatible") { $DatePart = $Date -split "\s+" $NewDateString = "$($DatePart[0]) $('{0:D2}' -f [int]$DatePart[1]) $($DatePart[2])" Try { If($DatePart[2] -match ":") { $Month = ([DateTime]::ParseExact($DatePart[0],"MMM",` [System.Globalization.CultureInfo]::InvariantCulture)).Month If((Get-Date).Month -ge $Month) { $NewDate = [DateTime]::ParseExact($NewDateString, ` "MMM dd HH:mm",[System.Globalization.CultureInfo]::InvariantCulture) } Else { $NewDate = ([DateTime]::ParseExact($NewDateString, ` "MMM dd HH:mm",[System.Globalization.CultureInfo]::InvariantCulture)).AddYears(-1) } } Else { $NewDate = [DateTime]::ParseExact($NewDateString, ` "MMM dd yyyy",[System.Globalization.CultureInfo]::InvariantCulture) } } Catch { } } } If($FTPmode -eq "IIS6") { $null, [string]$NewDate, [string]$IsDirectory, [string]$Size, [string]$Name = ` [regex]::split($Line,'^(\d{2}-\d{2}-\d{2}\s+\d{2}:\d{2}[AP]M)\s+*\s+' + ` '(\d*)\s+(.+).*$',"SingleLine,IgnoreCase,IgnorePatternWhitespace") If($IsDirectory -eq "") { $IsDirectory = "-" } } # Разбор значения размера Switch($Size) { {[int]$_ -lt 1024} { $HFSize = $_+"B"; break } {[System.Math]::Round([int]$_/1KB,0) -lt 1024} { $HFSize = ` [String]([System.Math]::Round($_/1KB,0))+"KB"; break } {[System.Math]::Round([int]$_/1MB,0) -lt 1024} { $HFSize = ` [String]([System.Math]::Round($_/1MB,0))+"MB"; break } {[System.Math]::Round([int]$_/1GB,0) -lt 1024} { $HFSize = ` [String]([System.Math]::Round($_/1GB,0))+"GB"; break } {[System.Math]::Round([int]$_/1TB,0) -lt 1024} { $HFSize = ` [String]([System.Math]::Round($_/1TB,0))+"TB"; break } } #End Switch If($IsDirectory -eq "d" -or $IsDirectory -eq "DIR") { $HFSize = "" } $LineObj = New-Object PSObject -Property @{ Dir = $IsDirectory Right = $Flag Ln = $Link User = $UserName Group = $GroupName Size = $HFSize SizeInByte = $Size OrgModifiedDate = $Date ModifiedDate = $NewDate Name = $Name } $LineObj.PSTypeNames.Clear() $LineObj.PSTypeNames.Add('PSFTP.Item') If($LineObj.Dir) { $ItemsCollection += $LineObj } $Line = $Stream.ReadLine() } # Закрытие подключение к ресурсу $FTPresponse.Close() # Возврат результата $ItemsCollection
Очень хороший модуль по FTP-скриптам можно скачать с сайта TechNet. В этом модуле содержатся скрипты по работе с FTP-ресурсом: просмотр содержимого, создание папок, скачивание файлов, закачивание файлов, удаление файлов и т.п.
Примечание. В скриптах модуля PSFTP есть небольшие недочеты. Например, я столкнулся с проблемой, что один из FTP-серверов не поддерживает команду Size, а эта команда использовалась во всех скриптах по работе с файлами. Также были проблемы с прокси-сервером, игнорирование которого не настраивалось в скриптах.
Во вложении к заметке находится полный PowerShell скрипт, которым я скачиваю файлы с внешнего FTP-сервера на локальный сервер компании. Этот скрипт ставится в расписание Windows на сервере-приемнике файлов.
Примечание. В моем скрипте для получения списка файлов папки используется абсолютный путь к папке FTP-сервера, так как домашняя папка используемого пользователя отличается от нужной. Чтобы переключиться с относительных путей на абсолютные, используется комбинация "%2f" в пути ресурса, например ftp://ftpserver.domain.com/%2fhome/ftp/upload.