This is an old revision of the document!
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@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 "!S" -localPath "%LocalPath%" -remotePath "%RemotePath%" %Delete% %Beep% %ContinueOnError% -interval "%Interval%" -pause -sessionLogPath "%SessionLogPath%" # @description Periodically scans for changes in a remote directory and reflects them on a local directory # @version 4 # @homepage https://winscp.net/eng/docs/library_example_keep_local_directory_up_to_date # @require WinSCP 5.9.2 # @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 - -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-xx-xx-xx@example.com/", [Parameter(Mandatory = $True)] $localPath, [Parameter(Mandatory = $True)] $remotePath, [Switch] $delete, [Switch] $beep, [Switch] $continueOnError, $sessionLogPath = $Null, $interval = 30, [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 $sessionOptions = New-Object WinSCP.SessionOptions $sessionOptions.ParseUrl($sessionUrl) $session = New-Object WinSCP.Session # Optimization # (do not waste time enumerating files, if you do not need to scan for deleted files) if ($delete) { $localFiles = Get-ChildItem -Recurse -Path $localPath } try { $session.SessionLogPath = $sessionLogPath Write-Host "Connecting..." $session.Open($sessionOptions) while ($True) { Write-Host "Synchronizing changes..." $result = $session.SynchronizeDirectories( [WinSCP.SynchronizationMode]::Local, $localPath, $remotePath, $delete) $changed = $False if (!$result.IsSuccess) { if ($continueOnError) { Write-Host "Error: $($result.Failures[0].Message)" $changed = $True } else { $result.Check() } } # Print updated files foreach ($download in $result.Downloads) { Write-Host "$($download.Destination) <= $($download.FileName)" $changed = $True } if ($delete) { # scan for removed local files (the $result does not include them) $localFiles2 = Get-ChildItem -Recurse -Path $localPath if ($localFiles) { $changes = Compare-Object -DifferenceObject $localFiles2 ` -ReferenceObject $localFiles $removedFiles = $changes | Where-Object -FilterScript { $_.SideIndicator -eq "<=" } | Select-Object -ExpandProperty InputObject # Print removed local files foreach ($removedFile in $removedFiles) { Write-Host "$removedFile deleted" $changed = $True } } $localFiles = $localFiles2 } if ($changed) { if ($beep) { [System.Console]::Beep() } } else { Write-Host "No change." } Write-Host "Waiting for $interval seconds, press Ctrl+C to abort..." $wait = [int]$interval # Wait for 1 second in a loop, to make the waiting breakable while ($wait -gt 0) { Start-Sleep -Seconds 1 $wait-- } Write-Host } } finally { Write-Host "Disconnecting..." # Disconnect, clean up $session.Dispose() } } catch { Write-Host "Error: $($_.Exception.Message)" } # 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 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. This feature is available only in the latest beta release.
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