Keep local directory up to date (download changed files from remote SFTP/FTP server)
This script periodically synchronizes changes from the remote server to a local directory.
WinSCP supports natively keeping a remote directory up to date function thanks to a possibility to get notified by Windows (as a local operating system) about changes in a local directory. None of the supported file transfer protocols unfortunately offer a functionality to watch for changes in a remote directory. So the only solution is to run full remote to local synchronization in regular intervals.
The script is distributed in WinSCP installer as a WinSCP extension.
Advertisement
To run the script manually, use:
powershell.exe -File KeepLocalUpToDate.ps1 -sessionUrl "sftp://username:password;fingerprint=ssh-rsa-xxxxxxxxxxx...@example.com/" -remotePath "/remote/path" -localPath "C:\local\path" [-delete]
If you just want to scan for changes, but not download them, see Watching for changes in SFTP/FTP server.
# @name &Keep Local Directory up to Date... # @command powershell.exe -ExecutionPolicy Bypass -File "%EXTENSION_PATH%" ^ # -sessionUrl "!E" -localPath "%LocalPath%" -remotePath "%RemotePath%" ^ # %Delete% %Beep% %ContinueOnError% -interval "%Interval%" ^ # -fileMask "%FileMask%" -pause -sessionLogPath "%SessionLogPath%" # @description Periodically scans for changes in a remote directory and ^ # reflects them on a local directory # @version 11 # @homepage https://winscp.net/eng/docs/library_example_keep_local_directory_up_to_date # @require WinSCP 5.16 # @option - -run group "Directories" # @option RemotePath -run textbox "&Watch for changes in the remote directory:" "!/" # @option LocalPath -run textbox ^ # "... &and automatically reflect them on the local directory:" "!\" # @option - -config -run group "Options" # @option Delete -config -run checkbox "&Delete files" "" -delete # @option Beep -config -run checkbox "&Beep on change" "" -beep # @option ContinueOnError -config -run checkbox "Continue on &error" "" -continueOnError # @option Interval -config -run textbox "&Interval (in seconds):" "30" # @option FileMask -config -run textbox "File &mask:" "" # @option - -config group "Logging" # @option SessionLogPath -config sessionlogfile # @optionspage ^ # https://winscp.net/eng/docs/library_example_keep_local_directory_up_to_date#options param ( # Use Generate Session URL function to obtain a value for -sessionUrl parameter. $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xxxxxxxxxxx...@example.com/", [Parameter(Mandatory = $True)] $localPath, [Parameter(Mandatory = $True)] $remotePath, [Switch] $delete, [Switch] $beep, [Switch] $continueOnError, $sessionLogPath = $Null, $interval = 30, $fileMask = $Null, [Switch] $pause ) function Beep() { if ($beep) { [System.Console]::Beep() } } function HandleException ($e) { if ($continueOnError) { Write-Host -ForegroundColor Red $_.Exception.Message Beep } else { throw $e } } function SetConsoleTitle ($status) { if ($sessionOptions) { $status = "$sessionOptions - $status" } $Host.UI.RawUI.WindowTitle = $status } 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 $sessionOptions = New-Object WinSCP.SessionOptions $sessionOptions.ParseUrl($sessionUrl) $transferOptions = New-Object WinSCP.TransferOptions -Property @{ FileMask = $fileMask }; $session = New-Object WinSCP.Session try { $session.SessionLogPath = $sessionLogPath Write-Host "Connecting..." SetConsoleTitle "Connecting" $session.Open($sessionOptions) while ($True) { Write-Host -NoNewline "Looking for changes..." SetConsoleTitle "Looking for changes" try { $differences = $session.CompareDirectories( [WinSCP.SynchronizationMode]::Local, $localPath, $remotePath, $delete, $False, [WinSCP.SynchronizationCriteria]::Time, $transferOptions) Write-Host if ($differences.Count -eq 0) { Write-Host "No changes found." } else { Write-Host "Synchronizing $($differences.Count) change(s)..." SetConsoleTitle "Synchronizing changes" Beep foreach ($difference in $differences) { $action = $difference.Action if ($action -eq [WinSCP.SynchronizationAction]::DownloadNew) { $message = "Downloading new $($difference.Remote.FileName)..." } elseif ($action -eq [WinSCP.SynchronizationAction]::DownloadUpdate) { $message = "Downloading updated $($difference.Remote.FileName)..." } elseif ($action -eq [WinSCP.SynchronizationAction]::DeleteLocal) { $message = "Deleting $($difference.Local.FileName)..." } else { throw "Unexpected difference $action" } Write-Host -NoNewline $message try { $difference.Resolve($session, $transferOptions) | Out-Null Write-Host " Done." } catch { Write-Host HandleException $_ } } } } catch { Write-Host HandleException $_ } SetConsoleTitle "Waiting" $wait = [int]$interval # Wait for 1 second in a loop, to make the waiting breakable while ($wait -gt 0) { Write-Host -NoNewLine "`rWaiting for $wait seconds, press Ctrl+C to abort... " Start-Sleep -Seconds 1 $wait-- } Write-Host Write-Host } } finally { Write-Host # to break after "Waiting..." status Write-Host "Disconnecting..." # Disconnect, clean up $session.Dispose() } } catch { $continueOnError = $True HandleException $_ SetConsoleTitle "Error" } # Pause if -pause switch was used if ($pause) { Write-Host "Press any key to exit..." [System.Console]::ReadKey() | Out-Null } # Never exits cleanly exit 1
Advertisement
Options
Enter root directories for the synchronization into the two directory boxes. By default the current working directories will be used. The directories can be specified, when executing the extension only.
The Delete files checkbox makes the extension delete files and subdirectories in local directory that you delete in a corresponding remote directory. Before using this, learn how it works, so you know what you are doing.
Check the Beep on change to make the extension beep when a change is detected.
Check the Continue on error not to interrupt watching for changes, when an error occurs. Typically you want to enable the option to skip files opened for writing and similar errors.
In the Interval box, specify an interval between the checks for changes.
In the File mask box, you can specify file mask to select/deselect files (or file types) and directories for the synchronization.
In the Session log file, you can specify a path to a session log file. The option is available on the Preferences dialog only.
In the Keyboard shortcut, you can specify a keyboard shortcut for the extension. The option is available on the Preferences dialog only.
Scripting
Or you can simply use the synchronize
scripting command.
To make the synchronization run periodically, you can either schedule the script or run the script in a loop. The latter may be more convenient, as it allows you to see all runs in a single console window, so that you can review the updates easily.
To run the script in the loop, you can use following batch file:1
@echo off :loop winscp.com /script=full_remote_to_local_synchronization.txt timeout /t 30 goto loop
Advertisement
- Note that the
timeout
command is available since Windows 7 only. For alternatives in older versions of Windows, refer to How to sleep for 5 seconds in Windows’s Command Prompt? article.Back