捕获使用 C# 执行 plink 的 cmd 的所有(stdout、stderr AND CON)输出(std out+err ok,CON 不起作用)
我想通过打开进程并运行 plink 从 C# 打开 SSH 连接。应收集所有输出,并根据结果,程序将向 ssh 发起操作。 我的大问题是,我正在使用几个不同的脚本,并且我需要(自动)用户交互。因此我必须捕获所有输出数据(标准输出、标准错误和控制台)。
查看下面的测试批次应该会让情况更清楚:
1: @ECHO OFF
2: ECHO StdOut
3: ECHO StdErr 1>&2
4: ECHO Cons>CON
代码如下:
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;
[...]
我能够捕获第 2+3 行,但不能捕获第 4 行(某些程序使用)。 我也尝试过 powershell (或直接 plink)而不是 cmd.exe 作为起点,但结果相同。
c# 中是否有任何方法可以捕获控制台,或者您是否知道任何第三方命令行能够将 CON 重定向到 stdout 或类似的东西?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不确定这是否可能——至少不使用一些简单的 API。
请注意,我尚未在网络上找到(尽管我尝试过)任何直接证实这一点的信息,但以下是我得出此结论的方法。
Windows 中的控制台是它自己的子系统,由
csrss.exe
管理(从 Windows Vista 开始也有conhost.exe
,但我离题了)。它有自己的一组 API(AttachConsole
、WriteConsole
等),并且每个进程只能有一个“控制台”。另一方面,CMD.EXE 只是另一个控制台模式应用程序,它恰好使用控制台并在控制台窗口中启动它。您可以通过启动不同的控制台模式应用程序并在 Process Explorer 中观察进程树来观察这种效果:没有 CMD.EXE 父进程(而是 Explorer 或您用来启动它的任何内容 - 当然包括 CMD。 EXE文件)。
到目前为止,我试图展示“控制台”和 CMD.EXE、批处理文件或一般控制台模式应用程序之间的区别。
因此,当在
CMD.EXE
中时,您可以使用>; CON
您实际上造成了与在本机应用程序中写入CONOUT$
相同的效果(或者在 UNIX 上典型地写入/dev/console
)像操作系统)。托管代码似乎没有直接等效的东西,因为Console.Out
和Console.Error
等于stdout
和stderr
在本机应用程序中(或1
和2
作为CMD.EXE
中的文件描述符)。话虽如此,当您启动一个进程时,您只能重定向它的标准输出和标准错误流,但不能(本身)重定向它写入控制台(或
CONOUT$
句柄)的消息。 )。我想这与尝试将进程写入某个文件的输出重定向相同,这(通常)也是不可能的。您可以使用一些挂钩或在子进程中注入一些东西来获取控制台输出来实现这一点。
无法轻松做到这一点,也是编写一个完整的终端(即控制台窗口,而不是
CMD.EXE
!) 替代 Windows 不容易的原因之一需要一些技巧或解决方法。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 alsoconhost.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 toCONOUT$
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, asConsole.Out
andConsole.Error
equalstdout
andstderr
in native applications (or1
and2
as file descriptors inCMD.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.AFAIK 知道你想要什么(重定向 CON)只能通过挂钩/注入来实现,这是相当复杂的,并且基本上不需要执行 SSH。
对于 SSH,您可以使用任意数量的 C# 库(免费和商业):
使用库的主要优点是您可以更好地控制 SSH会议比你能曾经通过一些重定向控制台实现,并且更容易实现...
更新 - 根据评论:
要从远程运行的程序获取所有输出,您需要使用一个带有“交互式”的库/terminal” SSH 类 - 例如 http://www.rebex.net 上的类/ssh-pack/default.aspx带有这样一个类并且工作得很好(没有附属关系,只是一个满意的客户),它可以用作仅代码组件或可视控件(无论适合您的需求)。
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):
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).
以下是一些执行此操作的 CodeProject 项目(通过本机代码),AFAICT 可以更好地处理重定向所有控制台输出:
通用控制台重定向器
重定向任意控制台的输入/输出
另外,命令 freopen 允许程序重定向其流。但是,如果程序执行显式 WriteConsole(),我不确定是否可以重定向它。
Here are some CodeProject projects which do this (via native code), which AFAICT better handle redirecting all console output:
Universal Console Redirector
Redirecting an arbitrary Console's Input/Output
Also, the command freopen allows a program to redirect its streams. However, if a program does an explicit WriteConsole() I'm not sure if it is possible to redirect that.