Differences
This shows you the differences between the selected revisions of the page.
scripts 2014-11-25 | scripts 2021-03-31 (current) | ||
Line 1: | Line 1: | ||
====== Useful Scripts ====== | ====== Useful Scripts ====== | ||
- | ~~SPLIT~~ | ||
- | ===== [[upload_single_file]] Uploading a single file ===== | + | ··* [[script_upload_single_file|*]] |
- | A single file upload involves so few commands that it is enough to provide them on the command line, saving writing a script file: | + | ··* [[script_upload_multiple_servers|*]] |
+ | * [[script_download_timestamped_filename|*]] | ||
+ | * [[script_download_most_recent_file|*]] | ||
+ | ··* [[script_upload_most_recent_file|*]] | ||
+ | * [[script_checking_file_existence|*]] | ||
+ | * [[script_local_move_after_successful_upload|*]] | ||
+ | * [[script_locking_files_while_uploading|*]] | ||
+ | * [[script_downloading_when_done_file_exists|*]] | ||
+ | * [[script_download_files_to_same_folder|*]] | ||
+ | * [[script_upload_file_list|*]] | ||
+ | * [[script_synchronize_any_local_file|*]] | ||
+ | * [[script_auto_compress_download|*]] | ||
+ | * [[script_custom_listing_format_csv|*]] | ||
+ | * [[script_retry|*]] | ||
+ | * [[script_formatting_timestamp_batch_file|*]] | ||
+ | * [[script_email|*]] | ||
+ | * [[script_vbnet_robust_example|*]] | ||
- | <code batch> | ||
- | winscp.com /command "option batch abort" "option confirm off" "open sftp://user:password@example.com/" "put examplefile.txt /home/user/" "exit" | ||
- | </code> | ||
- | |||
- | However you may want to use a script file anyway, so you can later expand it: | ||
- | |||
- | <code winscp> | ||
- | option batch abort | ||
- | option confirm off | ||
- | open sftp://user:password@example.com/ | ||
- | put examplefile.txt /home/user/ | ||
- | exit | ||
- | </code> | ||
- | |||
- | To run the script use following command (providing you have saved the script to file ''example.txt''): | ||
- | |||
- | <code batch> | ||
- | winscp.com /script=example.txt | ||
- | </code> | ||
- | |||
- | ===== [[upload_multiple_servers]] Upload to multiple servers / Parametrized script ===== | ||
- | If you need to repeat the same task against multiple servers, instead of writing separate and almost identical [[scripting|scripts]] for each server, you can write one parametrized script. | ||
- | |||
- | Following example is parametrized script that accepts one [[scripting#arguments|parameter]] with [[session_url|session URL]] and uploads a fixed local file to a fixed remote directory: | ||
- | |||
- | <code winscp> | ||
- | option batch abort | ||
- | option confirm off | ||
- | open %1% | ||
- | put examplefile.txt /home/user/ | ||
- | exit | ||
- | </code> | ||
- | |||
- | To use the script against multiple servers, just execute the script (saved to file ''script.txt'') repeatedly, using different [[session_url|session URL]] as parameter: | ||
- | |||
- | <code batch> | ||
- | winscp.com /script=script.txt /parameter sftp://martin@server1.example.com/ | ||
- | winscp.com /script=script.txt /parameter sftp://test@server2.example.com/ | ||
- | </code> | ||
- | |||
- | If the script has also other variable parts, like file to upload or remote directory, just replace those parts with additional parameters (''%2%'', ''%3%'', etc). | ||
- | |||
- | //Alternative to using ''/parameter'' switch is [[scripting#variables|using environment variable in the script]].// | ||
- | |||
- | |||
- | ===== [[download_timestamped_filename]] Downloading file to timestamped-filename ===== | ||
- | |||
- | ==== Using WinSCP .NET Assembly ==== | ||
- | Use [[library|WinSCP .NET assembly]] from your favorite language. Use relevant construct of your language or API of your runtime environment for the file name formatting. | ||
- | |||
- | If you do not have your favorite language, use [[library_powershell|PowerShell]]: | ||
- | |||
- | <code powershell> | ||
- | 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) | ||
- | |||
- | $localPath = "c:\downloaded\" | ||
- | $remotePath = "/home/user/" | ||
- | $file = "download.txt" | ||
- | |||
- | # Format timestamp | ||
- | $stamp = $(Get-Date -f "yyyyMMddHHmmss") | ||
- | |||
- | # Download the file and throw on any error | ||
- | $session.GetFiles( | ||
- | ($remotePath + $file), | ||
- | ($localPath + $file + "." + $stamp)).Check() | ||
- | } | ||
- | finally | ||
- | { | ||
- | # Disconnect, clean up | ||
- | $session.Dispose() | ||
- | } | ||
- | |||
- | exit 0 | ||
- | } | ||
- | catch [Exception] | ||
- | { | ||
- | Write-Host $_.Exception.Message | ||
- | exit 1 | ||
- | } | ||
- | </code> | ||
- | |||
- | ==== Using WinSCP Scripting ==== | ||
- | === [[batch]] Using TIMESTAMP Variable === | ||
- | //In the latest beta release//, &beta you can use ''[[scripting#timestamp|%TIMESTAMP%]]'' construct to insert a real-time to a script. | ||
- | |||
- | <code winscp> | ||
- | option batch abort | ||
- | option confirm off | ||
- | open mysession | ||
- | get "/home/user/download.txt" "C:\downloaded\download.txt.%TIMESTAMP#yyyymmddhhnnss%" | ||
- | exit | ||
- | </code> | ||
- | |||
- | |||
- | === [[batch]] From a Batch File === | ||
- | In Windows batch file, you may retrieve current time in locale-independent format using command ''[[http://technet.microsoft.com/en-us/library/bb491034.aspx|wmic]] os get LocalDateTime''. You can parse the value using using [[http://en.wikibooks.org/wiki/Windows_Batch_Scripting#String_processing|string processing syntax]]: | ||
- | |||
- | <code batch> | ||
- | @echo off | ||
- | |||
- | for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set LDT=%%j | ||
- | set STAMP=%LDT:~0,4%%LDT:~4,2%%LDT:~6,2%%LDT:~8,2%%LDT:~10,2%%LDT:~12,2% | ||
- | |||
- | winscp.com /script=script.txt | ||
- | </code> | ||
- | |||
- | //Note that the expression after ''set STAMP='' shows how to extract individual date/time components, in case you need to interleave them by some punctuation. If not, you can replace it by simple ''%LDT:~0,14%''.// | ||
- | |||
- | The ''script.txt'' should make use of the variable ''STAMP'' using ''%STAMP%'' [[scripting#variables|syntax]]. For example: | ||
- | |||
- | <code winscp> | ||
- | option batch abort | ||
- | option confirm off | ||
- | open mysession | ||
- | get "/home/user/download.txt" "C:\downloaded\download.txt.%STAMP%" | ||
- | exit | ||
- | </code> | ||
- | |||
- | === From a JScript === | ||
- | You may use following [[guide_automation_advanced#wsh|Windows script host JScript code]] (''example.js''): | ||
- | |||
- | <code javascript> | ||
- | // Local path to download to (keep trailing slash) | ||
- | var LOCALPATH = "c:\\downloaded\\"; | ||
- | // Remote path to download from (keep trailing slash) | ||
- | var REMOTEPATH = "/home/user/"; | ||
- | // File to download | ||
- | var FILE = "download.txt"; | ||
- | // Session to connect to | ||
- | var SESSION = "session"; | ||
- | // Path to winscp.com | ||
- | var WINSCP = "c:\\program files\\winscp\\winscp.com"; | ||
- | |||
- | // helper function to pad zeroes to the left of number | ||
- | function pad(n, len) | ||
- | { | ||
- | var s = n.toString(); | ||
- | while (s.length < len) | ||
- | { | ||
- | s = '0' + s; | ||
- | } | ||
- | return s; | ||
- | } | ||
- | |||
- | var date = new Date(); | ||
- | |||
- | // format timestamp | ||
- | var stamp = | ||
- | pad(date.getFullYear(), 4) + | ||
- | pad(date.getMonth(), 2) + | ||
- | pad(date.getDate(), 2) + | ||
- | pad(date.getHours(), 2) + | ||
- | pad(date.getMinutes(), 2) + | ||
- | pad(date.getSeconds(), 2); | ||
- | |||
- | var shell = WScript.CreateObject("WScript.Shell"); | ||
- | |||
- | // run winscp to download the file into timestamped-filename | ||
- | exec = shell.Exec("\"" + WINSCP + "\""); | ||
- | exec.StdIn.Write( | ||
- | "option batch abort\n" + | ||
- | "open \"" + SESSION + "\"\n" + | ||
- | "get \"" + REMOTEPATH + FILE + "\" \"" + LOCALPATH + FILE + "." + stamp + "\"\n" + | ||
- | "exit\n"); | ||
- | |||
- | // wait until it finishes and collect its output | ||
- | var output = exec.StdOut.ReadAll(); | ||
- | // optionally print the output | ||
- | WScript.Echo(output); | ||
- | </code> | ||
- | |||
- | Run the script with command: | ||
- | <code batch> | ||
- | cscript /nologo example.js | ||
- | </code> | ||
- | |||
- | ===== [[download_most_recent_file]] Downloading the most recent file ===== | ||
- | |||
- | ==== [[library]] Using WinSCP .NET Assembly ==== | ||
- | Use [[library|WinSCP .NET assembly]] from your favorite language. | ||
- | |||
- | If you do not have your favorite language, use [[library_powershell|PowerShell]]: | ||
- | |||
- | <code powershell> | ||
- | 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) | ||
- | |||
- | $localPath = "c:\downloaded\" | ||
- | $remotePath = "/home/user/" | ||
- | |||
- | # Gel 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 | ||
- | } | ||
- | </code> | ||
- | |||
- | ==== Using WinSCP Scripting ==== | ||
- | You may use following [[guide_automation_advanced#wsh|Windows script host JScript code]] (''example.js''): | ||
- | |||
- | <code javascript> | ||
- | // 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); | ||
- | } | ||
- | </code> | ||
- | |||
- | Run the script with command: | ||
- | <code batch> | ||
- | cscript /nologo example.js | ||
- | </code> | ||
- | |||
- | ==== 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 ''[[scriptcommand_synchronize|synchronize local]]'' in scripting or ''[[library_session_synchronizedirectories|Session.SynchronizeDirectories(SynchronizationMode.Local, ...)]]'' in .NET assembly); | ||
- | * Downloading all files created in the last 24 hours (using [[file_mask|file mask]] ''*>=1D''; e.g. ''%%get -filemask="*>=1D" /home/user/*%%'', or an equivalent in .NET assembly). | ||
- | * Downloading all files created today (using ''[[scripting#timestamp|%TIMESTAMP%]]'' syntax to format [[file_mask|file mask]] with today's time constraint, e.g. ''%%get -filemask="*>=%TIMESTAMP#yyyy-mm-dd%" /home/user/*%%'', or an equivalent in .NET assembly). | ||
- | |||
- | ===== [[upload_most_recent_file]] Uploading the most recent file ===== | ||
- | |||
- | |||
- | ==== [[library]] Using WinSCP .NET Assembly ==== | ||
- | Use [[library|WinSCP .NET assembly]] from your favorite language. | ||
- | |||
- | If you do not have your favorite language, use [[library_powershell|PowerShell]]: | ||
- | |||
- | <code powershell> | ||
- | 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) | ||
- | |||
- | $localPath = "c:\toupload\" | ||
- | $remotePath = "/home/user/" | ||
- | |||
- | # Gel list of files in the directory | ||
- | $directoryInfo = $session.ListDirectory($remotePath) | ||
- | |||
- | # Select the most recent file. | ||
- | # The !$_.PsIsContainer test excludes subdirectories. | ||
- | # With PowerShell 3.0, you can replace this with -File switch of Get-ChildItem. &win8 | ||
- | $latest = | ||
- | Get-ChildItem -Path $localPath | | ||
- | Where-Object {!$_.PsIsContainer} | | ||
- | Sort-Object LastWriteTime -Descending | | ||
- | Select-Object -First 1 | ||
- | |||
- | # Any file at all? | ||
- | if ($latest -eq $Null) | ||
- | { | ||
- | Write-Host "No file found" | ||
- | exit 1 | ||
- | } | ||
- | |||
- | # Upload the selected file | ||
- | $session.PutFiles($session.EscapeFileMask($localPath + $latest.Name), $remotePath).Check() | ||
- | } | ||
- | finally | ||
- | { | ||
- | # Disconnect, clean up | ||
- | $session.Dispose() | ||
- | } | ||
- | |||
- | exit 0 | ||
- | } | ||
- | catch [Exception] | ||
- | { | ||
- | Write-Host $_.Exception.Message | ||
- | exit 1 | ||
- | } | ||
- | </code> | ||
- | |||
- | ==== Using WinSCP Scripting ==== | ||
- | You may use following batch file that calls WinSCP [[scripting|script]]:((Inspired by SuperUser question [[http://superuser.com/a/158426/213663|Upload only the latest file with WinSCP]].)) | ||
- | |||
- | <code batch> | ||
- | @echo off | ||
- | set SESSION=sftp://user:password@example.com/ | ||
- | set LOCAL_PATH=c:\toupload\ | ||
- | set REMOTE_PATH=/home/user/ | ||
- | |||
- | for /f "delims=" %%i in ('dir /b /od %LOCAL_PATH%\*') do set LATEST=%%i | ||
- | if "%LATEST%" == "" goto NO_FILE | ||
- | |||
- | winscp.com /command ^ | ||
- | "option batch abort" ^ | ||
- | "option confirm off" ^ | ||
- | "open %SESSION%" ^ | ||
- | "put %LOCAL_PATH%%LATEST% %REMOTE_PATH%" ^ | ||
- | "exit" | ||
- | exit %ERRORLEVEL% | ||
- | |||
- | :NO_FILE | ||
- | echo No file found | ||
- | exit 1 | ||
- | </code> | ||
- | |||
- | ==== Alternatives ==== | ||
- | |||
- | Some of following alternatives can be easier to implement or actually even more appropriate for your specific task: | ||
- | |||
- | * Synchronizing a local directory to a remote directory (using ''[[scriptcommand_synchronize|synchronize remote]]'' in scripting or ''[[library_session_synchronizedirectories|Session.SynchronizeDirectories(SynchronizationMode.Remote, ...)]]'' in .NET assembly); | ||
- | * Uploading all files created in the last 24 hours (using [[file_mask|file mask]] ''*>=1D''; e.g. ''%%put -filemask="*>=1D" c:\toupload\*%%'', or an equivalent in .NET assembly). | ||
- | * Uploading all files created today (using ''[[scripting#timestamp|%TIMESTAMP%]]'' syntax to format [[file_mask|file mask]] with today's time constraint, e.g. ''%%put -filemask="*>=%TIMESTAMP#yyyy-mm-dd%" c:\toupload\*%%'', or an equivalent in .NET assembly). | ||
- | |||
- | ===== [[checking_file_existence]] Checking file existence ===== | ||
- | |||
- | |||
- | |||
- | ==== [[remote]] Remote file existence ==== | ||
- | |||
- | === Using WinSCP .NET Assembly === | ||
- | Use method ''[[library_session_fileexists|Session.FileExists]]'' from [[library|WinSCP .NET assembly]]. | ||
- | |||
- | If you do not have your favorite language, use [[library_powershell|PowerShell]]: | ||
- | |||
- | <code powershell> | ||
- | $remotePath = "/home/user/test.txt" | ||
- | |||
- | if ($session.FileExists($remotePath)) | ||
- | { | ||
- | Write-Host ("File {0} exists" -f $remotePath) | ||
- | } | ||
- | </code> | ||
- | |||
- | See complete [[library_session_fileexists#powershell|PowerShell example for Session.FileExists]]. | ||
- | |||
- | If you are not looking for a specific file, but for any file matching a mask (e.g. ''*.txt''), you need to use ''Session.ListDirectory'' and [[library_example_listing_files_matching_wildcard|query returned list of files]]. | ||
- | |||
- | ~~AD~~ | ||
- | |||
- | === [[scripting]] Using WinSCP Scripting === | ||
- | You can use a ''[[scriptcommand_stat|stat]]'' command in ''[[scriptcommand_option|option batch abort]]'' mode to query file attributes. If the file does not exist, the ''stat'' command fails and so does the script. Then, [[scripting#checking_results|test WinSCP exit code]] to determine, if the file exists or not. | ||
- | |||
- | <code batch> | ||
- | @echo off | ||
- | |||
- | set REMOTE_PATH=/home/user/test.txt | ||
- | winscp.com /command ^ | ||
- | "option batch abort" ^ | ||
- | "open mysession" ^ | ||
- | "stat %REMOTE_PATH%" ^ | ||
- | "exit" | ||
- | |||
- | if %ERRORLEVEL% neq 0 goto error | ||
- | |||
- | echo File %REMOTE_PATH% exists | ||
- | rem Do something | ||
- | exit 0 | ||
- | |||
- | :error | ||
- | echo Error or file %REMOTE_PATH% not exists | ||
- | exit 1 | ||
- | </code> | ||
- | |||
- | ==== [[local]] Local file existence ==== | ||
- | |||
- | * In [[library_powershell|PowerShell]], use ''[[http://technet.microsoft.com/en-us/library/hh849776.aspx|Test-Path]]'' cmdlet. See [[library_session_getfiles#powershell|example]]. | ||
- | * In a batch file, use ''[[http://technet.microsoft.com/en-us/library/cc754335.aspx|if exist]]'' command. See [[guide_automation_conditional#scripting|example]]. | ||
- | * In .NET, use ''[[http://msdn.microsoft.com/en-us/library/system.io.file.exists.aspx|File.Exists]]'' method. See [[library_session_getfiles#csharp|C#]] and [[library_session_getfiles#vbnet|VB.NET]] example. | ||
- | * In WSH, use ''[[http://msdn.microsoft.com/en-us/library/x23stk5t.aspx|Scripting.FileSystemObject.FileExists]]'' method. See [[library_session_getfiles#jscript|JScript]] and [[library_session_getfiles#jscript|VBScript]] example. | ||
- | |||
- | ===== [[local_move_after_successful_upload]] Moving local files to different location after successful upload ===== | ||
- | |||
- | |||
- | |||
- | |||
- | ==== [[library]] Using WinSCP .NET Assembly ==== | ||
- | Use [[library|WinSCP .NET assembly]] from your favorite language. | ||
- | |||
- | If you do not have your favorite language, use [[library_powershell|PowerShell]]: | ||
- | |||
- | <code powershell> | ||
- | 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) | ||
- | |||
- | $localPath = "C:\upload\*" | ||
- | $remotePath = "/home/user/" | ||
- | $backupPath = "C:\backup\" | ||
- | |||
- | # Upload files, collect results | ||
- | $transferResult = $session.PutFiles($localPath, $remotePath) | ||
- | |||
- | # Iterate over every transfer | ||
- | foreach ($transfer in $transferResult.Transfers) | ||
- | { | ||
- | # Success or error? | ||
- | if ($transfer.Error -eq $Null) | ||
- | { | ||
- | Write-Host ("Upload of {0} succeeded, moving to backup" -f | ||
- | $transfer.FileName) | ||
- | # Upload succeeded, move source file to backup | ||
- | Move-Item $transfer.FileName $backupPath | ||
- | } | ||
- | else | ||
- | { | ||
- | Write-Host ("Upload of {0} failed: {1}" -f | ||
- | $transfer.FileName, $transfer.Error.Message) | ||
- | } | ||
- | } | ||
- | } | ||
- | finally | ||
- | { | ||
- | # Disconnect, clean up | ||
- | $session.Dispose() | ||
- | } | ||
- | |||
- | exit 0 | ||
- | } | ||
- | catch [Exception] | ||
- | { | ||
- | Write-Host $_.Exception.Message | ||
- | exit 1 | ||
- | } | ||
- | </code> | ||
- | |||
- | ==== Using WinSCP Scripting ==== | ||
- | WinSCP scripting does not support move command for local files. Instead you can combine WinSCP script with batch file: | ||
- | |||
- | <code winscp> | ||
- | option batch abort | ||
- | option confirm off | ||
- | # Connect | ||
- | open mysession | ||
- | # Upload the files | ||
- | put *.* | ||
- | </code> | ||
- | |||
- | Launch the above script from batch file like the one below: | ||
- | |||
- | <code batch> | ||
- | winscp.com /script=example.txt | ||
- | if %ERRORLEVEL% neq 0 goto error | ||
- | |||
- | echo Upload succeeded, moving local files | ||
- | move *.* c:\backup\ | ||
- | exit 0 | ||
- | |||
- | :error | ||
- | echo Upload failed, keeping local files | ||
- | exit 1 | ||
- | </code> | ||
- | |||
- | ===== [[locking_files_while_uploading]] Locking files while uploading / Upload to temporary file name ===== | ||
- | |||
- | You may have an automated system monitoring a remote folder and you want to prevent it from accidentally picking a file that has not finished uploading yet. As majority of SFTP and FTP servers do not support file locking (and neither does WinSCP), you need to prevent the automated system from picking the file otherwise. | ||
- | |||
- | Common workarounds are: | ||
- | |||
- | - Upload "done" file once an upload of data files finishes and have the automated system wait for the "done" file before processing the data files. This is easy solution, but won't work in multi-user environment. | ||
- | - Upload data files to temporary ("upload") folder and move them atomically to target folder once the upload finishes. | ||
- | - Upload data files to distinct temporary name, e.g. with ''.filepart'' extension, and rename them atomically once the upload finishes. Have the automated system ignore the ''.filepart'' files. | ||
- | |||
- | Here we focus on the third approach (although the second is very similar, implementation-wise). | ||
- | |||
- | ==== Using Transfer to temporary filename feature ==== | ||
- | |||
- | With [[sftp|SFTP protocol]], you can use [[resume#automatic|Transfer to temporary filename]] feature to have WinSCP handle the rename automatically for you. | ||
- | |||
- | In [[scripting]], use: | ||
- | |||
- | <code winscp> | ||
- | put -resumesupport=on d:\toupload\*.txt /home/martin/upload/ | ||
- | </code> | ||
- | |||
- | With [[library|WinSCP .NET assembly]], use: | ||
- | |||
- | <code powershell> | ||
- | $transferOptions = New-Object WinSCP.TransferOptions | ||
- | $transferOptions.ResumeSupport.State = [WinSCP.TransferResumeSupportState]::On | ||
- | $session.PutFiles("d:\toupload\*.txt", "/home/martin/upload/", $False, $transferOptions).Check() | ||
- | </code> | ||
- | |||
- | ==== Moving/renaming uploaded files when upload finishes ==== | ||
- | |||
- | If you need to use a different name pattern or a protocol different from SFTP or you want to take the second approach, you need to code the rename/move. | ||
- | |||
- | Following example shows implementation of the third approach using [[library|WinSCP .NET assembly]] in [[library_powershell|PowerShell]]: | ||
- | |||
- | <code powershell> | ||
- | 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) | ||
- | |||
- | $localPath = "c:\toupload\" | ||
- | $remotePath = "/home/user/upload/" | ||
- | # Deliberately using an underscore instead of a dot, | ||
- | # as the dot has specific meaning in operation mask | ||
- | $suffix = "_filepart" | ||
- | |||
- | $transferOptions = New-Object WinSCP.TransferOptions | ||
- | # Particularly with SFTP protocol, prevent additional .filepart suffix | ||
- | # from being added to uploaded files larger than 100 KB | ||
- | $transferOptions.ResumeSupport.State = [WinSCP.TransferResumeSupportState]::Off | ||
- | |||
- | # Upload all .txt files with temporary "_filepart" suffix | ||
- | $transferResult = | ||
- | $session.PutFiles(($localPath + "*.txt"), ($remotePath + "*.*" + $suffix), | ||
- | $False, $transferOptions) | ||
- | |||
- | # Throw on any error | ||
- | $transferResult.Check() | ||
- | |||
- | # Rename uploaded files | ||
- | foreach ($transfer in $transferResult.Transfers) | ||
- | { | ||
- | # Remove suffix | ||
- | $finalName = $transfer.Destination.SubString(0, $transfer.Destination.Length - $suffix.Length) | ||
- | Write-Host ("Renaming uploaded file {0} to final name {1}" -f $transfer.Destination, $finalName) | ||
- | # Rename uploaded file to its final name | ||
- | $session.MoveFile($transfer.Destination, $finalName) | ||
- | } | ||
- | } | ||
- | finally | ||
- | { | ||
- | # Disconnect, clean up | ||
- | $session.Dispose() | ||
- | } | ||
- | |||
- | exit 0 | ||
- | } | ||
- | catch [Exception] | ||
- | { | ||
- | Write-Host $_.Exception.Message | ||
- | exit 1 | ||
- | } | ||
- | </code> | ||
- | |||
- | ===== [[synchronize_any_local_file]] Shortcut to synchronize any local directory with remote directory ===== | ||
- | |||
- | |||
- | |||
- | You may want to have a script that synchronizes any local directory with a same-named subdirectory of fixed remote path, e.g.: | ||
- | * ''c:\www\gallery'' with ''/home/user/www/gallery''; | ||
- | * ''c:\users\username\www\forum'' with ''/home/user/www/forum''. &winpath | ||
- | |||
- | Such a script is particularly useful for integrating with Windows Explorer's 'Send To' menu. | ||
- | |||
- | First create wrapper batch file to store the paths you want to synchronize into environment variables (change ''/home/user/www/'' to remote path root you want to synchronize against): | ||
- | <code batch> | ||
- | winscp.com /script=example.txt /parameter %1 "/home/user/www/%~n1%~x1" | ||
- | </code> | ||
- | |||
- | The script ''example.txt'' may look like: | ||
- | |||
- | <code winscp> | ||
- | # Being intended for interactive session, we are not enabling batch mode | ||
- | # Connect | ||
- | open mysession | ||
- | # Synchronize paths provided via environment variables | ||
- | synchronize remote "%1%" "%2%" | ||
- | </code> | ||
- | |||
- | Then you can make a shortcut to the batch file: | ||
- | * When placed on desktop, you can drop any local directory to it to start synchronization; | ||
- | * When placed to ''C:\Users\username\AppData\Roaming\Microsoft\Windows\SendTo'', you can use //Send To > Your Shortcut// from context menu of any local directory. &winpath | ||
- | |||
- | |||
- | |||
- | ===== [[auto_compress_download]] Automatically compress files before download ===== | ||
- | Following script compresses selected files into tar/gzip archive and downloads it: | ||
- | |||
- | <code winscp> | ||
- | option batch abort | ||
- | option confirm off | ||
- | open mysession | ||
- | cd %1% | ||
- | call tar -czf /tmp/archive.tar.gz %2% | ||
- | lpwd | ||
- | get -delete /tmp/archive.tar.gz | ||
- | exit | ||
- | </code> | ||
- | |||
- | Launch the above script from batch file like the one below, which automatically decompresses the archive: | ||
- | |||
- | <code batch> | ||
- | winscp.com /script=example.txt /parameter %* | ||
- | if %ERRORLEVEL% neq 0 goto error | ||
- | |||
- | echo Retrieving files succeeded | ||
- | gzip -d archive.tar.gz | ||
- | tar -xf archive.tar | ||
- | del archive.tar | ||
- | exit 0 | ||
- | |||
- | :error | ||
- | echo Retrieving files failed | ||
- | exit 1 | ||
- | </code> | ||
- | |||
- | Example of running the batch file to download all files under ''/home/user/www'': | ||
- | |||
- | <code> | ||
- | example.bat /home/user/www *.* | ||
- | </code> | ||
- | |||
- | The batch file needs Windows ports of ''gzip'' and ''tar'' tools. You can get them from [[http://sourceforge.net/projects/unxutils/|UnxUtils]] project. | ||
- | |||
- | ===== [[vbnet_robust_example]] Running WinSCP from VB.NET ===== | ||
- | &deprecated_use_net | ||
- | |||
- | Following is more robust alternative to simple example contained in guide to [[guide_dotnet|SFTP file transfers in .NET]]. | ||
- | |||
- | <code vbnet> | ||
- | Imports System | ||
- | Imports System.IO | ||
- | Imports System.Diagnostics | ||
- | Imports System.Xml | ||
- | Imports System.Xml.XPath | ||
- | Imports System.Configuration.ConfigurationManager | ||
- | |||
- | Public Class SFTP | ||
- | ' SFTP support, built on WinSCP | ||
- | Public Shared Function PutSFTP(ByRef filename As String, ByRef remotehost As String, ByRef username As String, ByRef password As String, _ | ||
- | Optional ByVal outfilename As String = Nothing, Optional ByVal output As String = Nothing, | ||
- | Optional ByRef errmsg As String = Nothing) As Boolean | ||
- | |||
- | ' Run hidden WinSCP process | ||
- | Dim winscp As Process = New Process() | ||
- | Dim logname As String = Path.ChangeExtension(Path.GetTempFileName, "xml") | ||
- | With winscp.StartInfo | ||
- | ' SFTPExecutable needs to be defined in app.config to point to winscp.com | ||
- | Try | ||
- | .FileName = AppSettings("SFTPExecutable") | ||
- | If .FileName Is Nothing OrElse .FileName.Length = 0 Then Throw (New Exception("from PutSFTP: SFTPExecutable not set in config file.")) | ||
- | Catch ex As Exception | ||
- | errmsg = ex.Message | ||
- | Return False | ||
- | End Try | ||
- | .Arguments = "/xmllog=" + logname | ||
- | .UseShellExecute = False | ||
- | .RedirectStandardInput = True | ||
- | .RedirectStandardOutput = True | ||
- | .CreateNoWindow = True | ||
- | End With | ||
- | Try | ||
- | winscp.Start() | ||
- | Catch ex As Exception | ||
- | errmsg = "from PutSFTP: Could not run the WinSCP executable " & winscp.StartInfo.FileName & Environment.NewLine & ex.Message | ||
- | Return False | ||
- | End Try | ||
- | |||
- | ' Feed in the scripting commands | ||
- | With winscp.StandardInput | ||
- | .WriteLine("option batch abort") | ||
- | .WriteLine("option confirm off") | ||
- | .WriteLine("open sftp://" & username & ":" & password & "@" & remotehost & "/") | ||
- | If outfilename Is Nothing Then .WriteLine("put " & filename) Else .WriteLine("put " & filename & " """ & outfilename & """") | ||
- | .Close() | ||
- | End With | ||
- | If output IsNot Nothing Then output = winscp.StandardOutput.ReadToEnd() | ||
- | |||
- | ' Wait until WinSCP finishes | ||
- | winscp.WaitForExit() | ||
- | |||
- | ' Parse and interpret the XML log | ||
- | ' (Note that in case of fatal failure the log file may not exist at all) | ||
- | If Not File.Exists(logname) Then | ||
- | errmsg = "from PutSFTP: The WinSCP executable appears to have crashed." | ||
- | Return False | ||
- | End If | ||
- | |||
- | Dim log As XPathDocument = New XPathDocument(logname) | ||
- | Dim ns As XmlNamespaceManager = New XmlNamespaceManager(New NameTable()) | ||
- | ns.AddNamespace("w", "http://winscp.net/schema/session/1.0") | ||
- | Dim nav As XPathNavigator = log.CreateNavigator() | ||
- | |||
- | ' Success (0) or error? | ||
- | Dim status As Boolean = (winscp.ExitCode = 0) | ||
- | If Not status Then | ||
- | errmsg = "from PutSFTP: There was an error transferring " & filename & "." | ||
- | ' See if there are any messages associated with the error | ||
- | For Each message As XPathNavigator In nav.Select("//w:message", ns) | ||
- | errmsg &= Environment.NewLine & message.Value | ||
- | Next message | ||
- | End If | ||
- | |||
- | Try | ||
- | My.Computer.FileSystem.DeleteFile(logname) | ||
- | Catch ex As Exception | ||
- | ' at least we tried to clean up | ||
- | End Try | ||
- | |||
- | Return status | ||
- | End Function | ||
- | End Class | ||
- | </code> | ||
- | |||
- | <trailer> | ||
- | ===== Further Reading ===== | ||
- | |||
- | |||
- | |||
- | * Guide to [[guide_automation|scripting/automation]]; | ||
- | * [[library|WinSCP .NET assembly]]; | ||
- | * [[library_powershell|Using WinSCP .NET Assembly from PowerShell]]. | ||
- | </trailer> | ||
- | |||
- | <nosplit> | ||
===== Other Examples ===== | ===== Other Examples ===== | ||
* Guide to [[guide_automation|scripting/automation]]; | * Guide to [[guide_automation|scripting/automation]]; | ||
* Guide to [[guide_automation_advanced|advanced scripting]]; | * Guide to [[guide_automation_advanced|advanced scripting]]; | ||
- | * See [[library_examples|WinSCP .NET assembly examples]] for advanced tasks. | + | * See [[library_examples|*]] for advanced tasks. |
- | </nosplit> | + | |