it-swarm.com.de

PowerShell Mit dem FTP-Server verbinden und Dateien abrufen

$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

Dies ist das Skript, das ich zum Importieren von Dateien von einem FTP-Server erhalten habe.
Ich bin mir jedoch nicht sicher, was der remotePickupDir ist und ist dieses Skript korrekt? 

12
user2744565

Der Pfad zum Remote-Auswahlverzeichnis sollte der genaue Pfad auf dem FTP-Server sein, auf den Sie zugreifen möchten ... _. Hier ist das Skript zum Herunterladen von Dateien vom Server ... _. Sie können es mit SSLMode hinzufügen oder ändern.

#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)
}
5
Manoj Patil

Die in der Frage verwendete AlexFTPS-Bibliothek scheint tot zu sein (wurde seit 2011 nicht aktualisiert).


Ohne externe Bibliotheken

Alternativ können Sie versuchen, dies ohne externe Bibliothek zu implementieren. Leider bieten weder .NET Framework noch PowerShell explizite Unterstützung für das Herunterladen aller Dateien in einem Verzeichnis (nur rekursive Dateidownloads zulassen).

Das müssen Sie selbst umsetzen:

  • Listen Sie das Remote-Verzeichnis auf
  • Iterieren Sie die Einträge, laden Sie Dateien herunter (und rekursieren Sie sie optional in Unterverzeichnisse - listen Sie sie erneut auf, usw.).

Ein schwieriger Teil ist das Identifizieren von Dateien aus Unterverzeichnissen. Es gibt keine Möglichkeit, dies mit dem .NET-Framework (FtpWebRequest oder WebClient) auf tragbare Weise durchzuführen. Leider unterstützt das .NET-Framework den Befehl MLSD nicht. Dies ist der einzige tragbare Weg, um Verzeichnislisten mit Dateiattributen im FTP-Protokoll abzurufen. Siehe auch Prüfen, ob das Objekt auf dem FTP-Server eine Datei oder ein Verzeichnis ist .

Ihre Optionen sind:

  • Wenn Sie wissen, dass das Verzeichnis keine Unterverzeichnisse enthält, verwenden Sie die ListDirectory-Methode (NLST-FTP-Befehl) und laden Sie einfach alle "Namen" als Dateien herunter.
  • Führen Sie eine Operation für einen Dateinamen durch, der für die Datei fehlgeschlagen ist und für Verzeichnisse erfolgreich ist (oder umgekehrt). Das heißt Sie können versuchen, den "Namen" herunterzuladen.
  • Sie können Glück haben und in Ihrem speziellen Fall können Sie eine Datei anhand eines Dateinamens von einem Verzeichnis unterscheiden (d. H. Alle Dateien haben eine Erweiterung, während Unterverzeichnisse dies nicht tun).
  • Sie verwenden eine lange Verzeichnisliste (LIST command = ListDirectoryDetails-Methode) und versuchen, eine serverspezifische Auflistung zu analysieren. Viele FTP-Server verwenden eine Auflistung im * nix-Stil, bei der Sie ein Verzeichnis anhand der Variable d ganz am Anfang des Eintrags identifizieren. Viele Server verwenden jedoch ein anderes Format. Das folgende Beispiel verwendet diesen Ansatz (vorausgesetzt, das * nix-Format).
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()
        }
    }
}

Verwenden Sie die Funktion wie:

$credentials = New-Object System.Net.NetworkCredential("user", "mypassword") 
$url = "ftp://ftp.example.com/directory/to/download/"
DownloadFtpDirectory $url $credentials "C:\target\directory"

Der Code wird aus meinem C # -Beispiel in C # übersetzt. Alle Dateien und Unterverzeichnisse über FTP herunterladen.


Verwenden der 3rd Party Library

Wenn Sie Probleme beim Analysieren der serverspezifischen Verzeichnisformate vermeiden möchten, verwenden Sie eine Bibliothek eines Drittanbieters, die den Befehl MLSD und/oder das Analysieren verschiedener LIST-Listenformate unterstützt. Idealerweise mit Unterstützung für das Herunterladen aller Dateien aus einem Verzeichnis oder sogar für rekursive Downloads.

Zum Beispiel mit WinSCP .NET Assembly können Sie das gesamte Verzeichnis mit einem einzigen Aufruf an Session.GetFiles herunterladen:

# 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()
}    

Intern verwendet WinSCP den Befehl MLSD, sofern vom Server unterstützt. Andernfalls wird der Befehl LIST verwendet und es werden Dutzende verschiedener Auflistungsformate unterstützt.

Die Session.GetFiles-Methode ist standardmäßig rekursiv.

(Ich bin der Autor von WinSCP)

20
Martin Prikryl

Hier ist der vollständige Arbeitscode zum Herunterladen aller Dateien (mit Platzhalter oder Dateierweiterung) von der FTP-Site in das lokale Verzeichnis. Legen Sie die Variablenwerte fest. 

    #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
    }
6
Arkesh Patel

Die remotePickupDir wäre der Ordner, den Sie auf dem FTP-Server aufrufen möchten. Soweit "ist dieses Skript korrekt", funktioniert es? Wenn es funktioniert, ist es richtig. Wenn dies nicht funktioniert, teilen Sie uns mit, welche Fehlermeldung oder unerwartetes Verhalten Sie erhalten, und wir können Ihnen besser helfen.

1
Nate Hekman