web-dev-qa-db-ja.com

PowerShellFTPダウンロードファイルとサブフォルダー

FTPサーバーからすべてのファイルおよびサブフォルダーをダウンロードするPowerShellスクリプトを作成するのが好きです。 1つの特定のフォルダーからすべてのファイルをダウンロードするスクリプトを見つけましたが、サブフォルダーとそのファイルもダウンロードするのが好きです。

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

ご協力いただきありがとうございます (:

7
Pascal

.NET FrameworkまたはPowerShellは、再帰的なファイル操作(ダウンロードを含む)を明示的にサポートしていません。再帰を自分で実装する必要があります。

  • リモートディレクトリを一覧表示します
  • エントリを繰り返し、ファイルをダウンロードし、サブディレクトリに繰り返します(それらを再度リストするなど)。

トリッキーな部分は、サブディレクトリからファイルを識別することです。 .NET Framework(FtpWebRequestまたはWebClient)を使用して移植可能な方法でこれを行う方法はありません。残念ながら、.NETFrameworkはMLSDコマンドをサポートしていません。これは、FTPプロトコルでファイル属性を使用してディレクトリリストを取得する唯一の移植可能な方法です。参照 FTPサーバー上のオブジェクトがファイルまたはディレクトリであるかどうかの確認

オプションは次のとおりです。

  • ファイルでは必ず失敗し、ディレクトリでは成功する(またはその逆の)ファイル名で操作を実行します。つまり「名前」をダウンロードしてみてください。それが成功した場合、それはファイルであり、それが失敗した場合、それはディレクトリです。
  • 運が良ければ、特定のケースでは、ファイル名でディレクトリからファイルを区別できます(つまり、すべてのファイルに拡張子が付いていますが、サブディレクトリには拡張子がありません)
  • 長いディレクトリリスト(LIST command = ListDirectoryDetails method)を使用して、サーバー固有のリストを解析しようとします。多くの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#FTP経由ですべてのファイルとサブディレクトリをダウンロードします

ただし Microsoftは新しい開発にFtpWebRequestを推奨していません


サーバー固有のディレクトリリスト形式の解析に関する問題を回避したい場合は、MLSDコマンドをサポートするサードパーティライブラリを使用するか、さまざまなLISTリスト形式を解析してください。再帰的なダウンロード。

たとえば、 WinSCP .NET Assembly を使用すると、 Session.GetFiles を1回呼び出すだけでディレクトリ全体をダウンロードできます。

# 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メソッド はデフォルトで再帰的です。

(私はWinSCPの作者です)

5
Martin Prikryl

PowerShellを介してFTPからファイル/フォルダーを取得するために、いくつかの関数を作成しました。FTPから非表示のものも取得できます。

特定のフォルダー内のすべてのファイルとサブフォルダー(非表示のものも含む)を取得する例:

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

3番目のライブラリをインストールしなくても、次のモジュールから関数をコピーできます。 https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1 ==

2
AstralisSomnium

AstralisSomnium

PowerShellを介してFTPからファイル/フォルダーを取得するために、いくつかの関数を作成しました。FTPから非表示のものも取得できます。

特定のフォルダー内のすべてのファイルとサブフォルダー(非表示のものも含む)を取得する例:

Get-FtpChildItem -ftpFolderPath " ftp://myHost.com/root/leaf/ " -userName "User" -password "pw" -Directory-File次のモジュールから関数をコピーするだけです。 3番目のライブラリをインストールする必要はありません: https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1

はい、でもダウンロードしたファイルの宛先はどこに書きますか?

Martin Prikryl

運が良ければ、特定のケースでは、ファイル名でディレクトリからファイルを区別できます(つまり、すべてのファイルに拡張子が付いていますが、サブディレクトリには拡張子がありません)

このオプションを使用すると思いますが、「。*」のようなものを作成してすべての拡張子を選択できますか?

0
Darknat