2011-01-03 35 views
16

Tóm tắt:Làm thế nào để nắm bắt kết quả đầu ra của Shell trong C#?

  • registry truy vấn trên máy tính từ xa
  • chụp đầu ra để sử dụng trong ứng dụng
  • cần phải được trong CSharp
  • cho đến nay tất cả các phương pháp sử dụng chỉ có thể truy vấn trên máy cục bộ
  • bất kỳ hy vọng nào được đánh giá cao

Sự cố đầy đủ:

Tôi cần tìm một cách để chạy một lệnh dòng lệnh trong csharp và nắm bắt đầu ra của nó. Tôi biết làm thế nào để làm điều này trong Perl, dưới đây là mã tôi sẽ sử dụng trong 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`; 

Mọi đề xuất về cách thực hiện điều này trong csharp sẽ được hoan nghênh. Cho đến nay, ive đã thử sử dụng phương thức RegistryKey OurKey = Registry.Users và nó hoạt động rất tốt nhưng tôi không thể truy vấn registry trên máy từ xa.

Vui lòng cho tôi biết nếu bạn cần thêm thông tin.

GIẢI PHÁP: (Cảm ơn bạn @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"); 


     } 
+0

thể trùng lặp của [Chụp sản lượng vỏ nslookup với C#] (http://stackoverflow.com/questions/353601/capturing-nslookup-shell-output-with-c) –

+2

Bạn hãy thử 'RegistryKey.OpenRemoteBaseKey '? http://msdn.microsoft.com/en-us/library/8zha3xws.aspx –

+0

PowerShell sẽ là lựa chọn tốt hơn nhiều. – TrueWill

Trả lời

27

Bạn có thể phải tinh chỉnh này một chút, nhưng đây là một số (chút thay đổi từ bản gốc) mã chuyển hướng stdout và stderr cho một quá trình:

 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(); 

     } 
+0

Cảm ơn bạn đã nhập mã. Tôi chỉ cố gắng thực hiện và thực hiện nó. Im có vấn đề với grabbing đầu ra từ it.currently im bằng cách sử dụng Output.AppendText (đầu ra + "\ n"); để in đầu ra bằng. điều này có đúng không? Im mới để csharp (khoảng 3 giờ tổng số kinh nghiệm :)) – toosweetnitemare

+0

Đây là giải pháp của tôi. Tôi chỉ phải thực sự quăng tên máy vào biến :). Cảm ơn nhiều! – toosweetnitemare

+0

Lưu ý rằng mã này * nên * làm việc cho 'reg.exe', nhưng sẽ treo với một bế tắc cho một chương trình viết đủ để dòng lỗi tiêu chuẩn của nó để lấp đầy kích thước bộ đệm mặc định. Giải pháp đúng cho trường hợp chung là đọc cả hai luồng đầu ra cùng một lúc, với các luồng riêng biệt. –

3

này không trả lời câu hỏi, nhưng phương pháp Registry.OpenRemoteBaseKey kết nối vào registry của máy khác trong cùng một cách mà lệnh REG làm. Hãy gọi RegistryKey.GetSubKeyNames để có được cùng một kết quả như REG QUERY.

+0

Tôi sẽ thử ngay bây giờ. cảm ơn! – toosweetnitemare

0

Bạn có thể chụp StandardOutput và StandardError bằng lớp System.Diagnostics.Process.

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

Hãy nhớ đọc phần nhận xét của tài liệu. Một số thuộc tính của lớp quy trình phải được đặt chính xác cho StandardOutput để có sẵn (ví dụ: UseShellExecute phải được đặt thành false).

8

Thực tế bất cứ điều gì bạn có thể chạy trong dòng lệnh, bạn có thể chạy trong một chương trình C# với các ràng buộc tương tự. Có một vài cách để làm điều đó, một là thông qua các lệnh quá trình không đồng bộ như tôi hiển thị trong blog của tôi. Bạn chỉ cần viết và đọc dòng lệnh theo kiểu hoạt động. Từ đây, chỉ cần tìm ra những gì bạn muốn thực hiện và làm thế nào để làm điều đó với một dòng lệnh. Sau đó, cắm nó vào chương trình

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); 
} 
} 

Như bạn có thể thấy, bạn chỉ cần khởi tạo lớp, xử lý sự kiện đầu ra và bắt đầu viết lệnh giống như bạn đang gõ vào dấu nhắc lệnh.

Dưới đây là cách hoạt động:

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; } 
} 
+0

Cảm ơn bạn rất nhiều vì mã. nó sẽ đưa tôi một vài phút để thử áp dụng điều này vào ứng dụng của tôi. – toosweetnitemare

4

Đây là lớp tôi sử dụng. Nó được điều chỉnh từ mã tôi tìm thấy trong một số blog posting một lúc trước, nhưng với nhiều sửa đổi khác.

using System; 
using System.Diagnostics; 
using System.Text; 
using System.Threading; 

namespace SonomaTechnologyInc { 
    /// <summary> 
    /// Utility class for working with command-line programs. 
    /// </summary> 
    public class Subprocess { 
     private Subprocess() { } 

     /// <summary> 
     /// Executes a command-line program, specifying a maximum time to wait 
     /// for it to complete. 
     /// </summary> 
     /// <param name="command"> 
     /// The path to the program executable. 
     /// </param> 
     /// <param name="args"> 
     /// The command-line arguments for the program. 
     /// </param> 
     /// <param name="timeout"> 
     /// The maximum time to wait for the subprocess to complete, in milliseconds. 
     /// </param> 
     /// <returns> 
     /// A <see cref="SubprocessResult"/> containing the results of 
     /// running the program. 
     /// </returns> 
     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; 
     } 
    } 

    /// <summary> 
    /// Represents the result of executing a command-line program. 
    /// </summary> 
    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; 
     } 

     /// <summary> 
     /// Gets the total wall time that the subprocess took, in seconds. 
     /// </summary> 
     public float ExecutionTime { 
      get { return executionTime; } 
     } 

     /// <summary> 
     /// Gets the output that the subprocess wrote to its standard output stream. 
     /// </summary> 
     public string Stdout { 
      get { return stdout; } 
     } 

     /// <summary> 
     /// Gets the output that the subprocess wrote to its standard error stream. 
     /// </summary> 
     public string Stderr { 
      get { return stderr; } 
     } 

     /// <summary> 
     /// Gets the subprocess's exit code. 
     /// </summary> 
     public int ExitCode { 
      get { return exitCode; } 
     } 

     /// <summary> 
     /// Gets a flag indicating whether the subprocess was aborted because it 
     /// timed out. 
     /// </summary> 
     public bool TimedOut { 
      get { return timedOut; } 
     } 
    } 

    internal class ProcessStream { 
     /* 
     * Class to get process stdout/stderr streams 
     * Author: SeemabK ([email protected]) 
     * 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; 
     } 
    } 
} 
+2

Tôi đã điều chỉnh mã của bạn và tạo một thư viện lớp học mà [Tôi đã đưa lên GitHub] (https://github.com/kenny-evitt/ExecuteCommandLineProgram). Có vấn đề gì với điều đó không? –

+1

@KennyEvitt: Không có vấn đề gì với tôi. Theo như tôi biết mã là của tôi (ngoại trừ những phần đến từ commenter "SeemabK" trên blog của Scott Hanselman, tất nhiên). Tôi không còn làm việc cho người sử dụng lao động mà tôi đã làm việc khi tôi viết điều đó, nhưng tôi cũng không tin họ có bất kỳ yêu cầu nào về nó. Vì vậy, tôi nghĩ bạn ổn. –

Các vấn đề liên quan