Post a reply

Before posting, please read how to report bug or request support effectively.

Bug reports without an attached log file are usually useless.

Options
Add an Attachment

If you do not want to add an Attachment to your Post, please leave the Fields blank.

(maximum 10 MB; please compress large files; only common media, archive, text and programming file formats are allowed)

Options

Topic review

martin

Re: Type 11 Disconnect when trying to use GetFileToDirectory

No. But you can call some trivial operation (like Session.FileExists), while processing your files, to keep your session alive.
icoryx

Re: Type 11 Disconnect when trying to use GetFileToDirectory

I guess the issue might be that the time between listing the files, comparing them and downloading them is too long? Is there any way to increase this? Some sort of keepalive option?
icoryx

Re: Type 11 Disconnect when trying to use GetFileToDirectory

Thanks for the reply!

The log might not be matching because I stripped the script down by a lot. The full script has a lot of stuff that should be irrelevant to the issue but here it is:
#Make PSScriptRoot available in psISE
$PSScriptRootFix = $MyInvocation.MyCommand.Path | Split-Path -Parent
 
#Load WinSCP .NET assembly
$winSCPPath = if ($env:WINSCP_PATH) { $env:WINSCP_PATH } else { "$PSScriptRootFix\WinSCPNETAssembly" }
$tempSCPPath = "C:\temp\WinSCPNETAssembly"
$tempAssemblyPath = (Join-Path $tempSCPPath "WinSCPnet.dll")
Copy-Item -Path $winSCPPath -Destination $tempSCPPath -Recurse -Force
Add-Type -Path $tempAssemblyPath
 
[string]$script:sftpServer = "***.***.***.***"
[string]$script:username = "******"
[string]$script:password = "******"
[string]$script:fingerprint = "******"
[int]$script:port = 65535
 
$scplogpath = "$PSScriptRootFix\logs\script.log"
 
#region Functions
 
function Write-ConsoleLog {
    param (
        [string]$message,
        [System.ConsoleColor]$foregroundColor = "White",
        [switch]$noNewLine
    )
 
    $params = @{}
 
    if ($noTime -eq 1) {
        $params["Object"] = "$message"
        $params["ForegroundColor"] = $foregroundColor
        $script:noTime = 0
    } else {
        $params["Object"] = "$(Get-Date -Format 'yyyy-MM-ddThh:mm:ss') $message"
        $params["ForegroundColor"] = $foregroundColor
    }
 
    if ($noNewLine) {
        $params["NoNewLine"] = $true
        $script:noTime = 1
    }
 
    Write-Host @params
}
 
 
function New-WinSCPSession {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]$sftpServer,
 
        [Parameter(Mandatory)]
        [string]$username,
 
        [string]$password = "",
 
        [string]$fingerprint,
 
        [int]$port,
 
        [string]$logpath = ""
    )
    begin {
        #PSCredential
        $securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force
 
        #SFTP SessionParameters
        if ($port) {
            $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
                Protocol = [WinSCP.Protocol]::Sftp
                HostName = $sftpServer
                UserName = $username
                SecurePassword = $securePassword
                SshHostKeyFingerprint = $fingerprint
                PortNumber = $port
            }
        }
        else {
            $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
                Protocol = [WinSCP.Protocol]::Sftp
                Hostname = $sftpServer
                Username = $username
                SecurePassword = $securePassword
                SshHostKeyFingerprint = $fingerprint
            }
        }
    }
 
    process {
        $session = New-Object WinSCP.Session
        $session.SessionLogPath = $logpath
        $session.Open($sessionOptions)
    }
 
    end {
        return $session
    }
}
 
 
function Get-SFTPFiles {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [WinSCP.Session]$SCPsession,
 
        [Parameter(Mandatory)]
        [string]$remotePath
    )
   
    begin {
        #Hashtable for the remote files
        $remoteFilesHashTable = @{}
    }
   
    process {
        Write-ConsoleLog "Getting SFTP Child-Item $remotePath" Cyan
        $remoteFiles = $script:SCPsession.EnumerateRemoteFiles($remotePath, $null, [WinSCP.EnumerationOptions]::AllDirectories)
        Write-ConsoleLog "Populating Hashtable... " Cyan -NoNewline
        $filecounter = 1
        foreach ($file in $remoteFiles) {
            $remoteFilesHashTable["file_$filecounter"] = [PSCustomObject]@{
                Name = $file.Name
                Path = $file.FullName
                Size = $file.Length
                LastWriteTime = $file.LastWriteTime
                Quartal = ""
            }
            $filecounter += 1
        }
        Write-ConsoleLog "Done" Green
    }
   
    end {
        return $remoteFilesHashTable
    }
}
 
 
 
function Get-LocalFiles {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        $localPath
    )
   
    begin {
        #Hashtable for local Files
        $localFilesHashTable = @{}
    }
   
    process {
        Write-ConsoleLog "Getting Local Child-Item $localpath ... " Cyan -NoNewline
        $localPath = $localPath.trimstart("\\")
        $localFiles = Get-ChildItem -Path "\\?\UNC\$localPath" -Recurse | Where-Object { -not $_.PSIsContainer }
        $filecounter = 1
        foreach ($file in $localFiles) {
            $localFilesHashTable["file_$filecounter"] = [PSCustomObject]@{
                Name = $file.Name
                Path = $file.FullName
                Size = $file.Length
                LastWriteTime = $file.LastWriteTime
                Quartal = ""
            }
            $filecounter += 1
        }
        Write-ConsoleLog "Done" Green
    }
   
    end {
        return $localFilesHashTable
    }
}
 
#endregion
 
 
#region Main
 
#SFTP Session
$SCPsession = New-WinSCPSession -sftpServer $sftpServer -username $username -password $password -fingerprint $fingerprint -port $port -logpath $scplogpath
 
#Collect Files
$eFiles = Get-SFTPFiles -SCPsession $SCPsession -remotePath "/Downloads/"
$anKFiles = Get-SFTPFiles -SCPsession $SCPsession -remotePath "/anK/"
 
#Quartale setzen
$eQuartale = @()
foreach ($file in $eFiles.Keys) {
    if ($eFiles[$file].Path -match "/Downloads/[\d]{4}-[1-4]/.*") {
        $remoteQ = ($eFiles[$file].Path -split "/")[4]
        $localQ = $remoteQ -replace "-", ""
 
        $eFiles[$file].Quartal = $localQ
 
        if ($eQuartale -notcontains $localQ) {
            $eQuartale += $localQ
        }
    }
}
 
$eMissingFiles = @{}
 
#local files
$noQFolders = Get-LocalFiles -localPath "\\fileserver\noQ\"        #Hashtable für Quartalsunabhängige Dateien
#$gQuartale = Get-ChildItem -Path "\\fileserver\dep\" | where { $_.Name -match "[\d]{4}[1-4]" } | Sort-Object Name  #lokale Quartale
$gQuartale = Get-ChildItem -Path "\\fileserver\dep\" | where { $_.Name -match "2024[1-4]" } | Sort-Object Name     #lokale Quartale nur 2024 (zum Test)
$gQuartalHashtables = @{}
 
#Get local Q Files
foreach ($q in $eQuartale) {
    if (Test-Path "\\fileserver\dep\$q\G") {
        $gQuartalHashtables = Get-LocalFiles -localPath "\\fileserver\dep\$q\G"
    }
}
 
#Get missing/altered files
foreach ($file in $eFiles.Keys) {
    Write-Host "$($eFiles[$file].Name)... "-NoNewline
    if (($eFiles[$file].Quartal).length -gt 0) {
        $localQ = $eFiles[$file].Quartal
        if ($gQuartalHashtables.ContainsKey($localQ)) {
            if ($gQuartalHashtables[$localQ].ContainsKey($file)) {
                if ($gQuartalHashtables[$localQ][$file].Size -ne $eFiles[$file].Size -or $gQuartalHashtables[$localQ][$file].LastWriteTime -ne $eFiles[$file].LastWriteTime ) {
                    $eMissingFiles[$file] = $eFiles[$file]
                    Write-Host "found but different attributes"
                }
                else {
                    Write-Host "found"
                }
            }
            else {
                $eMissingFiles[$file] = $eFiles[$file]
                Write-Host "missing"
            }
        }
        else {
            Write-Host "kein Quartal"
        }
    }
    else {
        $eFiles[$file].Quartal = "Quartalsunabhaengig"
 
        if ($noQGFolders.ContainsKey($file)) {
            if ($noQGFolders[$file].Size -ne $eFiles[$file].Size -or $noQGFolders[$file].LastWriteTime -ne $eFiles[$file].LastWriteTime ) {
                $eMissingFiles[$file] = $eFiles[$file]
                Write-Host "found but different attributes"
            }
            else {
                Write-Host "found"
            }
        }
        else {
            $eMissingFiles[$file] = $eFiles[$file]
            Write-Host "missing"
        }
    }
}
 
#Download missing/altered files
foreach ($file in $eMissingFiles.Keys) {
    $remotepath = $eMissingFiles[$file].Path
    if ($eMissingFiles[$file].Quartal -match "Quartalsunabhaengig") {
        $remotePathRel = $remotepath -replace "/Downloads/noQ",""
        $localpath = Join-Path "\\fileserver\noQ\" $remotePathRel | Split-Path -Parent
    }
    else {
        $remoteQ = "$(($eMissingFiles[$file].Quartal).Substring(0,4))-$(($eMissingFiles[$file].Quartal).Substring(4,1))"
        $remotePathRel = $remotepath -replace "/Downloads/$remoteQ",""
        $localpath = Join-Path "\\fileserver\dep\$($eMissingFiles[$file].Quartal)\G" $remotePathRel | Split-Path -Parent
    }
    Write-ConsoleLog "Downloading $file to $localpath" Cyan
    $SCPsession.GetFileToDirectory($remotepath,$localpath,$false,$null)
}
$SCPsession.Close()
 
Remove-Item -Path $tempAssemblyPath
 
Read-Host "Press Enter to Continue"


Now the log should match with the script. I have only renamed some paths so they might still be off.
martin

Re: Type 11 Disconnect when trying to use GetFileToDirectory

The log does not match your code. The log shows that Session.ListDirectory or similar was called after the session was opened. Then there was a 5 minutes pause before the download. During the pause the server somehow timeouted (although the connection was kept alive).
icoryx

Type 11 Disconnect when trying to use GetFileToDirectory

Hi,

I'm trying to download a file from an SFTP Server to a local fileserver using the GetFileToDirectory method. I am using the DLL Version 6.3.5.0 in PowerShell to do that.

Here's the basic script that I am using:
$winSCPPath = "D:\Path\To\DLL"
Add-Type -Path $winSCPPath
 
[string]$script:sftpServer = "xxxxx"
[string]$script:username = "xxxxx"
[string]$script:password = "xxxxx"
[string]$script:fingerprint = "xxxxx"
[int]$script:port = xxxxx
$securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force
 
$scplogpath = "$PSScriptRootFix\logs\script.log"
 
$remotePath = "/Path/To/Remote/File.msi"
$localPath = "\\fileserver\Place\File\Here\"
 
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
        Protocol = [WinSCP.Protocol]::Sftp
        HostName = $sftpServer
        UserName = $username
        SecurePassword = $securePassword
        SshHostKeyFingerprint = $fingerprint
        PortNumber = $port
    }
 
$session = New-Object WinSCP.Session
$session.SessionLogPath = $logpath
$session.Open($sessionOptions)
 
$session.GetFileToDirectory($remotePath, $localPath, $false, $null)

When I try to run just this it sometimes works and sometimes it doesn't. In the full script it never works. This is the error that I receive:
Remote side sent disconnect message
type 11 (by application):
"FlowSshPacketDecoder: unresponsiveness timeout"
Can't get attributes of file '/Path/To/Remote/File.msi'.

Is it just an issue with timeout? Or maybe the full version of my script somehow crashes the session? All it does is create 2 hashtables with remote/local files, compares them and then tries to download the missing files using the method above...