web-dev-qa-db-ja.com

PowerShellはFTPサーバーに接続してファイルを取得します

$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

これは、FTPサーバーからファイルをインポートするために取得したスクリプトです。
ただし、remotePickupDirとは何かわかりません。このスクリプトは正しいですか?

13
user2744565

リモートピックディレクトリパスは、アクセスしようとしているFTPサーバー上の正確なパスである必要があります。ここに、サーバーからファイルをダウンロードするスクリプトを示します。SSLModeで追加または変更できます。

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

質問で使用されたAlexFTPSライブラリは死んでいるようです(2011年以降更新されていません)。


外部ライブラリなし

または、外部ライブラリなしでこれを実装することもできます。ただし、残念ながら、.NET FrameworkもPowerShellも、ディレクトリ内のすべてのファイルのダウンロードを明示的にサポートしていません(再帰的なファイルのダウンロードのみを許可します)。

自分で実装する必要があります。

  • リモートディレクトリを一覧表示する
  • エントリを反復し、ファイルをダウンロードします(オプションでサブディレクトリに再帰します-それらを再度リストしますなど)。

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

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

  • ディレクトリにサブディレクトリが含まれていないことがわかっている場合は、ListDirectoryメソッド(NLST FTPコマンド)を使用して、すべての「名前」をファイルとしてダウンロードします。
  • ファイルに対して失敗することが確実で、ディレクトリに対して成功する(またはその逆)ファイル名に対して操作を実行します。つまり「名前」をダウンロードしてみてください。
  • あなたは幸運かもしれませんし、特定のケースでは、ファイル名でディレクトリからファイルを伝えることができます(つまり、すべてのファイルには拡張子がありますが、サブディレクトリにはありません)
  • 長いディレクトリリスト(LIST command = 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#FTPを介してすべてのファイルとサブディレクトリをダウンロード のC#の例から翻訳されています。


サードパーティのライブラリを使用する

サーバー固有のディレクトリリスト形式の解析に関する問題を回避する場合は、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 method はデフォルトで再帰的です。

(私はWinSCPの著者です)

24
Martin Prikryl

FTPサイトからローカルディレクトリにすべてのファイル(ワイルドカードまたはファイル拡張子付き)をダウンロードするための完全な作業コードを次に示します。変数値を設定します。

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

remotePickupDirは、ftpサーバー上の移動先のフォルダーです。 「このスクリプトは正しい」という限り、それは機能しますか?それが動作する場合、それは正しいです。動作しない場合は、どのエラーメッセージまたは予期しない動作が発生しているのかをお知らせください。サポートを提供させていただきます。

1
Nate Hekman