This is an old revision of the document!

Downloading the most recent file

Using WinSCP .NET Assembly

PowerShell

The following example uses WinSCP .NET assembly from a PowerShell script. If you have another preferred language, you can easily translate it.

param (
    $localPath = "c:\downloaded\",
    $remotePath = "/home/user/"
)
 
try
{
    # Load WinSCP .NET assembly
    Add-Type -Path "WinSCPnet.dll"
 
    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions
    $sessionOptions.Protocol = [WinSCP.Protocol]::Sftp
    $sessionOptions.HostName = "example.com"
    $sessionOptions.UserName = "user"
    $sessionOptions.Password = "mypassword"
    $sessionOptions.SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
 
    $session = New-Object WinSCP.Session
 
    try
    {
        # Connect
        $session.Open($sessionOptions)
 
        # Get list of files in the directory
        $directoryInfo = $session.ListDirectory($remotePath)
 
        # Select the most recent file
        $latest =
            $directoryInfo.Files |
            Where-Object { -Not $_.IsDirectory } |
            Sort-Object LastWriteTime -Descending |
            Select-Object -First 1
 
        # Any file at all?
        if ($latest -eq $Null)
        {
            Write-Host "No file found"
            exit 1
        }
 
        # Download the selected file
        $session.GetFiles($session.EscapeFileMask($remotePath + $latest.Name), $localPath).Check()
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }
 
    exit 0
}
catch [Exception]
{
    Write-Host $_.Exception.Message
    exit 1
}

C#

using System;
using System.Linq;
using WinSCP;
 
class Program
{
    static int Main(string[] args)
    {
        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",
            };
 
            using (Session session = new Session())
            {
                // Connect
                session.Open(sessionOptions);
 
                const string remotePath = "/home/user/";
                const string localPath = "c:\\downloaded\\";
 
                // Get list of files in the directory
                RemoteDirectoryInfo directoryInfo = session.ListDirectory(remotePath);
 
                // Select the most recent file
                RemoteFileInfo latest =
                    directoryInfo.Files
                        .Where(file => !file.IsDirectory)
                        .OrderByDescending(file => file.LastWriteTime)
                        .FirstOrDefault();
 
                // Any file at all?
                if (latest == null)
                {
                    throw new Exception("No file found");
                }
 
                // Download the selected file
                session.GetFiles(session.EscapeFileMask(remotePath + latest.Name), localPath).Check();
            }
 
            return 0;
        }
        catch (Exception e)
        {
            Console.WriteLine("Error: {0}", e);
            return 1;
        }
    }
}

Using WinSCP Scripting

In the Beta Version

Use the -latest switch of the get command:

get -latest /home/user/* c:\downloaded\

In the Stable Version

You may use following Windows script host JScript code (example.js):

// Configuration
 
// Local path to download to (keep trailing slash)
var LOCALPATH = "c:\\downloaded\\";
// Remote path to search in (keep trailing slash)
var REMOTEPATH = "/home/user/";
// Mask of files to search for
var FILEMASK = "*.*";
// Session to connect to
var SESSION = "session";
// Path to winscp.com
var WINSCP = "c:\\program files\\winscp\\winscp.com";
 
var filesys = WScript.CreateObject("Scripting.FileSystemObject");
var shell = WScript.CreateObject("WScript.Shell");
   
var logfilepath = filesys.GetSpecialFolder(2) + "\\" + filesys.GetTempName() + ".xml";
 
var exec;
 
// run winscp to get list of file in the remote directory into XML log
exec = shell.Exec("\"" + WINSCP + "\" /xmllog=\"" + logfilepath + "\"");
exec.StdIn.Write(
    "option batch abort\n" +
    "open \"" + SESSION + "\"\n" +
    "ls \"" + REMOTEPATH + FILEMASK + "\"\n" +
    "exit\n");
 
// wait until it finishes and collect its output
var output = exec.StdOut.ReadAll();
// optionally print the output
WScript.Echo(output);
 
if (exec.ExitCode != 0)
{
    WScript.Echo("Error retrieving list of files");
    WScript.Quit(1);
}
 
// look for log file
var logfile = filesys.GetFile(logfilepath);
 
if (logfile == null)
{
    WScript.Echo("Cannot find log file");
    WScript.Quit(1);
}
 
// parse XML log file
var doc = new ActiveXObject("MSXML2.DOMDocument");
doc.async = false;
doc.load(logfilepath);
 
doc.setProperty("SelectionNamespaces", 
    "xmlns:w='http://winscp.net/schema/session/1.0'");
 
var nodes = doc.selectNodes("//w:file");
 
// find the latest file
var filenameLatest = null;
var modificationLatest = null;
for (var i = 0; i < nodes.length; ++i)
{
    var filename = nodes[i].selectSingleNode("w:filename/@value");
    var modification = nodes[i].selectSingleNode("w:modification/@value");
    if ((filename != null) &&
        (filename.value != ".") &&
        (filename.value != "..") &&
        (modification != null))
    {
        // can compare timestamps stringwise
        if ((modificationLatest == null) ||
            (modificationLatest < modification.value))
        {
            modificationLatest = modification.value;
            filenameLatest = filename.value;
        }
    }
}
 
// no file in the log
if (filenameLatest == null)
{
    WScript.Echo("No file found");
    WScript.Quit(0);
}
 
// run winscp to download the latest file
exec = shell.Exec("\"" + WINSCP + "\"");
exec.StdIn.Write(
    "option batch abort\n" +
    "option confirm off\n" +
    "open \"" + SESSION + "\"\n" +
    "get \"" + REMOTEPATH + filenameLatest + "\" \"" + LOCALPATH + "\"\n" +
    "exit\n");
 
// wait until it finishes and collect its output
var output = exec.StdOut.ReadAll();
// optionally print the output
WScript.Echo(output);
 
if (exec.ExitCode != 0)
{
    WScript.Echo("Error downloading " + filenameLatest);
    WScript.Quit(1);
}

Run the script with command:

cscript /nologo example.js

Alternatives

Some of following alternatives can be easier to implement or actually even more appropriate for your specific task:

  • Synchronizing a remote directory to a local directory (using synchronize local in scripting or Session.SynchronizeDirectories(SynchronizationMode.Local, …) in .NET assembly);
  • Downloading all files created in the last 24 hours (using file mask *>=1D; e.g. get -filemask="*>=1D" /home/user/*, or an equivalent in .NET assembly).
  • Downloading all files created today (using %TIMESTAMP% syntax to format file mask with today’s time constraint, e.g. get -filemask="*>=%TIMESTAMP#yyyy-mm-dd%" /home/user/*, or an equivalent in .NET assembly).

Further Reading

Last modified: by martin