Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capture ALL (stdout, stderr AND CON) output of cmd executing plink with C# (std out+err ok, CON not working)

I want to open SSH connections from c# via opening a process and running plink. All output should be collected and depending on the results the program will fire actions to the ssh. My big problem is, that i am using a couple if different scripts and i need (automated) user interaction. Therefore i have to capture ALL output data (standard output, standard error AND CONSOLE).

Looking at the following test batch should make the case more clear:

1: @ECHO OFF
2: ECHO StdOut
3: ECHO StdErr 1>&2
4: ECHO Cons>CON

The code is like:

Process process;
Process process;
process = new Process();
process.StartInfo.FileName = @"cmd.exe";
process.StartInfo.Arguments = "/c test.bat";
process.StartInfo.UseShellExecute = false;
process.StartInfo.ErrorDialog = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
process.ErrorDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
process.BeginOutputReadLine();
process.BeginErrorReadLine();
StreamWriter inputWriter = process.StandardInput;
[...]

I am able to capture lines 2+3, but not 4 (used by some programs). I have also tried powershell (or directly plink) instead of cmd.exe as starting point, but same result.

Is there any way in c# to capture the console out as well or do you know any third party command line being able to redirect CON out to stdout or something like this?

like image 899
Michael K. Avatar asked Jan 23 '12 07:01

Michael K.


2 Answers

I'm not sure that is even possible - well at least not using some plain simple API.

Please note that I have not found (although I tried) any information on the web that directly confirms that, but here is how I come to this conclusion.

The console in Windows is its own subsystem, managed by csrss.exe (and starting with Windows Vista also conhost.exe, but I digress). It has it's own set APIs (AttachConsole, WriteConsole, etc.) and you can only have one "console" per process.

CMD.EXE on the other hand is just another console mode application, that just happens to use the console and being launched it a console window. You can observe this effect, by launching a different console mode application and watch the process tree in e.g. Process Explorer: there is no CMD.EXE parent process (but rather it is Explorer or whatever you used to start it - including of course CMD.EXE).

Thus far I was trying to show the difference between "the console" and CMD.EXE, batch files, or console mode applications in general.

So when in CMD.EXE you use > CON you are actually causing the same effect as doing a write to CONOUT$ in native applications (or your typical write to /dev/console on a UNIX-like OS). There doesn't seem to be a direct equivalent for managed code, as Console.Out and Console.Error equal stdout and stderr in native applications (or 1 and 2 as file descriptors in CMD.EXE).

Having all that said, when you start a process you're only enabled to redirect it's standard output and standard error streams, but not (per se) the messages it writes to the console (or CONOUT$ handle). I guess that would be the same as trying to redirect output that a process writes to some file, which is also not (generically) possible.

You could possible achieve this using some hooking or injecting something inside the child process to grab the console output.

Being not able to easily do this, is also (one of) the reason(s) why writing a complete terminal (i.e. console window, not CMD.EXE!) replacement for Windows is not easily possible and requires some hacks or workarounds.

like image 95
Christian.K Avatar answered Nov 03 '22 01:11

Christian.K


AFAIK know what you want (redirecting CON) is only possible by hooking/injecting which is rather complex and basically not necessary to do SSH.

For SSH you can use any number of C# libraries out there (free and commercial):

  • http://www.chilkatsoft.com/ssh-sftp-component.asp (commercial)
  • http://www.tamirgal.com/blog/page/SharpSSH.aspx (free)
  • http://sshnet.codeplex.com/ (free)
  • http://www.rebex.net/ssh-pack/default.aspx (commercial)
  • http://www.eldos.com/sbb/desc-ssh.php (commercial)

The main advantage of using a library is that you have much greater control over the SSH session than you could ever achieve via some redirected console AND it is much easier to implement...

UPDATE - as per comments:

To get all output from the remotely running program you need to use a library which comes with an "interactive/terminal" class for SSH - for example the one at http://www.rebex.net/ssh-pack/default.aspx comes with such a class and works really fine (not affilliated, just a happy customer), it can be used as a code-only component or as a visual control (whatever suits your needs).

like image 41
Yahia Avatar answered Nov 03 '22 02:11

Yahia