Remember already downloaded files so they are not downloaded again

You might have a server, where some kind of data files are periodically generated. You need to regularly download a new set of files to the local machine, where the files are processed. If you keep local copies of the files, you can use a simple synchronization. But if you cannot keep the local copies, you will have to remember, what files did you download already. And this is, what this script does. An alternative is to remember a timestamp of the last transferred file.

You can install this script as an WinSCP extension by using this page URL in the Add Extension command. The extension will automatically use the current local and remote directories.

To run the script manually or to schedule it, use:

powershell.exe -File C:\path\DownloadNewFiles.ps1 -sessionUrl "sftp://username:password;fingerprint=ssh-rsa-xx-xx-xx@example.com/" -localPath "C:\local\dest" -remotePath "/remote/source" -listPath "C:\path\downloaded.txt"
# @name         Download &New Files...
# @command      powershell.exe -ExecutionPolicy Bypass -File "%EXTENSION_PATH%" ^
#                   -sessionUrl "!E" -localPath "%LocalPath%" -remotePath "%RemotePath%" ^
#                   -listPath "%ListPath%" -pause -sessionLogPath "%SessionLogPath%"
# @description  Downloads new files and appends their list to a file, ^
#                   so they are not downloaded again the next time
# @version      1
# @homepage     https://winscp.net/eng/docs/library_example_remember_downloaded_files
# @require      WinSCP 5.14
# @option       - -run group "Directories"
# @option         RemotePath -run textbox "Download new files from &remote directory:" "!/"
# @option         LocalPath -run textbox "... to &local directory:" "!\"
# @option       - -run group "Options"
# @option         ListPath -run textbox "Re&member already downloaded files in:" ^
#                     "%LOCALAPPDATA%\WinSCP\DownloadNewFiles\!N.txt"
# @option       - -config group "Logging"
# @option         SessionLogPath -config sessionlogfile
# @optionspage  https://winscp.net/eng/docs/library_example_remember_downloaded_files#options
 
param (
    # Use Generate Session URL function to obtain a value for -sessionUrl parameter.
    $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xx-xx-xx@example.com/",
    [Parameter(Mandatory = $True)]
    $localPath,
    [Parameter(Mandatory = $True)]
    $remotePath,
    [Parameter(Mandatory = $True)]
    $listPath,
    $sessionLogPath = $Null,
    [Switch]
    $pause
)
 
try
{
    # Load WinSCP .NET assembly
    $assemblyPath = if ($env:WINSCP_PATH) { $env:WINSCP_PATH } else { $PSScriptRoot }
    Add-Type -Path (Join-Path $assemblyPath "WinSCPnet.dll")
 
    # Setup session options from URL
    $sessionOptions = New-Object WinSCP.SessionOptions
    $sessionOptions.ParseUrl($sessionUrl)
 
    $session = New-Object WinSCP.Session
    
    try
    {
        $session.SessionLogPath = $sessionLogPath
 
        $listPath = [Environment]::ExpandEnvironmentVariables($listPath)
        $listDir = (Split-Path -Parent $listPath) 
        New-Item -ItemType directory -Path $listDir -Force | Out-Null 
 
        if (Test-Path $listPath)
        {
            Write-Host "Loading list of already downloaded files from $listPath..."
            $downloaded = @(Get-Content $listPath)
        }
        else
        {
            Write-Host "File $listPath with list of already downloaded files doesn't exist yet."
            $downloaded = @()
        }
 
        Write-Host "Connecting..."
        $session.Open($sessionOptions)
 
        Write-Host "Looking for new files..."
        $files =
            $session.EnumerateRemoteFiles(
                $remotePath, "*", [WinSCP.EnumerationOptions]::AllDirectories)
 
        $count = 0
        foreach ($fileInfo in $files)
        {
            $remoteFilePath = $fileInfo.FullName
            if ($downloaded -notcontains $remoteFilePath)
            {
                $remoteFileLen = $fileInfo.Length
                Write-Host `
                    "Found new file $remoteFilePath with size $remoteFileLen, downloading..."
 
                $localFilePath =
                    [WinSCP.RemotePath]::TranslateRemotePathToLocal(
                        $remoteFilePath, $remotePath, $localPath)
                $localFileDir = (Split-Path -Parent $localFilePath) 
                New-Item -ItemType directory -Path $localFileDir -Force | Out-Null 
 
                $source = [WinSCP.RemotePath]::EscapeFileMask($remoteFilePath)
                $session.GetFiles($source, $localFilePath).Check()
 
                Add-Content $listPath $remoteFilePath
 
                $count++
 
                Write-Host "Downloaded."
            }
        }
 
        if ($count -gt 0)
        {
            Write-Host "Done, downloaded $count files."
        }
        else
        {
            Write-Host "Done, no new files found."
        }
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }
 
    $result = 0
}
catch
{
    Write-Host "Error: $($_.Exception.Message)"
    $result = 1
}
 
# Pause if -pause switch was used
if ($pause)
{
    Write-Host "Press any key to exit..."
    [System.Console]::ReadKey() | Out-Null
}
 
exit $result

Options

Run time

The first two input boxes specify source remote and destination local folder. These will be filled with paths to the current remote and local directories.

In the Remember already downloaded files in box, specify the path to a list text file that will be used to remember the files that were already downloaded. The file (and its parent folders) are automatically created, if it does not exist yet. By default, the file is stored in %LOCALAPPDATA%\WinSCP\DownloadNewFiles and named after the current session.

Preferences

In the Session log file, you can specify a path to a session log file.

In the Keyboard shortcut, you can specify a keyboard shortcut for the extension.

Last modified: by martin