Archivos y subcarpetas de descarga de PowerShell FTP

Me gusta escribir un script de PowerShell para descargar todos los archivos y subcarpetas de mi servidor FTP. Encontré un script para descargar todos los archivos de una carpeta específica, pero también me gusta descargar las subcarpetas y sus archivos.

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

Gracias por tu ayuda (:

.NET Framework o PowerShell no tienen ningún soporte explícito para las operaciones recursivas de archivos (incluidas las descargas). Tienes que implementar la recursión tú mismo:

  • Lista el directorio remoto
  • Iterar las entradas, descargar archivos y recurrir a subdirectorios (volver a enumerarlos, etc.)

La parte difícil es identificar los archivos de los subdirectorios. No hay forma de hacerlo de forma portátil con .NET Framework ( FtpWebRequest o WebClient ). Desafortunadamente, el .NET Framework no es compatible con el comando MLSD , que es la única forma portátil de recuperar la lista de directorios con atributos de archivos en el protocolo FTP. Consulte también Comprobar si el objeto en el servidor FTP es un archivo o directorio .

Tus opciones son:

  • Realice una operación en un nombre de archivo que seguramente fallará para el archivo y tendrá éxito para los directorios (o viceversa). Es decir, puede intentar descargar el “nombre”. Si eso tiene éxito, es un archivo, si eso falla, es un directorio.
  • Puede tener suerte y, en su caso específico, puede distinguir un archivo de un directorio por un nombre de archivo (es decir, todos sus archivos tienen una extensión, mientras que los subdirectorios no).
  • Utiliza una larga lista de directorios (comando LIST = método ListDirectoryDetails ) e intenta analizar una lista específica del servidor. Muchos servidores FTP usan la lista * nix-style, donde identifica un directorio por la d al comienzo de la entrada. Pero muchos servidores usan un formato diferente. El siguiente ejemplo usa este enfoque (asumiendo el formato * 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() } } } 

Use la función como:

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

El código se traduce de mi ejemplo de C # en C #. Descarga todos los archivos y subdirectorios a través de FTP .


Si desea evitar problemas al analizar los formatos de listado de directorios específicos del servidor, use una biblioteca de terceros que admita el comando MLSD y / o analice varios formatos de listas LIST ; y descargas recursivas.

Por ejemplo, con el ensamblado WinSCP .NET , puede descargar todo el directorio con una sola llamada a 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() } 

Internamente, WinSCP usa el comando MLSD , si es compatible con el servidor. Si no, usa el comando LIST y admite docenas de formatos de listado diferentes.

El método Session.GetFiles es recursivo por defecto.

(Soy el autor de WinSCP)

Para recuperar archivos / carpetas de FTP a través de PowerShell, escribí algunas funciones, incluso puedes obtener cosas ocultas de FTP.

Ejemplo para obtener todos los archivos y subcarpetas (incluso los ocultos) en una carpeta específica:

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

Puede copiar las funciones del siguiente módulo sin necesidad de tener instalada ninguna tercera biblioteca: https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1

AstralisSomnium

Para recuperar archivos / carpetas de FTP a través de PowerShell, escribí algunas funciones, incluso puedes obtener cosas ocultas de FTP.

Ejemplo para obtener todos los archivos y subcarpetas (incluso los ocultos) en una carpeta específica:

Get-FtpChildItem -ftpFolderPath ” ftp://myHost.com/root/leaf/ ” -userName “Usuario” -password “pw” -Directory -File Puede simplemente copiar las funciones del siguiente módulo sin necesidad de tener instalada ninguna tercera biblioteca: https://github.com/AstralisSomnium/PowerShell-No-Library-Just-Functions/blob/master/FTPModule.ps1

Sí, pero ¿dónde escribo el destino del archivo descargado?

Martin Prikryl

Puede tener suerte y, en su caso específico, puede distinguir un archivo de un directorio por un nombre de archivo (es decir, todos sus archivos tienen una extensión, mientras que los subdirectorios no).

Creo que use esta opción, pero ¿puedo hacer algo como “. *” Para seleccionar todas las extensiones?

Intereting Posts