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.Collections.Generic; 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..." }; string localPath = @"d:\backup"; string remotePath = "/home/user"; using (Session session = new Session()) { // Connect session.Open(sessionOptions); // Enumerate files and directories to download IEnumerable<RemoteFileInfo> fileInfos = session.EnumerateRemoteFiles( remotePath, null, EnumerationOptions.EnumerateDirectories | EnumerationOptions.AllDirectories); foreach (RemoteFileInfo fileInfo in fileInfos) { string localFilePath = session.TranslateRemotePathToLocal( fileInfo.FullName, remotePath, localPath); if (fileInfo.IsDirectory) { // Create local subdirectory, if it does not exist yet if (!Directory.Exists(localFilePath)) { Directory.CreateDirectory(localFilePath); } } else { Console.WriteLine("Downloading file {0}...", fileInfo.FullName); // Download file TransferOperationResult transferResult = session.GetFiles( session.EscapeFileMask(fileInfo.FullName), localFilePath); // Did the download succeeded? if (!transferResult.IsSuccess) { // Print error (but continue with other files) Console.WriteLine( "Error downloading file {0}: {1}", fileInfo.FullName, transferResult.Failures[0].Message); } } } } return 0; } catch (Exception e) { Console.WriteLine("Error: {0}", e); return 1; } } }
Advertisement
PowerShell Example
param ( # Use Generate Session URL function to obtain a value for -sessionUrl parameter. [Parameter(Mandatory = $True)] $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xx-xx-xx@example.com/", [Parameter(Mandatory = $True)] $remotePath, [Parameter(Mandatory = $True)] $localPath ) 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) # Enumerate files and directories to download $fileInfos = $session.EnumerateRemoteFiles( $remotePath, $Null, ([WinSCP.EnumerationOptions]::EnumerateDirectories -bor [WinSCP.EnumerationOptions]::AllDirectories)) foreach ($fileInfo in $fileInfos) { $localFilePath = $session.TranslateRemotePathToLocal($fileInfo.FullName, $remotePath, $localPath) if ($fileInfo.IsDirectory) { # Create local subdirectory, if it does not exist yet if (!(Test-Path $localFilePath)) { New-Item $localFilePath -ItemType directory | Out-Null } } else { Write-Host "Downloading file $($fileInfo.FullName)..." # Download file $transferResult = $session.GetFiles( $session.EscapeFileMask($fileInfo.FullName), $localFilePath) # Did the download succeeded? if (!$transferResult.IsSuccess) { # Print error (but continue with other files) Write-Host ( "Error downloading file $($fileInfo.FullName): " + "$($transferResult.Failures[0].Message)") } } } } finally { # Disconnect, clean up $session.Dispose() } exit 0 } catch { Write-Host "Error: $($_.Exception.Message)" exit 1 }
Advertisement
Upload
For an example of walking a local tree to upload files individually, see Recursively move files in directory tree to/from SFTP/FTP server while preserving source directory structure.
The upload example calls OperationResultBase.Check
, so it aborts on any error. Just replace the call with OperationResultBase.IsSuccess
test as this example does. See Capturing Results of Operations