Для того, чтобы использовать 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.
