PowerShell Подключение к FTP-серверу и получение файлов
$ftpServer = "ftp.example.com"
$username ="validUser"
$password ="myPassword"
$localToFTPPath = "C:\ToFTP"
$localFromFTPPath = "C:\FromFTP"
$remotePickupDir = "/Inbox"
$remoteDropDir = "/Outbox"
$SSLMode = [AlexPilotti.FTPS.Client.ESSLSupportMode]::ClearText
$ftp = new-object "AlexPilotti.FTPS.Client.FTPSClient"
$cred = New-Object System.Net.NetworkCredential($username,$password)
$ftp.Connect($ftpServer,$cred,$SSLMode) #Connect
$ftp.SetCurrentDirectory($remotePickupDir)
$ftp.GetFiles($localFromFTPPath, $false) #Get Files
Это script, который я получил для импорта файлов с FTP-сервера.
Однако я не уверен, что такое remotePickupDir
и этот script правильный?
Ответы
Ответ 1
Путь каталога удаленного выбора должен быть точным путем на ftp-сервере, к которому вы пытаетесь получить доступ.
вот script для загрузки файлов с сервера.
вы можете добавить или изменить с помощью SSLMode..
#ftp server
$ftp = "ftp://example.com/"
$user = "XX"
$pass = "XXX"
$SetType = "bin"
$remotePickupDir = Get-ChildItem 'c:\test' -recurse
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)
foreach($item in $remotePickupDir){
$uri = New-Object System.Uri($ftp+$item.Name)
#$webclient.UploadFile($uri,$item.FullName)
$webclient.DownloadFile($uri,$item.FullName)
}
Ответ 2
Библиотека AlexFTPS, использованная в этом вопросе, кажется мертвой (не обновлялась с 2011 года).
Без внешних библиотек
Кроме того, вы можете попробовать реализовать это без какой-либо внешней библиотеки. Но, к сожалению, ни .NET Framework, ни PowerShell не имеют явной поддержки загрузки всех файлов в каталоге (разрешают только рекурсивные загрузки файлов).
Вы должны реализовать это самостоятельно:
- Перечислите удаленный каталог
- Повторяйте записи, загружая файлы (и, возможно, повторяясь в подкаталоги - перечисляя их снова и т.д.)
Сложной задачей является выявление файлов из подкаталогов. Нет никакого способа сделать это в портативном виде с помощью .NET Framework (FtpWebRequest
или WebClient
). К сожалению,.NET Framework не поддерживает команду MLSD
, которая является единственным переносимым способом получения списка каталогов с атрибутами файлов в протоколе FTP. См. также Проверка, является ли объект на FTP-сервере файлом или каталогом.
Ваши варианты:
- Если вы знаете, что каталог не содержит никаких подкаталогов, используйте метод
ListDirectory
(команда NLST
FTP) и просто загрузите все "имена" в виде файлов.
- Выполните операцию с именем файла, которая наверняка не удастся для файла и удастся для каталогов (или наоборот). То есть Вы можете попробовать загрузить "имя".
- Возможно, вам повезет, и в вашем конкретном случае вы можете отличить файл из каталога по имени файла (т.е. все ваши файлы имеют расширение, а подкаталоги - нет)
- Вы используете длинный список каталогов (метод
LIST
= метод ListDirectoryDetails
) и пытаетесь проанализировать специфичный для сервера список. Многие FTP-серверы используют листинг в стиле * nix, где вы идентифицируете каталог по d
в самом начале записи. Но многие серверы используют другой формат. В следующем примере используется этот подход (в формате * nix)
function DownloadFtpDirectory($url, $credentials, $localPath)
{
$listRequest = [Net.WebRequest]::Create($url)
$listRequest.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails
$listRequest.Credentials = $credentials
$lines = New-Object System.Collections.ArrayList
$listResponse = $listRequest.GetResponse()
$listStream = $listResponse.GetResponseStream()
$listReader = New-Object System.IO.StreamReader($listStream)
while (!$listReader.EndOfStream)
{
$line = $listReader.ReadLine()
$lines.Add($line) | Out-Null
}
$listReader.Dispose()
$listStream.Dispose()
$listResponse.Dispose()
foreach ($line in $lines)
{
$tokens = $line.Split(" ", 9, [StringSplitOptions]::RemoveEmptyEntries)
$name = $tokens[8]
$permissions = $tokens[0]
$localFilePath = Join-Path $localPath $name
$fileUrl = ($url + $name)
if ($permissions[0] -eq 'd')
{
if (!(Test-Path $localFilePath -PathType container))
{
Write-Host "Creating directory $localFilePath"
New-Item $localFilePath -Type directory | Out-Null
}
DownloadFtpDirectory ($fileUrl + "/") $credentials $localFilePath
}
else
{
Write-Host "Downloading $fileUrl to $localFilePath"
$downloadRequest = [Net.WebRequest]::Create($fileUrl)
$downloadRequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
$downloadRequest.Credentials = $credentials
$downloadResponse = $downloadRequest.GetResponse()
$sourceStream = $downloadResponse.GetResponseStream()
$targetStream = [System.IO.File]::Create($localFilePath)
$buffer = New-Object byte[] 10240
while (($read = $sourceStream.Read($buffer, 0, $buffer.Length)) -gt 0)
{
$targetStream.Write($buffer, 0, $read);
}
$targetStream.Dispose()
$sourceStream.Dispose()
$downloadResponse.Dispose()
}
}
}
Используйте такую функцию, как:
$credentials = New-Object System.Net.NetworkCredential("user", "mypassword")
$url = "ftp://ftp.example.com/directory/to/download/"
DownloadFtpDirectory $url $credentials "C:\target\directory"
Код переведен с моего примера С# в С# Загрузка всех файлов и подкаталогов через FTP.
Использование сторонней библиотеки
Если вы хотите избежать проблем с синтаксическим анализом форматов списков каталогов, специфичных для сервера, используйте стороннюю библиотеку, которая поддерживает команду MLSD
и/или анализирует различные форматы списков LIST
. И в идеале с поддержкой загрузки всех файлов из каталога или даже рекурсивных загрузок.
Например, с помощью сборки WinSCP.NET вы можете загрузить весь каталог одним вызовом Session.GetFiles
:
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
Protocol = [WinSCP.Protocol]::Ftp
HostName = "ftp.example.com"
UserName = "user"
Password = "mypassword"
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Download files
$session.GetFiles("/directory/to/download/*", "C:\target\directory\*").Check()
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
Внутренне, WinSCP использует команду MLSD
, если поддерживается сервером. В противном случае он использует команду LIST
и поддерживает десятки различных форматов списков.
Session.GetFiles
метод по умолчанию рекурсивный.
(Я автор WinSCP)
Ответ 3
Вот полный рабочий код для загрузки всех файлов (с подстановочным знаком или расширением файла) с FTP-сайта в локальный каталог. Задайте значения переменных.
#FTP Server Information - SET VARIABLES
$ftp = "ftp://XXX.com/"
$user = 'UserName'
$pass = 'Password'
$folder = 'FTP_Folder'
$target = "C:\Folder\Folder1\"
#SET CREDENTIALS
$credentials = new-object System.Net.NetworkCredential($user, $pass)
function Get-FtpDir ($url,$credentials) {
$request = [Net.WebRequest]::Create($url)
$request.Method = [System.Net.WebRequestMethods+FTP]::ListDirectory
if ($credentials) { $request.Credentials = $credentials }
$response = $request.GetResponse()
$reader = New-Object IO.StreamReader $response.GetResponseStream()
while(-not $reader.EndOfStream) {
$reader.ReadLine()
}
#$reader.ReadToEnd()
$reader.Close()
$response.Close()
}
#SET FOLDER PATH
$folderPath= $ftp + "/" + $folder + "/"
$files = Get-FTPDir -url $folderPath -credentials $credentials
$files
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)
$counter = 0
foreach ($file in ($files | where {$_ -like "*.txt"})){
$source=$folderPath + $file
$destination = $target + $file
$webclient.DownloadFile($source, $target+$file)
#PRINT FILE NAME AND COUNTER
$counter++
$counter
$source
}
Ответ 4
remotePickupDir
будет папкой, на которую вы хотите перейти на ftp-сервер. Насколько "этот script правильный", хорошо, работает ли он? Если он работает, то это правильно. Если это не сработает, сообщите нам, какое сообщение об ошибке или неожиданное поведение вы получаете, и мы сможем вам помочь.
Ответ 5
Для получения файлов/папок с FTP через powerShell я написал несколько функций, вы можете получить даже скрытые вещи из FTP.
Пример получения всех файлов, которые не скрыты в определенной папке:
Get-FtpChildItem -ftpFolderPath "ftp://myHost.com/root/leaf/" -userName "User" -password "pw" -hidden $false -File
Пример получения всех папок (также скрытых) в определенной папке:
Get-FtpChildItem -ftpFolderPath"ftp://myHost.com/root/leaf/" -userName "User" -password "pw" -Directory
Вы можете просто скопировать функции из следующего модуля без необходимости и установки третьей библиотеки:
https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1
Ответ 6
Извините, но я нашел ответы на все вопросы. Если powershell действительно понимали как оболочку, вы просто отбросили бы свою любимую надежную нативную программу ftp и покончили бы с ней. Разумный подход состоит в том, чтобы иметь один хороший инструмент для одной конкретной задачи, а это означает многофункциональную операционную систему, предлагающую широкий спектр инструментов командной строки. MS никогда не принимала этот путь, и все еще больно делать самую основную работу. Почему бы не заменить вашу экосистему, установив cygwin и ncftp?