Differences
This shows you the differences between the selected revisions of the page.
2022-06-16 | 2023-10-31 | ||
5.20 Change: SHA-256 fingerprints are not padded anymore (martin) | synchronization (martin) | ||
Line 1: | Line 1: | ||
- | ====== Automating transfers in parallel connections over SFTP/FTP protocol ====== | + | ====== Automating transfers or synchronization in parallel connections over SFTP/FTP protocol ====== |
===== Download ===== | ===== Download ===== | ||
Line 395: | Line 395: | ||
} | } | ||
</code> | </code> | ||
+ | |||
+ | ===== Synchronization ===== | ||
+ | |||
+ | ==== [[synchronization_powershell]] PowerShell ==== | ||
+ | |||
+ | //Regarding ''Start-ThreadJob'' cmdlet, see the comment in [[#powershell|Download section]].// | ||
+ | |||
+ | <code powershell> | ||
+ | param ( | ||
+ | $sessionUrl = "sftp://user:password;fingerprint=ssh-rsa-xxxxxxxxxxx...@example.com/", | ||
+ | $remotePath = "/remote/path/", | ||
+ | $localPath = "c:\local\path\", | ||
+ | $removeFiles = $False, | ||
+ | $connections = 3 | ||
+ | ) | ||
+ | |||
+ | try | ||
+ | { | ||
+ | $assemblyFilePath = "WinSCPnet.dll" | ||
+ | # Load WinSCP .NET assembly | ||
+ | Add-Type -Path $assemblyFilePath | ||
+ | |||
+ | # Setup session options | ||
+ | $sessionOptions = New-Object WinSCP.SessionOptions | ||
+ | $sessionOptions.ParseUrl($sessionUrl) | ||
+ | |||
+ | $started = Get-Date | ||
+ | # Plain variables cannot be modified in job threads | ||
+ | $stats = @{ | ||
+ | count = 0 | ||
+ | } | ||
+ | |||
+ | try | ||
+ | { | ||
+ | # Connect | ||
+ | Write-Host "Connecting..." | ||
+ | $session = New-Object WinSCP.Session | ||
+ | $session.Open($sessionOptions) | ||
+ | |||
+ | Write-Host "Comparing directories..." | ||
+ | $differences = | ||
+ | $session.CompareDirectories( | ||
+ | [WinSCP.SynchronizationMode]::Both, $localPath, $remotePath, $removeFiles) | ||
+ | if ($differences.Count -eq 0) | ||
+ | { | ||
+ | Write-Host "No changes found." | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | if ($differences.Count -lt $connections) | ||
+ | { | ||
+ | $connections = $differences.Count; | ||
+ | } | ||
+ | $differenceEnumerator = $differences.GetEnumerator() | ||
+ | |||
+ | for ($i = 1; $i -le $connections; $i++) | ||
+ | { | ||
+ | Start-ThreadJob -Name "Connection $i" -ArgumentList $i { | ||
+ | param ($no) | ||
+ | |||
+ | try | ||
+ | { | ||
+ | Write-Host "Starting connection $no..." | ||
+ | |||
+ | $syncSession = New-Object WinSCP.Session | ||
+ | $syncSession.Open($using:sessionOptions) | ||
+ | |||
+ | while ($True) | ||
+ | { | ||
+ | [System.Threading.Monitor]::Enter($using:differenceEnumerator) | ||
+ | try | ||
+ | { | ||
+ | if (!($using:differenceEnumerator).MoveNext()) | ||
+ | { | ||
+ | break | ||
+ | } | ||
+ | |||
+ | $difference = ($using:differenceEnumerator).Current | ||
+ | ($using:stats).count++ | ||
+ | } | ||
+ | finally | ||
+ | { | ||
+ | [System.Threading.Monitor]::Exit($using:differenceEnumerator) | ||
+ | } | ||
+ | |||
+ | Write-Host "$difference in $no..." | ||
+ | $difference.Resolve($syncSession) | Out-Null | ||
+ | } | ||
+ | |||
+ | Write-Host "Connection $no done" | ||
+ | } | ||
+ | finally | ||
+ | { | ||
+ | $syncSession.Dispose() | ||
+ | } | ||
+ | } | Out-Null | ||
+ | } | ||
+ | |||
+ | Write-Host "Waiting for connections to complete..." | ||
+ | Get-Job | Receive-Job -Wait | ||
+ | |||
+ | Write-Host "Done" | ||
+ | } | ||
+ | |||
+ | $ended = Get-Date | ||
+ | Write-Host "Took $(New-TimeSpan -Start $started -End $ended)" | ||
+ | Write-Host "Synchronized $($stats.count) differences" | ||
+ | } | ||
+ | finally | ||
+ | { | ||
+ | # Disconnect, clean up | ||
+ | $session.Dispose() | ||
+ | } | ||
+ | |||
+ | exit 0 | ||
+ | } | ||
+ | catch | ||
+ | { | ||
+ | Write-Host "Error: $($_.Exception.Message)" | ||
+ | exit 1 | ||
+ | } | ||
+ | </code> | ||
+ |