如何在C#中捕获Shell命令输出?

摘要:

  • 查询远程机器上的注册表
  • 捕获要在应用程序中使用的输出
  • 需要在csharp
  • 到目前为止,所有使用的方法只能在本地机器上查询
  • 任何希望都非常感激

完整问题:

我需要找到一种在csharp中运行命令行命令并捕获其输出的方法。 我知道如何在Perl中执行此操作,下面是我将在Perl中使用的代码。

#machine to check my $pc = $_[0]; #create location of registry query my $machine = "\\\\".$pc."\\HKEY_USERS"; #run registry query my @regQuery= `REG QUERY $machine`; 

有关如何在csharp中执行此操作的任何建议都将受到欢迎。 到目前为止,我已经尝试使用RegistryKey OurKey = Registry.Users方法,它工作得很好但我无法在远程计算机上查询注册表。

如果您需要更多信息,请与我们联系。

解决方案:(谢谢@Robaticus)

 private void reg(string host) { string build = "QUERY \\\\" + host + "\\HKEY_USERS"; string parms = @build; string output = ""; string error = string.Empty; ProcessStartInfo psi = new ProcessStartInfo("reg.exe", parms); psi.RedirectStandardOutput = true; psi.RedirectStandardError = true; psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal; psi.UseShellExecute = false; System.Diagnostics.Process reg; reg = System.Diagnostics.Process.Start(psi); using (System.IO.StreamReader myOutput = reg.StandardOutput) { output = myOutput.ReadToEnd(); } using (System.IO.StreamReader myError = reg.StandardError) { error = myError.ReadToEnd(); } Output.AppendText(output + "\n"); } 

您可能需要对此进行一些调整,但这里有一些(从原始版本略微修改)代码重定向stdout和stderr进程:

  string parms = @"QUERY \\machine\HKEY_USERS"; string output = ""; string error = string.Empty; ProcessStartInfo psi = new ProcessStartInfo("reg.exe", parms); psi.RedirectStandardOutput = true; psi.RedirectStandardError = true; psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal; psi.UseShellExecute = false; System.Diagnostics.Process reg; reg = System.Diagnostics.Process.Start(psi); using (System.IO.StreamReader myOutput = reg.StandardOutput) { output = myOutput.ReadToEnd(); } using(System.IO.StreamReader myError = reg.StandardError) { error = myError.ReadToEnd(); } 

实际上,您可以在命令行中运行的任何内容都可以在具有类似约束的C#程序中运行。 有几种方法可以实现,一种是通过我在博客中显示的异步流程命令。 您只需以活动方式编写和读取命令行。 从这里开始,只需弄清楚你想要完成什么以及如何使用命令行完成它。 然后将其插入程序

 class Program { static void Main(string[] args) { LaunchCommandAsProcess cmd = new LaunchCommandAsProcess(); cmd.OutputReceived += new LaunchCommandAsProcess.OutputEventHandler(launch_OutputReceived); cmd.SendCommand("help"); cmd.SendCommand("ipconfig"); cmd.SyncClose(); } /// Outputs normal and error output from the command prompt. static void launch_OutputReceived(object sendingProcess, EventArgsForCommand e) { Console.WriteLine(e.OutputData); } } 

如您所见,您只需实例化类,处理输出事件,并开始编写命令,就像您在命令提示符中键入一样。

以下是它的工作原理:

 public class LaunchCommandAsProcess { public delegate void OutputEventHandler(object sendingProcess, EventArgsForCommand e); public event OutputEventHandler OutputReceived; private StreamWriter stdIn; private Process p; public void SendCommand(string command) { stdIn.WriteLine(command); } public LaunchCommandAsProcess() { p = new Process(); p.StartInfo.FileName = @"C:\Windows\System32\cmd.exe"; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardInput = true; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; p.StartInfo.CreateNoWindow = true; p.Start(); stdIn = p.StandardInput; p.OutputDataReceived += Process_OutputDataReceived; p.ErrorDataReceived += Process_OutputDataReceived; p.BeginOutputReadLine(); p.BeginErrorReadLine(); } /// /// Raises events when output data has been received. Includes normal and error output. /// /// /// private void Process_OutputDataReceived(object sendingProcess, DataReceivedEventArgs outLine) { if (outLine.Data == null) return; else { if (OutputReceived != null) { EventArgsForCommand e = new EventArgsForCommand(); e.OutputData = outLine.Data; OutputReceived(this, e); } } } /// /// Synchronously closes the command promp. /// public void SyncClose() { stdIn.WriteLine("exit"); p.WaitForExit(); p.Close(); } /// /// Asynchronously closees the command prompt. /// public void AsyncClose() { stdIn.WriteLine("exit"); p.Close(); } } public class EventArgsForCommand : EventArgs { public string OutputData { get; internal set; } } 

这是我使用的课程。 它改编自我刚才在博客中找到的代码,但有各种其他修改。

 using System; using System.Diagnostics; using System.Text; using System.Threading; namespace SonomaTechnologyInc { ///  /// Utility class for working with command-line programs. ///  public class Subprocess { private Subprocess() { } ///  /// Executes a command-line program, specifying a maximum time to wait /// for it to complete. ///  ///  /// The path to the program executable. ///  ///  /// The command-line arguments for the program. ///  ///  /// The maximum time to wait for the subprocess to complete, in milliseconds. ///  ///  /// A  containing the results of /// running the program. ///  public static SubprocessResult RunProgram(string command, string args, int timeout) { bool timedOut = false; ProcessStartInfo pinfo = new ProcessStartInfo(command); pinfo.Arguments = args; pinfo.UseShellExecute = false; pinfo.CreateNoWindow = true; //pinfo.WorkingDirectory = ? pinfo.RedirectStandardOutput = true; pinfo.RedirectStandardError = true; Process subprocess = Process.Start(pinfo); ProcessStream processStream = new ProcessStream(); try { processStream.Read(subprocess); subprocess.WaitForExit(timeout); processStream.Stop(); if(!subprocess.HasExited) { // OK, we waited until the timeout but it still didn't exit; just kill the process now timedOut = true; try { subprocess.Kill(); processStream.Stop(); } catch { } subprocess.WaitForExit(); } } catch(Exception ex) { subprocess.Kill(); processStream.Stop(); throw ex; } finally { processStream.Stop(); } TimeSpan duration = subprocess.ExitTime - subprocess.StartTime; float executionTime = (float) duration.TotalSeconds; SubprocessResult result = new SubprocessResult( executionTime, processStream.StandardOutput.Trim(), processStream.StandardError.Trim(), subprocess.ExitCode, timedOut); return result; } } ///  /// Represents the result of executing a command-line program. ///  public class SubprocessResult { readonly float executionTime; readonly string stdout; readonly string stderr; readonly int exitCode; readonly bool timedOut; internal SubprocessResult(float executionTime, string stdout, string stderr, int exitCode, bool timedOut) { this.executionTime = executionTime; this.stdout = stdout; this.stderr = stderr; this.exitCode = exitCode; this.timedOut = timedOut; } ///  /// Gets the total wall time that the subprocess took, in seconds. ///  public float ExecutionTime { get { return executionTime; } } ///  /// Gets the output that the subprocess wrote to its standard output stream. ///  public string Stdout { get { return stdout; } } ///  /// Gets the output that the subprocess wrote to its standard error stream. ///  public string Stderr { get { return stderr; } } ///  /// Gets the subprocess's exit code. ///  public int ExitCode { get { return exitCode; } } ///  /// Gets a flag indicating whether the subprocess was aborted because it /// timed out. ///  public bool TimedOut { get { return timedOut; } } } internal class ProcessStream { /* * Class to get process stdout/stderr streams * Author: SeemabK (seemabk@yahoo.com) * Usage: //create ProcessStream ProcessStream myProcessStream = new ProcessStream(); //create and populate Process as needed Process myProcess = new Process(); myProcess.StartInfo.FileName = "myexec.exe"; myProcess.StartInfo.Arguments = "-myargs"; //redirect stdout and/or stderr myProcess.StartInfo.UseShellExecute = false; myProcess.StartInfo.RedirectStandardOutput = true; myProcess.StartInfo.RedirectStandardError = true; //start Process myProcess.Start(); //connect to ProcessStream myProcessStream.Read(ref myProcess); //wait for Process to end myProcess.WaitForExit(); //get the captured output :) string output = myProcessStream.StandardOutput; string error = myProcessStream.StandardError; */ private Thread StandardOutputReader; private Thread StandardErrorReader; private Process RunProcess; private string _StandardOutput = ""; private string _StandardError = ""; public string StandardOutput { get { return _StandardOutput; } } public string StandardError { get { return _StandardError; } } public ProcessStream() { Init(); } public void Read(Process process) { try { Init(); RunProcess = process; if(RunProcess.StartInfo.RedirectStandardOutput) { StandardOutputReader = new Thread(new ThreadStart(ReadStandardOutput)); StandardOutputReader.Start(); } if(RunProcess.StartInfo.RedirectStandardError) { StandardErrorReader = new Thread(new ThreadStart(ReadStandardError)); StandardErrorReader.Start(); } int TIMEOUT = 1 * 60 * 1000; // one minute if(StandardOutputReader != null) StandardOutputReader.Join(TIMEOUT); if(StandardErrorReader != null) StandardErrorReader.Join(TIMEOUT); } catch { } } private void ReadStandardOutput() { if(RunProcess == null) return; try { StringBuilder sb = new StringBuilder(); string line = null; while((line = RunProcess.StandardOutput.ReadLine()) != null) { sb.Append(line); sb.Append(Environment.NewLine); } _StandardOutput = sb.ToString(); } catch { } } private void ReadStandardError() { if(RunProcess == null) return; try { StringBuilder sb = new StringBuilder(); string line = null; while((line = RunProcess.StandardError.ReadLine()) != null) { sb.Append(line); sb.Append(Environment.NewLine); } _StandardError = sb.ToString(); } catch { } } private void Init() { _StandardError = ""; _StandardOutput = ""; RunProcess = null; Stop(); } public void Stop() { try { if(StandardOutputReader != null) StandardOutputReader.Abort(); } catch { } try { if(StandardErrorReader != null) StandardErrorReader.Abort(); } catch { } StandardOutputReader = null; StandardErrorReader = null; } } } 

这不回答问题,但Registry.OpenRemoteBaseKey方法以与REG命令相同的方式连接到另一台机器的注册表。 调用RegistryKey.GetSubKeyNames以获得与REG QUERY相同的输出。

您可以使用System.Diagnostics.Process类捕获StandardOutput和StandardError。

http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx

请务必阅读文档的备注部分。 必须正确设置流程类的某些属性才能使StandardOutput可用(例如,必须将UseShellExecute设置为false)。