Powershell - FTP-клиент

Записка от 25.03.2014

Для того, чтобы использовать 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.
7z.png Скачивание файлов с FTP сервера с помощью PowerShell

 

Вверх