This is an old revision of the document!
Recursively download directory tree with custom error handling
The simplest way to download a directory tree is by using Session.GetFiles
, providing path to a root of the tree as a source. This way a batch operation however stops on any error. If you need to use a custom error handling, for example to ignore any error and just continue, you need to implement walking the tree explicitly.
This example shows a basic implementation that outputs any errors encountered and continues.
Advertisement
C# Example
using System; using System.IO; using WinSCP; class Example { public static int Main() { try { // Setup session options SessionOptions sessionOptions = new SessionOptions { Protocol = Protocol.Sftp, HostName = "example.com", UserName = "user", Password = "mypassword", SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx" }; string localPath = @"d:\backup"; string remotePath = "/home/user"; using (Session session = new Session()) { // Connect session.Open(sessionOptions); // Start recursion downloadDirectory(session, localPath, remotePath); } return 0; } catch (Exception e) { Console.WriteLine("Error: {0}", e); return 1; } } private static void downloadDirectory(Session session, string localPath, string remotePath) { Console.WriteLine(string.Format("Downloading directory {0} ...", remotePath)); try { RemoteDirectoryInfo directoryInfo = session.ListDirectory(remotePath); foreach (RemoteFileInfo fileInfo in directoryInfo.Files) { string remoteFilePath = remotePath + "/" + fileInfo.Name; if (fileInfo.IsDirectory) { // Skip references to current and parent directories if ((fileInfo.Name != ".") && (fileInfo.Name != "..")) { // Recurse into subdirectories string localDirPath = localPath + "\\" + fileInfo.Name; // Create local subdirectory, if it does not exist yet if (!Directory.Exists(localDirPath)) { Directory.CreateDirectory(localDirPath); } downloadDirectory(session, localDirPath, remoteFilePath); } } else { Console.WriteLine(string.Format("Downloading file {0}...", remoteFilePath)); // Download file TransferOperationResult transferResult = session.GetFiles(remoteFilePath, (localPath + "\\")); // Did the download succeded? if (!transferResult.IsSuccess) { // Print error (but continue with other files) Console.WriteLine(string.Format("Error downloading file {0}: {1}", remoteFilePath, transferResult.Failures[0].Message)); } } } } catch (Exception e) { Console.WriteLine(string.Format("Error downloading directory {0}: {1}", remotePath, e.Message)); } } }
Advertisement
PowerShell Example
param ( # Use Generate URL function to obtain a value for -sessionUrl parameter. [Parameter(Mandatory)] $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xx-xx-xx@example.com/", [Parameter(Mandatory)] $remotePath, [Parameter(Mandatory)] $localPath ) function DownloadDirectory ($session, $localPath, $remotePath) { Write-Host ("Downloading directory {0} ..." -f $remotePath) try { $directoryInfo = $session.ListDirectory($remotePath) foreach ($fileInfo in $directoryInfo.Files) { $remoteFilePath = ($remotePath + "/" + $fileInfo.Name) if ($fileInfo.IsDirectory) { # Skip references to current and parent directories if (($fileInfo.Name -ne ".") -and ($fileInfo.Name -ne "..")) { # Recurse into subdirectories $localDirPath = ($localPath + "\" + $fileInfo.Name) # Create local subdirectory, if it does not exist yet if (!(Test-Path $localDirPath)) { New-Item $localDirPath -ItemType directory | Out-Null } DownloadDirectory $session $localDirPath $remoteFilePath } } else { Write-Host ("Downloading file {0}..." -f $remoteFilePath) # Download file $transferResult = $session.GetFiles($remoteFilePath, ($localPath + "\")) # Did the download succeded? if (!$transferResult.IsSuccess) { # Print error (but continue with other files) Write-Host ("Error downloading file {0}: {1}" -f $remoteFilePath, $transferResult.Failures[0].Message) } } } } catch [Exception] { Write-Host ("Error downloading directory {0}: {1}" -f $remotePath, $_.Exception.Message) } } try { # Load WinSCP .NET assembly Add-Type -Path "WinSCPnet.dll" # Setup session options from URL $sessionOptions = New-Object WinSCP.SessionOptions $sessionOptions.ParseUrl($sessionUrl); $session = New-Object WinSCP.Session $session.SessionLogPath = "session.log" try { # Connect $session.Open($sessionOptions) # Start recursion DownloadDirectory $session $localPath $remotePath } finally { # Disconnect, clean up $session.Dispose() } exit 0 } catch [Exception] { Write-Host $_.Exception.Message exit 1 }
Advertisement