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 (:

Author: Martin Prikryl, 2016-05-06

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)

 2
Author: Martin Prikryl,
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]

 2
Author: AstralisSomnium,
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 ?

 0
Author: Darknat,
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