Search code examples
ftpsftpwinscpwinscp-net

A WinSCP script to download, rename, and move files


Disclaimer #1: I posted this question on the WinSCP's forum but haven't received any replies and this issue is time-sensitive.
Disclaimer #2: I'm basing the legitimacy of this cross-post on advice found on the subject from Meta.
With that preamble...

Up until now, I have been been using WS_FTP but would like to switch to WinSCP. I'm trying to convert this WS_FTP script into WinSCP:

"C:\Program Files (x86)\Ipswitch\WS_FTP 12\wsftppro.exe"
-s "sftp://USERNAME:[email protected]/USERNAME/logs/*.sqb"
-d "local:C:\PccDataRelay\LogDownloads\"
-rename tx_[yyyy]-[mm]-[dd]_[hh]-[tt]-[ss]_[OnlyName].[OnlyExt]
-move "/USERNAME/logs/transferred/"

I've been able to convert it partially:

cd C:\PccDataRelay\TestDownloads

"C:\Program Files (x86)\WinSCP\winscp.com" /ini=nul /log=C:\PccDataRelay\AuditLogs\incremental_download.log /command ^
    "open sftp://USERNAME:[email protected]/USERNAME/logs/ -hostkey=""ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx""" ^
    "get /USERNAME/logs/*.sqb" ^
    "exit"

But that only downloads the files. How can I get it to rename and move the original files while also leaving them in-place on the FTP site?


Solution

  • WinSCP does not have a feature similar to -rename and -move switches. So it's not easy to implement this task in a simple scripting so that it behaves transactionally (renames and moves only the files that were successfully downloaded)


    But you can use WinSCP .NET assembly from a PowerShell script.

    # Load WinSCP .NET assembly
    Add-Type -Path "WinSCPnet.dll"
    
    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
        Protocol = [WinSCP.Protocol]::Sftp
        HostName = "ftpus.pointclickcare.com"
        UserName = "USERNAME"
        Password = "PASSWORD"
        SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxx...="
    }
    
    # Connect
    Write-Host "Connecting..."
    $session = New-Object WinSCP.Session
    $session.SessionLogPath = "C:\PccDataRelay\AuditLogs\incremental_download.log"
    $session.Open($sessionOptions)
    
    # Download files
    $transferResult =
        $session.GetFilesToDirectory(
            "/USERNAME/logs", "C:\PccDataRelay\LogDownloads", "*.sqb")
    
    # Process source files
    foreach ($transfer in $transferResult.Transfers)
    {
        $oldName = $transfer.FileName
        # Success or error?
        if ($transfer.Error -eq $Null)
        {
            $newName =
                "/USERNAME/logs/transferred/tx_" +
                (Get-Date -Format "yyyy-MM-dd-hh-mm-ss") + "_" +
                [IO.Path]::GetFileName($oldName)
            Write-Host (
                "Download of $oldName succeeded, moving to backup $newName")
            $session.MoveFile($oldName, $newName)
        }
        else
        {
            Write-Host (
                "Download of $oldName failed: $($transfer.Error.Message)")
        }
    }
    

    Some references that this answer is based on:

    See also: