PowerShell ftp pobieranie plików i podfolderów
Lubię pisać skrypt PowerShell do pobierania wszystkich plików i podfolderów z mojego serwera FTP. Znalazłem skrypt do pobierania wszystkich plików z jednego określonego folderu, ale lubię również pobierać podfoldery i ich pliki.
#FTP Server Information - SET VARIABLES
$ftp = "ftp://ftp.abc.ch/"
$user = 'abc'
$pass = 'abc'
$folder = '/'
$target = "C:\LocalData\Powershell\"
#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()
$reader.ReadToEnd()
$reader.Close()
$response.Close()
}
#SET FOLDER PATH
$folderPath= $ftp + "/" + $folder + "/"
$Allfiles=Get-FTPDir -url $folderPath -credentials $credentials
$files = ($Allfiles -split "`r`n")
$files
$webclient = New-Object System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)
$counter = 0
foreach ($file in ($files | where {$_ -like "*.*"})){
$source=$folderPath + $file
$destination = $target + $file
$webclient.DownloadFile($source, $target+$file)
#PRINT FILE NAME AND COUNTER
$counter++
$counter
$source
}
Dzięki za pomoc (:
3 answers
. NET framework lub PowerShell nie mają wyraźnego wsparcia dla rekurencyjnych operacji na plikach(w tym pobierania). Musisz zaimplementować rekurencję samodzielnie:
- lista zdalnego katalogu
- iteracja wpisów, pobieranie plików i rekurencja do podkatalogów (lista ich ponownie, itp.)
Trudną częścią jest identyfikacja plików z podkatalogów. Nie ma sposobu, aby to zrobić w przenośny sposób z. NET framework (FtpWebRequest
lub WebClient
). . NET framework niestety nie obsługuje polecenia MLSD
, które jest jedynym przenośnym sposobem pobierania list katalogów z atrybutami plików w protokole FTP. Patrz także sprawdzanie, czy obiekt na serwerze FTP jest plikiem lub katalogiem .
Twoje opcje to:
- wykonaj operację na nazwie pliku, która z pewnością nie powiedzie się dla pliku i zakończy się sukcesem dla katalogów (lub odwrotnie). Możesz spróbować pobrać "nazwę". Jeśli się powiedzie, to plik, jeśli zawiedzie, to katalog.
- możesz mieć szczęście i w twoim konkretnym przypadku możesz odróżnić Plik od katalogu po nazwie pliku (tzn. wszystkie Twoje pliki mają rozszerzenie, podczas gdy podkatalogi Nie)
- używasz długiej listy katalogów (metoda
LIST
command =ListDirectoryDetails
) i próbujesz przeanalizować listę specyficzną dla serwera. Wiele serwerów FTP używa listy w stylu *nix, gdzie identyfikuje się katalog za pomocąd
na samym początku wpisu. Ale wiele serwerów używa innego formatu. Poniższy przykład wykorzystuje takie podejście (przy założeniu formatu * 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()
}
}
}
Użyj funkcji w stylu:
$credentials = New-Object System.Net.NetworkCredential("user", "mypassword")
$url = "ftp://ftp.example.com/directory/to/download/"
DownloadFtpDirectory $url $credentials "C:\target\directory"
Kod jest przetłumaczony z mojego przykładu C# w C # Pobierz wszystkie pliki i podkatalogi przez FTP .
Jeśli chcesz uniknąć problemów z parsowaniem formatów listowania katalogów specyficznych dla serwera, użyj biblioteki innej firmy, która obsługuje polecenie MLSD
i/lub parsowanie różnych formatów listowania LIST
; i rekurencyjne pobieranie.
Na przykład z WinSCP. NET assembly możesz pobrać cały katalog jednym wywołaniem do 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()
}
Wewnętrznie, WinSCP używa polecenia MLSD
, jeśli jest obsługiwane przez serwer. Jeśli nie, używa polecenia LIST
i obsługuje dziesiątki różnych formatów list.
The Session.GetFiles
metoda jest domyślnie rekurencyjna.
(Jestem autorem WinSCP)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-04 06:28:18
Do pobierania plików / folderów z FTP przez powerShell napisałem kilka funkcji, można uzyskać nawet ukryte rzeczy z FTP.
Przykład pobierania wszystkich plików i podfolderów (nawet ukrytych) do określonego folderu:
Get-FtpChildItem -ftpFolderPath "ftp://myHost.com/root/leaf/" -userName "User" -password "pw" -Directory -File
Możesz po prostu skopiować funkcje z poniższego modułu bez konieczności instalowania trzeciej biblioteki: https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1{[7]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-26 13:15:42
AstralisSomnium
Do pobierania plików / folderów z FTP przez powerShell napisałem kilka funkcji, można uzyskać nawet ukryte rzeczy z FTP.
Przykład pobierania wszystkich plików i podfolderów (nawet ukrytych) w katalog specyficzny:
Get-Ftpfolditem-ftpFolderPath "ftp://myHost.com/root/leaf / " -userName "User" - password " pw " - Directory-File możesz po prostu skopiować funkcje z poniższego modułu bez potrzeby Dowolna 3. biblioteka zainstalowane: https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1
Tak, ale gdzie zapisuję miejsce docelowe pobranego pliku ?
Martin Prikryl
Możesz mieć szczęście i w twoim konkretnym przypadku możesz odróżnić Plik od Katalog przez nazwę pliku (tzn. wszystkie Twoje pliki mają rozszerzenie, podczas gdy podkatalogi nie)
Myślę, że skorzystaj z tej opcji, ale czy mogę zrobić coś w stylu ".* "aby wybrać wszystkie rozszerzenia ?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-03 16:40:17