2011-01-03 4 views
16

Резюме:Как захватить вывод команды командной консоли в C#?

  • реестра запрос на удаленной машине
  • выход
  • захвата для использования в приложении
  • потребности быть в 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, приветствуются. Пока ive попытался использовать метод 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"); 


     } 
+0

возможно дубликат [Захват NSlookup выход оболочки с C#] (http://stackoverflow.com/questions/353601/capturing-nslookup-shell-output-with-c) –

+2

Пробовали ли вы 'RegistryKey.OpenRemoteBaseKey '? http://msdn.microsoft.com/en-us/library/8zha3xws.aspx –

+0

PowerShell был бы намного лучшим выбором. – TrueWill

ответ

27

Вы, возможно, придется настроить это немного, но вот некоторые (слегка измененный от исходного) код, который перенаправляет стандартный вывод и стандартный поток ошибок для процесса:

 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

Благодарим вас за код. Я просто попытался реализовать и выполнить его. У меня возникают проблемы с захватом вывода из него. В настоящее время я использую Output.AppendText (output + "\ n"); для печати вывода. это верно? Im new to csharp (около 3 часов опыта :) :) – toosweetnitemare

+0

Это мое решение. Мне просто пришлось набросать имя машины в переменную :). Большое спасибо! – toosweetnitemare

+0

Обратите внимание, что этот код * должен * работать для 'reg.exe', но будет зависать с тупиком для программы, которая достаточно записывает свой стандартный поток ошибок, чтобы заполнить размер буфера по умолчанию. Правильным решением для общего случая является чтение обоих потоков вывода одновременно с отдельными потоками. –

3

Это не дает ответа на вопрос, но метод Registry.OpenRemoteBaseKey подключается к реестру другого компьютера таким же образом, что команда REG делает. Вызовите RegistryKey.GetSubKeyNames, чтобы получить тот же результат, что и REG QUERY.

+0

им собираюсь попробовать это прямо сейчас. благодаря! – toosweetnitemare

0

Вы можете захватить StandardOutput и StandardError, используя класс System.Diagnostics.Process.

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

Обязательно прочитайте раздел примечаний документации. Некоторые свойства класса процесса должны быть правильно установлены для доступности StandardOutput (например, UseShellExecute должно быть установлено в false).

8

Практически все, что вы можете запустить в командной строке, вы можете запускать в программе C# с аналогичными ограничениями. Есть несколько способов сделать это, один из них - через команды асинхронного процесса, как показано в моем blog. Вы просто пишете и читаете в командной строке активным способом. Отсюда просто выясните, что вы хотите выполнить и как это сделать с помощью командной строки. Затем вставьте его в программу

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

Как вы можете видеть, вы просто создать экземпляр класса, обрабатывать выходной событие, и начать писать команды так же, как вы typeing в командной строке.

Вот как это работает:

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

Большое спасибо за код. мне понадобится несколько минут, чтобы попробовать применить это к моему приложению. – toosweetnitemare

4

Вот класс, который я использую. Он адаптирован из кода, который я нашел в blog posting некоторое время назад, но с различными другими модификациями.

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

Я адаптировал ваш код и создал библиотеку классов, которые [я выставил на GitHub] (https://github.com/kenny-evitt/ExecuteCommandLineProgram). Любая проблема с этим? –

+1

@KennyEvitt: Никакой проблемы со мной. Насколько я знаю, код мой (за исключением частей, которые пришли от комментатора «SeemabK» в блоге Скотта Хансельмана, конечно). Я больше не работаю для работодателя, над которым я работал, когда писал это, но я не верю, что у них есть претензии к нему. Поэтому я думаю, что все в порядке. –

Смежные вопросы