Search code examples
powershellwinscp

WinSCP XML log with PowerShell to confirm multiple file upload


With my script, I am attempting to scan a directory for a subdirectory that is automatically created each day that contains the date in the directory name. Once it finds yesterdays date (since I need to upload previous day), it looks for another subdirectory, then any files that contain "JONES". Once it finds those files, it does a foreach loop to upload them using winscp.com.

My issue is that I'm trying to use the .xml log created from winscp to send to a user to confirm uploads. The problem is that the .xml file contains only the last file uploaded.

Here's my script:

# Set yesterday's date (since uploads will happen at 2am)
$YDate = (Get-Date).AddDays(-1).ToString('MM-dd-yyyy')

# Find Directory w/ Yesterday's Date in name
$YesterdayFolder = Get-ChildItem -Path "\\Path\to\server" | Where-Object {$_.FullName.contains($YDate)}

If ($YesterdayFolder) {

    #we specify the directory where all files that we want to upload are contained 
    $Dir= $YesterdayFolder

    #list every sql server trace file
    $FilesToUpload = Get-ChildItem -Path (Join-Path $YesterdayFolder.FullName "Report") | Where-Object {$_.Name.StartsWith("JONES","CurrentCultureIgnoreCase")}

    foreach($item in ($FilesToUpload))
    { 
          $PutCommand = '& "C:\Program Files (x86)\WinSCP\winscp.com" /command "open ftp://USERNAME:[email protected]:21/dropoff/ -explicitssl" "put """"' + $Item.FullName + '""""" "exit"' 
          Invoke-Expression $PutCommand         
    } 
} Else {
    #Something Else will go here
}

I feel that it's my $PutCommand line all being contained within the ForEach loop, and it just overwrites the xml file each time it connects/exits, but I haven't had any luck breaking that script up.


Solution

  • You are running WinSCP again and again for each file. Each run overwrites a log of the previous run.

    Call WinSCP once instead only. It's even better as you avoid re-connecting for each file.

    $FilesToUpload = Get-ChildItem -Path (Join-Path $YesterdayFolder.FullName "Report") |
        Where-Object {$_.Name.StartsWith("JONES","CurrentCultureIgnoreCase")}
    
    $PutCommand = '& "C:\Program Files (x86)\WinSCP\winscp.com" /command "open ftp://USERNAME:[email protected]:21/dropoff/ -explicitssl" '
    
    foreach($item in ($FilesToUpload))
    { 
          $PutCommand += '"put """"' + $Item.FullName + '""""" '
    } 
    $PutCommand += '"exit"'
    
    Invoke-Expression $PutCommand 
    

    Though all you really need to do is checking WinSCP exit code. If it is 0, all went fine. No need to have the XML log as a proof.


    And even better, use the WinSCP .NET assembly from PowerShell script, instead of driving WinSCP from command-line. It does all error checking for you (you get an exception if anything goes wrong). And you avoid all nasty stuff of command-line (like escaping special symbols in credentials and filenames).

    try
    {
        # Load WinSCP .NET assembly
        Add-Type -Path "WinSCPnet.dll"
    
        # Setup session options
        $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
            Protocol = [WinSCP.Protocol]::Ftp
            FtpSecure = [WinSCP.FtpSecure]::Explicit
            TlsHostCertificateFingerprint = "xx:xx:xx:xx:xx:xx..."
            HostName = "ftps.hostname.com"
            UserName = "username"
            Password = "password"
        }
    
        $session = New-Object WinSCP.Session
    
        try
        {
            # Connect
            $session.Open($sessionOptions)
    
            # Upload files
            foreach ($item in ($FilesToUpload))
            {
                $session.PutFiles($Item.FullName, "/dropoff/").Check()
                Write-Host "Upload of $($Item.FullName) succeeded"
            }
        }
        finally
        {
            # Disconnect, clean up
            $session.Dispose()
        }
    
        exit 0
    }
    catch [Exception]
    {
        Write-Host "Error: $($_.Exception.Message)"
        exit 1
    }