Skip to content

Instantly share code, notes, and snippets.

@FeodorFitsner
Created September 27, 2016 06:04
Show Gist options
  • Save FeodorFitsner/7016cc13bc91db525331bda55c232ed1 to your computer and use it in GitHub Desktop.
Save FeodorFitsner/7016cc13bc91db525331bda55c232ed1 to your computer and use it in GitHub Desktop.
Parallel copying over FTP with WinSCP
param (
$sessionUrl = "ftp-host-name",
$username = "your-username",
$password = "your-password",
$remotePath = "/",
$localPath = "C:\projects\...",
$batches = 20
)
# Event handling function
function FileTransferred {
param($e)
if ($e.Error -eq $Null)
{
#Write-Host ("Transfer of {0} succeeded" -f $e.FileName)
}
else
{
Write-Host ("Transfer of {0} failed: {1}" -f $e.FileName, $e.Error)
}
}
Function Format-FileSize() {
Param ([int]$size)
If ($size -gt 1TB) {[string]::Format("{0:0.00} TB", $size / 1TB)}
ElseIf ($size -gt 1GB) {[string]::Format("{0:0.00} GB", $size / 1GB)}
ElseIf ($size -gt 1MB) {[string]::Format("{0:0.00} MB", $size / 1MB)}
ElseIf ($size -gt 1KB) {[string]::Format("{0:0.00} kB", $size / 1KB)}
ElseIf ($size -gt 0) {[string]::Format("{0:0} B", $size)}
Else {""}
}
$assemblyPath = "c:\Program Files (x86)\WinSCP"
$dllPath = (Join-Path $assemblyPath "WinSCPnet.dll")
# Load WinSCP .NET assembly
Add-Type -Path $dllPath
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
Protocol = [WinSCP.Protocol]::Ftp
HostName = $sessionUrl
UserName = $username
Password = $password
}
$started = Get-Date
#$session = New-Object WinSCP.Session
#$session.Open($sessionOptions)
#$result = $session.RemoveFiles($remotePath)
#$session.Close()
#Write-Host ("Files deleted: $result")
try
{
Write-Host ("Retrieving files...")
# Retrieve list of files and sort them from larges to smallest
$files = Get-ChildItem -Path $localPath -Recurse –File
# Calculate total size of all files
$total = Format-FileSize(($files | Measure-Object -Property Length -Sum).Sum)
Write-Host ("Preparing {0} file(s) with total size of {1}..." -f $files.Length, $total)
# Start the background job for the batch
$result = $files | Split-Pipeline -Verbose -Count $batches -Function FileTransferred, Format-FileSize -Variable dllPath, sessionOptions, remotePath, localPath { $files = @($input)
# Load WinSCP .NET assembly.
# Need to use an absolute path as the Job is started from user's documents folder.
Add-Type -Path $dllPath
$size = $files.Count
$total = ( $files | Measure-Object -Property Length -Sum).Sum
$totalF = Format-FileSize($total)
Write-Host ("Connecting host for uploading {0} file(s) with total size of {1}..." -f $size, $totalF)
$session = New-Object WinSCP.Session
# Subscribe to the event
#$session.add_FileTransferred( { FileTransferred($_) } )
$session.Open($sessionOptions)
# Upload the files selected for this batch
foreach ($file in $files)
{
$localFilePath = $file.FullName
$remoteFilePath = $session.TranslateLocalPathToRemote($file.FullName, $localPath, $remotePath);
$subtotal = $subtotal + $file.Length
$progress = [Math]::Round($subtotal * 100 / $total, 2)
$size = Format-FileSize($file.Length)
Write-Host ("Upload $remoteFilePath ({0})" -f $size)
[timespan]$time = (Measure-Command {
$session.PutFiles($file.FullName, $session.EscapeFileMask($remoteFilePath)).Check()
}).Duration()
$rate = Format-FileSize($file.Length / $time.TotalSeconds)
Write-Host ("Complete $remoteFilePath ({1}/s, {2}) - {0}% of batch" -f $progress, $rate, $time)
}
# Disconnect, clean up
Write-Host ("Disconnecting host {0}..." -f $no)
Write-Host $result
$session.Dispose()
}
Write-Host "All files uploaded."
$ended = Get-Date
Write-Host ("Took {0}" -f (New-TimeSpan -Start $started -End $ended))
}
finally
{
# Disconnect, clean up
}
exit 0
# Module for Parallel Data Processing in PowerShell
# https://github.com/nightroman/SplitPipeline
Install-Package SplitPipeline -ProviderName NuGet -Force
Install-Module SplitPipeline -Force
# Install WinSCP with .NET Assembly
choco install winscp -y
$env:Path += ";c:\Program Files (x86)\WinSCP"
# Execute deploy script
powershell -file deploy.ps1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment