Session.PutFiles Method doesn't upload multiple files or display multiple errors

Advertisement

Guest

Session.PutFiles Method doesn't upload multiple files or display multiple errors

I am new at PowerShell, and I am using the automated script to upload files to an FTP site.
In order to test for failures, I created five text files and removed the permissions from two of them so that the error message would be:
Can't open file 'H:\Documents\PositivePay\Test02.txt'.

Test Files:
Test01
Test02 (Permissions Removed; Properties > Security > Advanced > Change Permissions > Uncheck "Include..." > Remove > Apply)
Test03
Test04 (Permissions Removed; Properties > Security > Advanced > Change Permissions > Uncheck "Include..." > Remove > Apply)
Test05

When uploading all five files at once, I would expect to see:

Upload of H:\Documents\PositivePay\Test01.txt succeeded, moving to backup
Upload of H:\Documents\PositivePay\Test02.txt failed: Can't open file 'H:\Documents\PositivePay\Test02.txt'.
System Error. Code: 5.
Access is denied
Upload of H:\Documents\PositivePay\Test03.txt succeeded, moving to backup
Upload of H:\Documents\PositivePay\Test04.txt failed: Can't open file 'H:\Documents\PositivePay\Test02.txt'.
System Error. Code: 5.
Access is denied
Upload of H:\Documents\PositivePay\Test03.txt succeeded, moving to backup

However, instead the following happens:
Only the first file (Test01) is uploaded.
Only the first error (Test02) is displayed.

Nothing happens to Test03, Test04 or Test05.

From the Console:
Upload of H:\Documents\PositivePay\Test01.txt succeeded, moving to backup
Upload of H:\Documents\PositivePay\Test02.txt failed: Can't open file 'H:\Documents\PositivePay\Test02.txt'.
System Error. Code: 5.
Access is denied

Here is the script.

param (
$localPath = "H:\Documents\PositivePay\",
$remotePath = "/PosPayPut",
$backupPath = "H:\Documents\BMOSFTP\Backup"
)

try
{
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"

# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
Protocol = [WinSCP.Protocol]::Sftp
HostName = "INTENTIONALLY BLANK"
UserName = "INTENTIONALLY BLANK"
Password = "INTENTIONALLY BLANK"
SshHostKeyFingerprint = "ssh-rsa 1024 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
}

$session = New-Object WinSCP.Session

try
{
# Connect
$session.Open($sessionOptions)

# Upload files, collect results
$transferResult = $session.PutFiles($localPath, $remotePath)

# Iterate over every transfer
foreach ($transfer in $transferResult.Transfers)
{
# Success or error?
if ($transfer.Error -eq $Null)
{
Write-Host ("Upload of {0} succeeded, moving to backup" -f
$transfer.FileName)
# Upload succeeded, move source file to backup
Move-Item $transfer.FileName $backupPath
}
else
{
Write-Host ("Upload of {0} failed: {1}" -f
$transfer.FileName, $transfer.Error.Message)
}
}
}
finally
{
# Disconnect, clean up
$session.Dispose()
}

#exit 0
}
catch [Exception]
{
Write-Host ("Error: {0}" -f $_.Exception.Message)
#exit 1
}

Reply with quote

Advertisement

Guest

Thank you for the reply.

As I understand it, when an error is encountered, the script stops immediately (by design). Therefore, the script doesn't loop through each $transfer in $transferResult.Transfers. That's why the code below only lists the first failed file and not the others. Is that correct?

else
{
Write-Host ("Upload of {0} failed: {1}" -f
$transfer.FileName, $transfer.Error.Message)
}

(Also, as an aside comment, I registered online for a username, but when I try to post a comment, I get a red box that says:
"Sorry, but this username has already been taken." I am not sure why it won't let me post under my username: sjham)

Reply with quote

sjham
Joined:
Posts:
2
Location:
Chicago, IL

After reading about "Automating download in parallel connections over SFTP/FTP protocol", I was able to adapt my script and I got the error handling to work for each $FilePath in $FilePaths.

The remaining issue to be resolved is how to capture the $Transfer.Error.Message. When I run the script below in PS ISE, I get the results that I want, except that the error part is blank.

Here is was appears in the console:
2017-03-14 04:31:43 PM (UTC-05:00) Test01.txt was transferred to /PosPayPut/.
2017-03-14 04:31:43 PM (UTC-05:00) Test02.txt was not transferred to /PosPayPut/. Error: .
2017-03-14 04:31:43 PM (UTC-05:00) Test03.txt was transferred to /PosPayPut/.
2017-03-14 04:31:43 PM (UTC-05:00) Test04.txt was not transferred to /PosPayPut/. Error: .
2017-03-14 04:31:44 PM (UTC-05:00) Test05.txt was transferred to /PosPayPut/.
2017-03-14 04:31:44 PM (UTC-05:00) Test07.txt was transferred to /PosPayPut/.
2017-03-14 04:31:44 PM (UTC-05:00) Test09.txt was transferred to /PosPayPut/.

Here is my revised code:

$LocalPath = "H:\Documents\PositivePay"
$RemotePath = "/PosPayPut/"
$FilePaths = Get-ChildItem $LocalPath -Include *.* -Recurse -ErrorAction SilentlyContinue |
   Where-Object {!$_.psIsContainer -eq $True} | ForEach-Object -Process {$_.FullName}
$Success = @()
$Failure = @()

Try {
   Set-Location "C:\Program Files (x86)\WinSCP\"
   Add-Type -Path "WinSCPnet.dll"
   $SessionOptions = New-Object WinSCP.SessionOptions -Property @{
     Protocol = [WinSCP.Protocol]::Sftp
     HostName = "XXX"
     UserName = "XXX"
     Password = "XXX"
     SshHostKeyFingerprint = "ssh-rsa 1024 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
   }
   $Session = New-Object WinSCP.Session
   Try {
      $Session.Open($SessionOptions)
      ForEach ($FilePath In $FilePaths) {
         $Transfer = $Session.PutFiles($FilePath, $RemotePath)
         If ($Transfer.IsSuccess) {
            Write-Host ("$(Get-Date –f "yyyy-MM-dd hh:mm:ss tt (UTCzzzz)") {0} was transferred to {1}." -f
               (Split-Path $FilePath -Leaf -Resolve), $RemotePath)
            $Success += (Split-Path $FilePath -Leaf -Resolve)
         }
         Else {
            Write-Host ("$(Get-Date –f "yyyy-MM-dd hh:mm:ss tt (UTCzzzz)") {0} was not transferred to {1}. Error: {2}." -f
               (Split-Path $FilePath -Leaf -Resolve), $RemotePath, $Transfer.Error.Message -Replace '(?:\s|\r|\n)',' ') #THIS IS THE PART WHERE THE ERROR.MESSAGE IS BLANK
            $Failure += (Split-Path $FilePath -Leaf -Resolve)
         }
      }
   }
   Finally {
      $session.Dispose()
   }
}
Catch [Exception] {
   Write-Host ("Error: {0}" -f $_.Exception.Message)
   $Failure += (Split-Path $FilePaths -Leaf -Resolve)
}

Reply with quote

Advertisement

sjham
Joined:
Posts:
2
Location:
Chicago, IL

Worked perfectly; thank you!

2017-03-16 09:02:06 AM (UTC-05:00) Test01.txt was transferred to /PosPayPut/.
2017-03-16 09:02:06 AM (UTC-05:00) Test02.txt was not transferred to /PosPayPut/. Error: Can't open file 'H:\Documents\PositivePay\Test02.txt'. System Error. Code: 5. Access is denied.
2017-03-16 09:02:07 AM (UTC-05:00) Test03.txt was transferred to /PosPayPut/.
2017-03-16 09:02:07 AM (UTC-05:00) Test04.txt was not transferred to /PosPayPut/. Error: Can't open file 'H:\Documents\PositivePay\Test04.txt'. System Error. Code: 5. Access is denied.
2017-03-16 09:02:07 AM (UTC-05:00) Test05.txt was transferred to /PosPayPut/.
2017-03-16 09:02:08 AM (UTC-05:00) Test07.txt was transferred to /PosPayPut/.
2017-03-16 09:02:08 AM (UTC-05:00) Test09.txt was transferred to /PosPayPut/.

Reply with quote

Advertisement

You can post new topics in this forum