web-dev-qa-db-fra.com

Télécharger des fichiers via FTP à l'aide de PowerShell

Je souhaite utiliser PowerShell pour transférer des fichiers via FTP sur un serveur FTP anonyme. Je n'utiliserais aucun paquet supplémentaire. Comment?

Il ne doit y avoir aucun risque que le script se bloque ou se bloque.

68
magol

Je ne suis pas sûr que vous puissiez prouver à 100% que le script ne soit pas suspendu ni bloqué, car il y a des choses qui ne sont pas sous votre contrôle (que se passe-t-il si le serveur perd le pouvoir au cours du téléchargement?) - mais cela devrait fournir une base solide pour vous aider à démarrer:

# create the FtpWebRequest and configure it
$ftp = [System.Net.FtpWebRequest]::Create("ftp://localhost/me.png")
$ftp = [System.Net.FtpWebRequest]$ftp
$ftp.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$ftp.Credentials = new-object System.Net.NetworkCredential("anonymous","anonymous@localhost")
$ftp.UseBinary = $true
$ftp.UsePassive = $true
# read in the file to upload as a byte array
$content = [System.IO.File]::ReadAllBytes("C:\me.png")
$ftp.ContentLength = $content.Length
# get the request stream, and write the bytes into it
$rs = $ftp.GetRequestStream()
$rs.Write($content, 0, $content.Length)
# be sure to clean up after ourselves
$rs.Close()
$rs.Dispose()
78
Goyuix

Il y a aussi d'autres moyens. J'ai utilisé le script suivant:

$File = "D:\Dev\somefilename.Zip";
$ftp = "ftp://username:[email protected]/pub/incoming/somefilename.Zip";

Write-Host -Object "ftp url: $ftp";

$webclient = New-Object -TypeName System.Net.WebClient;
$uri = New-Object -TypeName System.Uri -ArgumentList $ftp;

Write-Host -Object "Uploading $File...";

$webclient.UploadFile($uri, $File);

Et vous pouvez exécuter un script sur l'utilitaire de ligne de commande FTP Windows à l'aide de la commande suivante

ftp -s:script.txt 

(Découvrez cet article )

La question suivante sur SO répond également à ceci: comment écrire un script pour le téléchargement FTP et le téléchargement?

44
Cyril Gupta

Je ne vais pas prétendre que c'est plus élégant que la solution la plus votée ... mais c'est cool (enfin, du moins dans mon esprit, LOL) à sa manière:

$server = "ftp.lolcats.com"
$filelist = "file1.txt file2.txt"   

"open $server
user $user $password
binary  
cd $dir     
" +
($filelist.split(' ') | %{ "put ""$_""`n" }) | ftp -i -in

Comme vous pouvez le constater, il utilise ce client FTP Windows intégré à Dinky. Beaucoup plus court et simple, aussi. Oui, j'ai effectivement utilisé cela et ça marche!

28
Dexter Legaspi

J'ai récemment écrit pour powershell plusieurs fonctions de communication avec FTP, voir https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1 . La deuxième fonction ci-dessous, vous pouvez envoyer un dossier local entier à FTP. Dans le module sont même des fonctions pour supprimer/ajouter/lire des dossiers et des fichiers de manière récursive.

#Add-FtpFile -ftpFilePath "ftp://myHost.com/folder/somewhere/uploaded.txt" -localFile "C:\temp\file.txt" -userName "User" -password "pw"
function Add-FtpFile($ftpFilePath, $localFile, $username, $password) {
    $ftprequest = New-FtpRequest -sourceUri $ftpFilePath -method ([System.Net.WebRequestMethods+Ftp]::UploadFile) -username $username -password $password
    Write-Host "$($ftpRequest.Method) for '$($ftpRequest.RequestUri)' complete'"
    $content = $content = [System.IO.File]::ReadAllBytes($localFile)
    $ftprequest.ContentLength = $content.Length
    $requestStream = $ftprequest.GetRequestStream()
    $requestStream.Write($content, 0, $content.Length)
    $requestStream.Close()
    $requestStream.Dispose()
}

#Add-FtpFolderWithFiles -sourceFolder "C:\temp\" -destinationFolder "ftp://myHost.com/folder/somewhere/" -userName "User" -password "pw"
function Add-FtpFolderWithFiles($sourceFolder, $destinationFolder, $userName, $password) {
    Add-FtpDirectory $destinationFolder $userName $password
    $files = Get-ChildItem $sourceFolder -File
    foreach($file in $files) {
        $uploadUrl ="$destinationFolder/$($file.Name)"
        Add-FtpFile -ftpFilePath $uploadUrl -localFile $file.FullName -username $userName -password $password
    }
}

#Add-FtpFolderWithFilesRecursive -sourceFolder "C:\temp\" -destinationFolder "ftp://myHost.com/folder/" -userName "User" -password "pw"
function Add-FtpFolderWithFilesRecursive($sourceFolder, $destinationFolder, $userName, $password) {
    Add-FtpFolderWithFiles -sourceFolder $sourceFolder -destinationFolder $destinationFolder -userName $userName -password $password
    $subDirectories = Get-ChildItem $sourceFolder -Directory
    $fromUri = new-object System.Uri($sourceFolder)
    foreach($subDirectory in $subDirectories) {
        $toUri  = new-object System.Uri($subDirectory.FullName)
        $relativeUrl = $fromUri.MakeRelativeUri($toUri)
        $relativePath = [System.Uri]::UnescapeDataString($relativeUrl.ToString())
        $lastFolder = $relativePath.Substring($relativePath.LastIndexOf("/")+1)
        Add-FtpFolderWithFilesRecursive -sourceFolder $subDirectory.FullName -destinationFolder "$destinationFolder/$lastFolder" -userName $userName -password $password
}

}

6
AstralisSomnium

Moyen le plus simple

Le moyen le plus simple de télécharger un fichier binaire sur un serveur FTP à l'aide de PowerShell consiste à utiliser WebClient.UploadFile :

$client = New-Object System.Net.WebClient
$client.Credentials = New-Object System.Net.NetworkCredential("username", "password")
$client.UploadFile("ftp://ftp.example.com/remote/path/file.Zip", "C:\local\path\file.Zip")

Options avancées

Si vous avez besoin d'un contrôle plus important que WebClient n'offre pas (comme cryptage TLS/SSL , etc.), utilisez FtpWebRequest . Le moyen le plus simple est de copier un FileStream vers un flux FTP en utilisant Stream.CopyTo :

$request = [Net.WebRequest]::Create("ftp://ftp.example.com/remote/path/file.Zip")
$request.Credentials = New-Object System.Net.NetworkCredential("username", "password")
$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile 

$fileStream = [System.IO.File]::OpenRead("C:\local\path\file.Zip")
$ftpStream = $request.GetRequestStream()

$fileStream.CopyTo($ftpStream)

$ftpStream.Dispose()
$fileStream.Dispose()

Suivi des progrès

Si vous devez surveiller la progression du téléchargement, vous devez copier le contenu vous-même par morceaux:

$request = [Net.WebRequest]::Create("ftp://ftp.example.com/remote/path/file.Zip")
$request.Credentials = New-Object System.Net.NetworkCredential("username", "password")
$request.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile 

$fileStream = [System.IO.File]::OpenRead("C:\local\path\file.Zip")
$ftpStream = $request.GetRequestStream()

$buffer = New-Object Byte[] 10240
while (($read = $fileStream.Read($buffer, 0, $buffer.Length)) -gt 0)
{
    $ftpStream.Write($buffer, 0, $read)
    $pct = ($fileStream.Position / $fileStream.Length)
    Write-Progress `
        -Activity "Uploading" -Status ("{0:P0} complete:" -f $pct) `
        -PercentComplete ($pct * 100)
}

$fileStream.CopyTo($ftpStream)

$ftpStream.Dispose()
$fileStream.Dispose()

Dossier de téléchargement

Si vous souhaitez télécharger tous les fichiers d'un dossier, voir
Script PowerShell pour télécharger un dossier entier vers FTP

5
Martin Prikryl

Voici ma version super cool PARCE QU'IL A UNE BARRE DE PROGRÈS :-)

Ce qui est une fonctionnalité complètement inutile, je sais, mais il a toujours l'air cool\m/\ m /

$webclient = New-Object System.Net.WebClient
Register-ObjectEvent -InputObject $webclient -EventName "UploadProgressChanged" -Action { Write-Progress -Activity "Upload progress..." -Status "Uploading" -PercentComplete $EventArgs.ProgressPercentage } > $null

$File = "filename.Zip"
$ftp = "ftp://user:password@server/filename.Zip"
$uri = New-Object System.Uri($ftp)
try{
    $webclient.UploadFileAsync($uri, $File)
}
catch  [Net.WebException]
{
    Write-Host $_.Exception.ToString() -foregroundcolor red
}
while ($webclient.IsBusy) { continue }

PS Cela aide beaucoup quand je me demande "est-ce que ça a cessé de fonctionner, ou est-ce juste ma lente connexion ASDL?"

3
Alex

Vous pouvez simplement gérer le téléchargement de fichiers via PowerShell, comme ceci. Le projet complet est disponible sur Github ici https://github.com/edouardkombo/PowerShellFtp

#Directory where to find pictures to upload
$Dir= 'c:\fff\medias\'

#Directory where to save uploaded pictures
$saveDir = 'c:\fff\save\'

#ftp server params
$ftp = 'ftp://10.0.1.11:21/'
$user = 'user'
$pass = 'pass'

#Connect to ftp webclient
$webclient = New-Object System.Net.WebClient 
$webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)  

#Initialize var for infinite loop
$i=0

#Infinite loop
while($i -eq 0){ 

    #Pause 1 seconde before continue
    Start-Sleep -sec 1

    #Search for pictures in directory
    foreach($item in (dir $Dir "*.jpg"))
    {
        #Set default network status to 1
        $onNetwork = "1"

        #Get picture creation dateTime...
        $pictureDateTime = (Get-ChildItem $item.fullName).CreationTime

        #Convert dateTime to timeStamp
        $pictureTimeStamp = (Get-Date $pictureDateTime).ToFileTime()

        #Get actual timeStamp
        $timeStamp = (Get-Date).ToFileTime() 

        #Get picture lifeTime
        $pictureLifeTime = $timeStamp - $pictureTimeStamp

        #We only treat pictures that are fully written on the disk
        #So, we put a 2 second delay to ensure even big pictures have been fully wirtten   in the disk
        if($pictureLifeTime -gt "2") {    

            #If upload fails, we set network status at 0
            try{

                $uri = New-Object System.Uri($ftp+$item.Name)

                $webclient.UploadFile($uri, $item.FullName)

            } catch [Exception] {

                $onNetwork = "0"
                write-Host $_.Exception.Message;
            }

            #If upload succeeded, we do further actions
            if($onNetwork -eq "1"){
                "Copying $item..."
                Copy-Item -path $item.fullName -destination $saveDir$item 

                "Deleting $item..."
                Remove-Item $item.fullName
            }


        }  
    }
}   
2
Edouard Kombo

solution de Goyuix fonctionne très bien, mais tel que présenté, il me donne cette erreur: "La commande FTP demandée n'est pas prise en charge lors de l'utilisation d'un proxy HTTP."

Ajout de cette ligne après $ftp.UsePassive = $true résolu le problème pour moi:

$ftp.Proxy = $null;
2
Mike Brady

Vous pouvez utiliser cette fonction:

function SendByFTP {
    param (
        $userFTP = "anonymous",
        $passFTP = "anonymous",
        [Parameter(Mandatory=$True)]$serverFTP,
        [Parameter(Mandatory=$True)]$localFile,
        [Parameter(Mandatory=$True)]$remotePath
    )
    if(Test-Path $localFile){
        $remoteFile = $localFile.Split("\")[-1]
        $remotePath = Join-Path -Path $remotePath -ChildPath $remoteFile
        $ftpAddr = "ftp://${userFTP}:${passFTP}@${serverFTP}/$remotePath"
        $browser = New-Object System.Net.WebClient
        $url = New-Object System.Uri($ftpAddr)
        $browser.UploadFile($url, $localFile)    
    }
    else{
        Return "Unable to find $localFile"
    }
}

Cette fonction envoie le fichier spécifié par FTP . Vous devez appeler la fonction avec ces paramètres:

  • userFTP = "anonymous" par défaut ou votre nom d'utilisateur
  • passFTP = "anonyme" par défaut ou votre mot de passe
  • serverFTP = adresse IP du serveur FTP
  • localFile = Fichier à envoyer
  • remotePath = le chemin sur le serveur FTP

Par exemple :

SendByFTP -userFTP "USERNAME" -passFTP "PASSWORD" -serverFTP "MYSERVER" -localFile "toto.Zip" -remotePath "path/on/the/FTP/"
1
hasma