web-dev-qa-db-fra.com

PowerShell Se connecter au serveur FTP et obtenir des fichiers

$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

C'est le script que j'ai obtenu pour importer des fichiers à partir d'un serveur FTP.
Cependant, je ne sais pas quelle est la remotePickupDir et ce script est-il correct? 

12
user2744565

Le chemin du répertoire de sélection à distance doit être le chemin exact sur le serveur FTP auquel vous souhaitez accéder ... Voici le script pour télécharger des fichiers du serveur ... vous pouvez ajouter ou modifier des informations avec 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)
}
5
Manoj Patil

La bibliothèque AlexFTPS utilisée dans la question semble être morte (n'a pas été mise à jour depuis 2011).


Sans bibliothèques externes

Alternativement, vous pouvez essayer d'implémenter cela sans aucune bibliothèque externe. Mais malheureusement, ni le .NET Framework ni PowerShell ne prennent en charge explicitement le téléchargement de tous les fichiers d’un répertoire (laissez uniquement les téléchargements de fichiers récursifs).

Vous devez implémenter cela vous-même:

  • Lister le répertoire distant
  • Itérer les entrées, télécharger des fichiers (et éventuellement récursir dans des sous-répertoires - les lister à nouveau, etc.)

Une partie délicate consiste à identifier les fichiers de sous-répertoires. Il n’ya aucun moyen de le faire de manière portable avec le framework .NET (FtpWebRequest ou WebClient). Malheureusement, le framework .NET ne prend pas en charge la commande MLSD, qui est le seul moyen portable d’extraire une liste de répertoires avec des attributs de fichier dans le protocole FTP. Voir aussi Vérification si l'objet sur le serveur FTP est un fichier ou un répertoire .

Vos options sont:

  • Si vous savez que le répertoire ne contient aucun sous-répertoire, utilisez la méthode ListDirectory (commande NLST FTP) et téléchargez simplement tous les "noms" sous forme de fichiers.
  • Effectuez une opération sur un nom de fichier qui est voué à l'échec pour le fichier et qui réussit aux répertoires (ou inversement). C'est à dire. vous pouvez essayer de télécharger le "nom".
  • Vous avez peut-être de la chance et, dans votre cas particulier, vous pouvez nommer un fichier d'un répertoire à partir d'un répertoire (c'est-à-dire que tous vos fichiers ont une extension, contrairement aux sous-répertoires).
  • Vous utilisez une longue liste de répertoires (méthode LIST command = ListDirectoryDetails) et essayez d'analyser une liste spécifique au serveur. De nombreux serveurs FTP utilisent une liste de style * nix, dans laquelle vous identifiez un répertoire par la variable d tout au début de l'entrée. Mais de nombreux serveurs utilisent un format différent. L'exemple suivant utilise cette approche (en supposant le format * 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()
        }
    }
}

Utilisez la fonction comme:

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

Le code est traduit de mon exemple C # dans C # Téléchargez tous les fichiers et sous-répertoires via FTP .


Utiliser une bibliothèque tierce

Si vous souhaitez éviter les problèmes d’analyse des formats de liste de répertoires spécifiques au serveur, utilisez une bibliothèque tierce qui prend en charge la commande MLSD et/ou en analysant divers formats de liste LIST. Et idéalement avec un support pour télécharger tous les fichiers depuis un répertoire ou même des téléchargements récursifs.

Par exemple, avec WinSCP .NET Assembly vous pouvez télécharger le répertoire complet en un seul appel à 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()
}    

En interne, WinSCP utilise la commande MLSD, si elle est prise en charge par le serveur. Sinon, il utilise la commande LIST et prend en charge des dizaines de formats de liste différents.

La méthode Session.GetFiles est récursive par défaut.

(Je suis l'auteur de WinSCP)

20
Martin Prikryl

Voici le code de travail complet pour télécharger tous les fichiers (avec caractère générique ou extension de fichier) du site FTP vers le répertoire local. Définissez les valeurs des variables. 

    #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

La remotePickupDir serait le dossier que vous voulez aller sur le serveur ftp. En ce qui concerne "ce script est-il correct", eh bien, ça marche? Si cela fonctionne, alors c'est correct. Si cela ne fonctionne pas, dites-nous quel message d'erreur ou quel comportement inattendu vous avez et nous pourrons mieux vous aider.

1
Nate Hekman