2016-05-06 80 views
4

我喜歡編寫一個PowerShell腳本從我的FTP服務器上下載所有文件子文件夾。我發現一個腳本從一個特定文件夾下載所有文件,但我也想下載子文件夾及其文件。PowerShell FTP下載文件和子文件夾

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

感謝您的幫助(:

回答

2

NET框架或PowerShell中沒有遞歸文件操作(包括下載任何明確的支持),您必須執行遞歸自己:

  • 列出遠程目錄
  • 迭代項,下載文件,並在遞歸到子目錄(再次列出這些,等)

棘手的部分是從子目錄中識別文件。使用.NET框架(FtpWebRequestWebClient)無法以便攜方式執行此操作。不幸的是,.NET框架不支持MLSD命令,該命令是用FTP協議檢索具有文件屬性的目錄列表的唯一可移植方式。另請參閱Checking if object on FTP server is file or directory

的選項有:

  • 上那是一定要失敗的文件,併成功爲目錄(反之亦然)的文件名再做一次手術。即你可以嘗試下載「名稱」。如果成功,它就是一個文件,如果失敗了,它就是一個目錄。
  • 你可能是幸運的,在特定情況下,可以通過文件名告訴從目錄中的文件(即所有文件的擴展名,而子目錄不)
  • 您使用長的目錄列表(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" 

的代碼是從我的C#示例中C# Download all files and subdirectories through FTP翻譯。


如果你想避免與解析服務器特定的目錄列表格式的煩惱,使用支持MLSD命令和/或解析各種LIST房源格式第三方庫;和遞歸下載。

例如與WinSCP .NET assembly你可以用一個調用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 method是遞歸的。

(我的WinSCP的作者)

+1

謝謝你很多。使用winscp完美工作! – Pascal

2

對於通過PowerShell與FTP檢索文件/文件夾,我寫了一些功能,你可以得到竟然隱藏着的東西從FTP。

例爲獲得特定文件夾中的所有文件和子文件夾(甚至是隱藏的):

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

您可以直接從以下模塊複製的功能,而無需安裝任何第三屆庫: https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1

0

AstralisSomnium

爲了通過powerShell從FTP檢索文件/文件夾,我編寫了一些功能,甚至可以從FTP獲取隱藏的東西。

示例在 特定文件夾中獲得的所有文件和子文件夾(甚至隱藏的):

GET-FtpChildItem -ftpFolderPath 「ftp://myHost.com/root/leaf/」 -userName 「用戶」 - 密碼 「PW」 -Directory - 文件你可以只複製從以下模塊的功能,而無需任何第三屆庫 安裝: https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1

是的,但如果我寫的下載文件的目的地是哪裏?

馬丁Prikryl

你可能是幸運的,在特定情況下,可以通過文件名告訴從 目錄中的文件(即所有文件的擴展名,而 子目錄不)

我認爲使用這個選項,但我可以使「。*」來選擇所有的擴展名?