Kross
Kross

Reputation: 305

WinSCP not fully executing from C# using System.Diagnostics.Process?

I am trying to download some files from an FTP server and automate this task. I followed this tutorial for the most part to complete my process:
http://www.timmitchell.net/post/2015/08/03/downloading-sftp-files-with-ssis/

Now, I would like to use the command:

synchronize local \\somesharefolder /someremotedir

If I run this come command from my command line, it works without issues and synchronizes the 300~ files that are necessary.

My problem, when I run this from C#, it only synchronizes 30~ files and hangs in the WaitForExit() function call. If I display the process window and close it manually, my output shows nothing wrong. The connection succeeds, the files begin to download, and then it stops.

Here is the redacted code:

// Create a new Process object to execute WinSCP
Process winscp = new Process();

// Set the executable path and download directory
winscp.StartInfo.FileName = @"C:\Program Files (x86)\WinSCP\WinSCP.com";

// Set static execution options
winscp.StartInfo.UseShellExecute = false;
winscp.StartInfo.RedirectStandardInput = true;
winscp.StartInfo.RedirectStandardOutput = true;
winscp.StartInfo.CreateNoWindow = true;

// Set session options
string sessionOptionString = "option batch abort" +
    System.Environment.NewLine + "option confirm off";

// Build the connection string (<user>:<password>@<hostname>)
string connectString = @"open ftp://" +
    "username" + ":" +
    "password" + "@" +
    "hostURL" + " -implicit";

// Supplying the host key adds an extra level of security, and avoids getting the prompt to trust the server
string hostKeyString = null;

// If hostkey was specified, include it
if (hostKeyString != null && hostKeyString.Length > 0)
{
    connectString += " -hostkey=\"" + hostKeyString + "\"";
}
else
{
    connectString += " -hostkey";
}

// Build the get command strings, stored in list to maintain order.
List<string> cmdStrings = new List<string>();

cmdStrings.Add(@"synchronize local \\some\file\share /some/remote/directory");
// Create output variables to capture execution info
string outStr = "", errStr = "";
int returnVal = 1;

// This try/catch block will capture catastrophic failures (such as specifying the wrong path to winscp)
try
{
    winscp.Start();

    winscp.StandardInput.WriteLine(sessionOptionString);
    winscp.StandardInput.WriteLine(connectString);
    foreach (var cmd in cmdStrings)
    {
        winscp.StandardInput.WriteLine(cmd);
    }
    winscp.StandardInput.Close();

    winscp.WaitForExit();

    // Set the outStr to the output value, obfuscating the password

    outStr = winscp.StandardOutput.ReadToEnd().Replace(":" +
        "password" +
        "@", ":*******@");
    returnVal = winscp.ExitCode;
}
catch (Exception ex)
{
    errStr = "An error occurred when attempting to execute winscp.com: " +
        ex.Message.Replace("'", "\"").Replace("--", " - ");
}

outStr.Dump();

Sample redacted output:

winscp> option batch abort
batch           abort     
reconnecttime   120       
winscp> option confirm off
confirm         off       
winscp> open ftp://something:*******@127.0.0.1 -implicit -hostkey
Connecting to 127.0.0.1:990 ...
TLS connection established. Waiting for welcome message...
Connected
Starting the session...
Session started.
Active session: [1] [email protected]
winscp> synchronize local \\some\file\share /some/remote/directory
Comparing...
Local '\\some\file\share' <= Remote '/some/remote/directory'
Synchronizing...
Local '\\some\file\share' <= Remote '/some/remote/directory'
something150401.csv    |            0 B |    0.0 KB/s | binary |   0%
something150402.csv    |            0 B |    0.0 KB/s | binary |   0%
something150403.csv    |           81 B |    0.1 KB/s | binary | 100%
something150404.csv    |          121 B |    0.2 KB/s | binary | 100%
something150405.csv    |          242 B |    0.3 KB/s | binary | 100%
something150406.csv    |          164 B |    0.1 KB/s | binary | 100%
something150407.csv    |           39 B |    0.1 KB/s | binary | 100%
something150408.csv    |          203 B |    0.1 KB/s | binary | 100%
something150409.csv    |          197 B |    0.2 KB/s | binary | 100%
something150410.csv    |            0 B |    0.2 KB/s | binary |   0%
something150411.csv    |          124 B |    0.2 KB/s | binary | 100%
something150412.csv    |          202 B |    0.2 KB/s | binary | 100%
something150413.csv    |          123 B |    0.2 KB/s | binary | 100%
something150414.csv    |          199 B |    0.2 KB/s | binary | 100%
something150415.csv    |          283 B |    0.2 KB/s | binary | 100%
something150416.csv    |          203 B |    0.2 KB/s | binary | 100%
something150417.csv    |           82 B |    0.2 KB/s | binary | 100%
something150418.csv    |          199 B |    0.3 KB/s | binary | 100%
something150419.csv    |          285 B |    0.3 KB/s | binary | 100%
something150420.csv    |           82 B |    0.3 KB/s | binary | 100%
something150421.csv    |          156 B |    0.3 KB/s | binary | 100%
something150422.csv    |          162 B |    0.3 KB/s | binary | 100%
something150423.csv    |          163 B |    0.3 KB/s | binary | 100%
something150424.csv    |          204 B |    0.3 KB/s | binary | 100%
something150425.csv    |          240 B |    0.3 KB/s | binary | 100%
something150426.csv    |           82 B |    0.3 KB/s | binary | 100%
something150427.csv    |          164 B |    0.3 KB/s | binary | 100%
something150428.csv    |          122 B |    0.3 KB/s | binary | 100%
something150429.csv    |           82 B |    0.3 KB/s | binary | 100%
something150430.csv    |            0 B |    0.3 KB/s | binary |   0%
something150501.csv    |          123 B |    0.3 KB/s | binary | 100%
something150502.csv    |          122 B |    0.3 KB/s | binary | 100%
something150503.csv    |          245 B |    0.3 KB/s | binary | 100%
something150504.csv    |          203 B |    0.4 KB/s | binary | 100%
something150505.csv    |          205 B |    0.5 KB/s | binary | 100%
something150506.csv    |          121 B |    0.5 KB/s | binary | 100%
something150507.csv    |          164 B |    0.5 KB/s | binary | 100%
something150508.csv    |           82 B |    0.5 KB/s | binary | 100%
something150509.csv    |          164 B |    0.5 KB/s | binary | 100%
something150510.csv    |          205 B |    0.5 KB/s | binary | 100%
something150511.csv    |          164 B |    0.5 KB/s | binary | 100%
something150512.csv    |           41 B |    0.5 KB/s | binary | 100%
something150513.csv    |            0 B |    0.5 KB/s | binary |   0%
something150514.csv    |           82 B |    0.5 KB/s | binary | 100%
something150515.csv    |           82 B |    0.5 KB/s | binary | 100%
something150516.csv    |          244 B |    0.5 KB/s | binary | 100%

The output stops there, it is not cut off.

Upvotes: 2

Views: 1069

Answers (1)

spender
spender

Reputation: 120450

You are waiting for the process to finish before reading StandardOutput. This is problematic because the redirected StandardOutput has a fixed-size buffer.

When the buffer is full, writes to it will block, so the child-process being managed by Process is blocking when writing to its stdout.

If you ReadToEnd before WaitForExit, the problem should no longer occur.

Upvotes: 2

Related Questions