Error: Exception calling "Open" with "1" argument(s): "Connection failed."
We use a PowerShell function to upload data to a govt program that mandates FTPS. We were recently contacted to say they hadn't received our last few uploads. Digging down I found the error was being thrown by the
Has the call to
Passwords are stored in textfiles as
Testing Code
Function
function
We also use this logging function
Upload-WinSCP-FTPS
function. I mocked up the call for testing and got the same error.
Has the call to
Open
changed?
Passwords are stored in textfiles as
SecureString
s. I've checked, and this one looks correct. Has a @
somewhere in the middle, the rest is just mixed upper/lower text.
Testing Code
. C:\scripts\Function-Upload-WinSCP-FTPS . c:\scripts\Function-Write-Log.ps1 $logFile = "C:\Scripts\log\test.log" $hostname = "ftps.tca.gov.au" $port = [int]990 $user = "FGX_PUT7" $passwordFile = "C:\scripts\credential.TCA.txt" $password = Get-Content $passwordFile | ConvertTo-SecureString $file = "C:\Scripts\testfile.txt" $remotepath = "/" $transferTimer = [System.Diagnostics.Stopwatch]::StartNew() # upload file $result = Upload-WinSCP-FTPS ` -HostName $hostname ` -Port $port ` -User $user ` -SecurePassword $password ` -TransferFile $file ` -RemotePath $remotepath ` -ParentLogFile $logFile $resultVal = $result[-1] # last element if($resultVal -eq 0) { Write-Log "Upload returned 0 (Success) for $($f.Name)" -Path $logFile -Level Info Write-Log "Moving $($f.Name) to $($scriptCfg.DestPath)" -Path $logFile -Level Info Move-Item -Path $f.FullName -Destination $($scriptCfg.DestPath) -Force } else { Write-Log "Error: Return code $resultVal when attempting to transfer file via FTPS" -Path $logFile -Level Error } $transferTimer.Stop() Write-Log "Transfer Complete." -Path $logFile -Level Info Write-Log -Message ("Duration {0:hh} hours, {0:mm} minutes and {0:ss} seconds" -f $transferTimer.Elapsed) -Path $logFile -Level Debug
Function
Upload-WinSCP-FTPS()
<# .Synopsis Upload a a file using the FTPS protocol. .DESCRIPTION Loads the WinSCP library and uses it to created an FGTPS Connection using the parameters provided .NOTES Looks for WINSCP at "C:\Program Files (x86)\WinSCP\WinSCPnet.dll" .PARAMETER Hostname The Host the FTP server is running on. Can be DNS or IP .PARAMETER Port An Integer representing a TCP Port. Should be the port the FTP Server is running on. .PARAMETER User .. .PARAMETER SecurePassword .. .PARAMETER TransferFile .. .PARAMETER RemotePath .. .PARAMETER ParentLogFile .. .EXAMPLE .. .LINK .. #> Function Upload-WinSCP-FTPS() { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$HostName = $(throw "-HostName is required"), [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [int]$Port = $(throw "-Port is required. Commonly 21 or 990."), [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$User = $(throw "-User is required"), [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [SecureString]$SecurePassword = $(throw "-SecurePassword is of type SecureString. It is required"), [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$TransferFile = $(throw "-TransferFile is a path to and including a filename. It is required"), [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$RemotePath = $(throw "-RemotePath is a path on the server to upload to. It is required"), [Parameter(Mandatory=$false)] [string]$ParentLogFile ) [int]$returnVal = 0 [int]$returnSuccess = 0 [int]$returnErrorExceptionThrown = 1 [int]$returnErrorFileMissing = 2 if (! (test-path function:Write-Log)) { . c:\scripts\Function-Write-Log.ps1 } ## Logging Setup ######################################################## [string]$logPrefix = "" if([string]::IsNullOrEmpty($ParentLogFile)) { $logPrefix = "" $logDir = "C:\Scripts\log\" Generate-Folder $logDir $logName = "tca_dir_upload_$(Get-Date -Format "yyyyMMdd").log" $logFile = Join-Path -Path $logDir -ChildPath $logName Write-Log "Logfile not passed in" -Path $logFile -Prefix $logPrefix -Level Info } else { $logPrefix = "FTPS: " $logFile = $ParentLogFile Write-Log "Logfile passed in" -Path $logFile -Prefix $logPrefix -Level Info } Write-Log "Logfile is: $logFile" -Path $logFile -Prefix $logPrefix -Level Info ## Params ############################################################### Write-Log "Params" -Path $logFile -Prefix $logPrefix -Level Verbose Write-Log "HostName: $HostName" -Path $logFile -Prefix $logPrefix -Level Verbose Write-Log "Port: $Port" -Path $logFile -Prefix $logPrefix -Level Verbose Write-Log "User: $User" -Path $logFile -Prefix $logPrefix -Level Verbose Write-Log "SecurePassword: ----" -Path $logFile -Prefix $logPrefix -Level Verbose Write-Log "TransferFile: $TransferFile" -Path $logFile -Prefix $logPrefix -Level Verbose Write-Log "RemotePath: $RemotePath" -Path $logFile -Prefix $logPrefix -Level Verbose Write-Log "ParentLogFile: $ParentLogFile" -Path $logFile -Prefix $logPrefix -Level Verbose ## Check Transfer file ################################################## if(-Not (Test-Path $TransferFile -PathType leaf)) { Write-Log "$TransferFile does not exist" -Path $logFile -Prefix $logPrefix -Level Error $returnVal = $returnErrorFileMissing $returnVal Return } try { # Load WinSCP .NET assembly Write-Log "Load WinSCP .NET assembly" -Path $logFile -Prefix $logPrefix -Level Debug Add-Type -Path "C:\Program Files (x86)\WinSCP\WinSCPnet.dll" # Setup session options Write-Log "Set WinSCP session options" -Path $logFile -Prefix $logPrefix -Level Debug $sessionOptions = New-Object WinSCP.SessionOptions -Property @{ Protocol = [WinSCP.Protocol]::Ftp FtpSecure = [WinSCP.FtpSecure]::Implicit HostName = $HostName PortNumber = $Port UserName = $User SecurePassword = $SecurePassword } Write-Log "Create new Session" -Path $logFile -Prefix $logPrefix -Level Debug $session = New-Object WinSCP.Session try { # Connect Write-Log "Open Session" -Path $logFile -Prefix $logPrefix -Level Debug $session.Open($sessionOptions) # Upload files $transferOptions = New-Object WinSCP.TransferOptions $transferOptions.TransferMode = [WinSCP.TransferMode]::Binary Write-Log "Upload file: $TransferFile" -Path $logFile -Prefix $logPrefix -Level Debug $transferResult = $session.PutFiles($TransferFile, $RemotePath, $False, $transferOptions) # Throw on any error Write-Log "Check Result" -Path $logFile -Prefix $logPrefix -Level Debug $transferResult.Check() # Print results foreach ($transfer in $transferResult.Transfers) { Write-Log "Upload success: $($transfer.FileName)" -Path $logFile -Prefix $logPrefix } } finally { # Disconnect, clean up $session.Dispose() } $returnVal = $returnSuccess $returnVal Return } catch { Write-Log "Error: $($_.Exception.Message)" -Path $logFile -Prefix $logPrefix -Level Error $returnVal = $returnErrorExceptionThrown $returnVal Return } }
function
Write-Log
We also use this logging function
<# .Synopsis Write-Log writes a message to a specified log file with the current time stamp. .DESCRIPTION The Write-Log function is designed to add logging capability to other scripts. In addition to writing output and/or verbose you can write to a log file for later debugging. .NOTES Created by: Jason Wasser @wasserja Modified: 11/24/2015 09:30:19 AM Changelog: * Code simplification and clarification - thanks to @juneb_get_help * Added documentation. * Renamed LogPath parameter to Path to keep it standard - thanks to @JeffHicks * Revised the Force switch to work as it should - thanks to @JeffHicks To Do: * Add error handling if trying to create a log file in a inaccessible location. * Add ability to write $Message to $Verbose or $Error pipelines to eliminate duplicates. .PARAMETER Message Message is the content that you wish to add to the log file. .PARAMETER Path The path to the log file to which you would like to write. By default the function will create the path and file if it does not exist. .PARAMETER Level Specify the criticality of the log information being written to the log (i.e. Error, Warning, Informational) .PARAMETER NoClobber Use NoClobber if you do not wish to overwrite an existing file. .EXAMPLE Write-Log -Message 'Log message' Writes the message to c:\Logs\PowerShellLog.log. .EXAMPLE Write-Log -Message 'Restarting Server.' -Path c:\Logs\Scriptoutput.log Writes the content to the specified log file and creates the path and file specified. .EXAMPLE Write-Log -Message 'Folder does not exist.' -Path c:\Logs\Script.log -Level Error Writes the message to the specified log file as an error message, and writes the message to the error pipeline. #> function Write-Log { [CmdletBinding()] Param ( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Alias("LogContent")] [string]$Message, [Parameter(Mandatory=$false)] [Alias('LogPath')] [string]$Path='C:\Logs\PowerShellLog.log', [Parameter(Mandatory=$false)] [ValidateSet("Error","Warn","Info")] [string]$Level="Info", [Parameter(Mandatory=$false)] [switch]$NoClobber ) Begin { # Set VerbosePreference to Continue so that verbose messages are displayed. $VerbosePreference = 'Continue' } Process { # If the file already exists and NoClobber was specified, do not write to the log. if ((Test-Path $Path) -AND $NoClobber) { Write-Error "Log file $Path already exists, and you specified NoClobber. Either delete the file or specify a different name." Return } # If attempting to write to a log file in a folder/path that doesn't exist create the file including the path. elseif (!(Test-Path $Path)) { Write-Verbose "Creating $Path." $NewLogFile = New-Item $Path -Force -ItemType File } else { # Nothing to see here yet. } # Format Date for our Log File $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" # Write message to error, warning, or verbose pipeline and specify $LevelText switch ($Level) { 'Error' { Write-Error $Message $LevelText = 'ERROR:' } 'Warn' { Write-Warning $Message $LevelText = 'WARNING:' } 'Info' { Write-Verbose $Message $LevelText = 'INFO:' } } # Write log entry to $Path "$FormattedDate $LevelText $Message" | Out-File -FilePath $Path -Append } End { } }