2016-05-06 8 views
4

Ich möchte ein PowerShell-Skript zum Download alle Dateien und Unterordner von meinem FTP-Server zu schreiben. Ich habe ein Skript gefunden, um alle Dateien aus einem bestimmten Ordner herunterzuladen, aber ich lade auch gerne die Unterordner und ihre Dateien herunter.PowerShell FTP-Download-Dateien und Unterordner

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

Danke für Ihre Hilfe. (:

Antwort

2

Das Framework .NET oder Powershell keine explizite Unterstützung für rekursive Dateioperationen (einschließlich Downloads haben) Sie haben die Rekursion selbst zu implementieren:

  • Liste der Remote-Verzeichnis
  • Iterate die Einträge, Dateien und rekursiv in Unterverzeichnissen (Auflistung sie wieder, etc.)
  • Download

Tricky Teil ist die Identifizierung von Dateien aus Unterverzeichnissen. Es gibt keine Möglichkeit, dies auf portable Weise mit dem .NET-Framework zu tun (FtpWebRequest oder WebClient). Das .NET-Framework unterstützt leider nicht den Befehl MLSD, der die einzige Möglichkeit ist, Verzeichnislisten mit Dateiattributen im FTP-Protokoll abzurufen. Siehe auch Checking if object on FTP server is file or directory.

Optionen sind verfügbar:

  • Sie eine Operation auf einen Dateinamen, die Datei scheitern und erfolgreich für Verzeichnisse (oder umgekehrt) ist sicher. I.e. Sie können versuchen, den "Namen" herunterzuladen. Wenn das gelingt, ist es eine Datei, wenn das fehlschlägt, ist es ein Verzeichnis.
  • können Sie Glück haben und in Ihrem speziellen Fall, können Sie eine Datei aus einem Verzeichnis durch einen Dateinamen (dh alle Dateien haben eine Erweiterung, während Unterverzeichnisse nicht) sagen
  • Sie verwenden eine lange Verzeichnisliste (LIST command = ListDirectoryDetails Methode) und versuchen, eine serverspezifische Auflistung zu analysieren. Viele FTP-Server verwenden eine * nix-style-Auflistung, in der Sie ein Verzeichnis durch die d am Anfang des Eintrags identifizieren. Viele Server verwenden jedoch ein anderes Format. Das folgende Beispiel verwendet diesen Ansatz (vorausgesetzt, die * 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 von meinem C# Beispiel in C# Download all files and subdirectories through FTP übersetzt.


Wenn Sie Probleme vermeiden wollen, mit dem serverspezifischen Verzeichnis Parsen Formaten Auflistung, verwenden Sie eine 3rd-Party-Bibliothek, die den MLSD Befehl und/oder Analysieren von verschiedenen LIST Auflistung Formate unterstützt; und rekursive Downloads.

Zum Beispiel mit WinSCP .NET assembly können Sie ganzes Verzeichnis mit einem einzigen Aufruf 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 WinSCP den MLSD Befehl verwendet, wenn vom Server unterstützt.Ist dies nicht der Fall, wird der Befehl LIST verwendet und Dutzende verschiedener Listenformate unterstützt.

Die Session.GetFiles method ist standardmäßig rekursiv.

(ich bin der Autor von WinSCP)

+1

Vielen Dank sehr viel. Funktioniert perfekt mit winscp! – Pascal

2

Für Dateien/Ordner von FTP über Power Abrufen schrieb ich einige Funktionen können Sie auch Sachen von FTP versteckt erhalten.

Beispiel für das Erhalten alle Dateien und Unterordner (auch unsichtbare) in einem bestimmten Ordner:

Get-FtpChildItem -ftpFolderPath "ftp://myHost.com/root/leaf/" -userName "User" -password "pw" -Directory -File 

Sie können nur die Funktionen aus der folgenden Modul kopieren, ohne jede dritte Bibliothek zu benötigen installiert: https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1

0

AstralisSomnium

Zum Abrufen von Dateien/Ordner von FTP über PowerShell habe ich einige Funktionen geschrieben, mit denen man sogar versteckte Sachen von FTP bekommen kann.

Beispiel für das Erhalten alle Dateien und Unterordner (auch unsichtbare) in einem bestimmten Ordner :

Get-FtpChildItem -ftpFolderPath "ftp://myHost.com/root/leaf/" -UserName "User" -Passwort "pw" -Directory -File Sie kann nur die Funktionen aus der folgenden Modul kopieren, ohne jede dritte Bibliothek installiert zu benötigen: https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1

Ja, aber wo ich Ziel der heruntergeladenen Datei schreiben?

Martin Prikryl

du Glück sein kann und in Ihrem speziellen Fall, können Sie eine Datei von einem Verzeichnis durch einen Dateinamen sagen (dh alle Dateien eine Erweiterung haben, während Unterverzeichnisse nicht)

Ich denke, dass diese Option verwenden, aber kann ich etwas wie ". *" machen, um alle Erweiterung zu wählen?