Skip to content

Instantly share code, notes, and snippets.

@peaeater
Created December 12, 2022 18:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peaeater/2b76b83cba9dd664edcacbd339238ba5 to your computer and use it in GitHub Desktop.
Save peaeater/2b76b83cba9dd664edcacbd339238ba5 to your computer and use it in GitHub Desktop.
Powershell using WinSCP to sync directories over FTP with file mask.
<#
Sync a directory to remote server in FTP mode
Peter Tyrrell
#>
param(
[Parameter(Mandatory = $false, Position = 0)]
[string]$logsrc = "",
[Parameter(Mandatory = $true, Position = 1)]
[string]$hostname,
[Parameter(Mandatory = $true, Position = 2)]
[string]$username,
[Parameter(Mandatory = $true, Position = 3)]
[string]$password,
[Parameter(Mandatory = $true, Position = 4)]
[string]$fingerprint,
[Parameter(Mandatory = $false, Position = 5)]
[int]$port = 21,
[Parameter(Mandatory = $false, Position = 6)]
[string]$remotePath = "/",
[Parameter(Mandatory = $true, Position = 7)]
[string]$localPath,
[Parameter(Mandatory = $false, Position = 8)]
[string]$winscp = "C:\Program Files (x86)\WinSCP\WinSCPNET.dll",
[Parameter(Mandatory = $false, Position = 9)]
[string]$ftpMode = "passive",
[Parameter(Mandatory = $false, Position = 10)]
[string]$ftpSecure = "explicit",
[Parameter(Mandatory = $false, Position = 11)]
[string]$filemask = $null
)
. .\helper.logging.ps1
function fileTransferred {
param($e)
# file transfer status
if ($null -eq $e.Error) {
logInfo -logsrc $logsrc -msg ("INFO {0} upload OK" -f $e.FileName)
}
else {
logError -logsrc $logsrc -msg ("ERROR {0} upload failure: {1}" -f $e.FileName, $e.Error)
exit 1
}
# file permissions status
if ($null -ne $e.Chmod) {
if ($null -ne $e.Chmod.Error) {
logError -logsrc $logsrc -msg ("ERROR {0} set permissions failure: {1}" -f $e.Chmod.FileName, $e.Chmod.Error)
}
}
# timestamp status
if ($null -ne $e.Touch) {
if ($null -ne $e.Touch.Error) {
logError -logsrc $logsrc -msg ("ERROR {0} set timestamp failure: {1}" -f $e.Touch.FileName, $e.Touch.Error)
}
}
}
<#
Push files to remote server.
#>
try {
# load winscp assembly
Add-Type -Path $winscp
# session options
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.Protocol = [WinSCP.Protocol]::Ftp
if ($ftpSecure -like "explicit") {
$sessionOptions.FtpSecure = [WinSCP.FtpSecure]::Explicit
}
elseif ($ftpSecure -like "implicit") {
$sessionOptions.FtpSecure = [WinSCP.FtpSecure]::Implicit
}
else {
$sessionOptions.FtpSecure = [WinSCP.FtpSecure]::None
}
if ($ftpMode -like "active") {
$sessionOptions.FtpMode = [WinSCP.FtpMode]::Active
}
else {
$sessionOptions.FtpMode = [WinSCP.FtpMode]::Passive
}
$sessionOptions.TlsHostCertificateFingerprint = $fingerprint
$sessionOptions.PortNumber = $port
$sessionOptions.HostName = $hostname
$sessionOptions.UserName = $username
$sessionOptions.Password = $password
$session = New-Object WinSCP.Session
# sync dirs
try {
# continuously report sync progress
$session.add_FileTransferred( { fileTransferred($_) } )
# connect
$session.Open($sessionOptions)
# apply file mask
$transferOptions = $null
if ($null -ne $filemask) {
$transferOptions = New-Object WinSCP.TransferOptions
$transferOptions.FileMask = $filemask
}
# sync files 1 direction, from local => remote. Push all local files, newer and older, and delete obsolete remote files.
$syncResult = $session.SynchronizeDirectories([WinSCP.SynchronizationMode]::Remote, $localPath, $remotePath, $true, $true, [WinSCP.SynchronizationCriteria]::Time, $transferOptions)
# throw exception for any error
$syncResult.Check()
$uploadCount = $syncResult.Uploads.Count
$downloadCount = $syncResults.Downloads.Count
$removalCount = $syncResults.Removals.Count
logInfo -logsrc $logsrc -msg (("File sync to {0} successful: {1} uploaded, {2} downloaded, {3} removed." -f $hostname, $uploadCount, $downloadCount, $removalCount))
}
finally {
# disconnect, clean up
$session.Dispose()
}
exit 0
}
catch [Exception] {
# any uncaught exception bubbles up here
logError -logsrc $logsrc -msg $_.Exception
exit 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment