2011-01-03 2 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에서이 작업을 수행하는 방법에 대한 제안을 환영합니다. 지금까지 필자는 RegistryKey OurKey = Registry.Users 메소드를 사용해 보았지만 훌륭하게 작동하지만 원격 컴퓨터의 레지스트리를 쿼리 할 수는 없습니다.

더 자세한 정보가 필요하면 알려주십시오.

해결책 :

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

가능한 중복 (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

코드를 제공해 주셔서 감사합니다. 방금 구현하고 실행하려고했습니다. 임 it.currently Output.AppendText (출력 + "\ n")를 사용하여 출력 잡아 문제가; 출력을 인쇄하려면. 이 올바른지? 임 csharp에 새로운 (총 경험의 약 3 시간 :)) – toosweetnitemare

+0

이것은 내 해결책이다. 나는 실제로 기계 이름을 변수에 넣어야 만했다. :). 고마워요! – toosweetnitemare

+0

이 코드는'reg.exe'에서 작동해야하지만 기본 버퍼 크기를 채우기에 충분한 표준 오류 스트림을 기록하는 프로그램에 대해 교착 상태가 발생합니다. 일반적인 경우에 대한 올바른 해결책은 별도의 스레드를 사용하여 두 출력 스트림을 동시에 읽는 것입니다. –

3

이 질문에 대답하지 않지만 Registry.OpenRemoteBaseKey 방법은 REG 명령을 수행하는 것과 같은 방법으로 다른 컴퓨터의 레지스트리에 연결 (@Robaticus에게 감사). RegistryKey.GetSubKeyNames으로 전화를 걸어 REG QUERY과 동일한 결과를 얻으십시오.

+0

지금 바로 시도해 보겠습니다. 감사! – toosweetnitemare

0

System.Diagnostics.Process 클래스를 사용하여 StandardOutput 및 StandardError를 캡처 할 수 있습니다.

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

하면 문서의주의 섹션을 읽으십시오. ProcessOutput 클래스의 특정 속성은 StandardOutput이 사용 가능하도록 올바르게 설정되어야합니다 (예 : UseShellExecute를 false로 설정해야 함).

8

실질적으로 명령 줄에서 실행할 수있는 것은 비슷한 제약 조건을 가진 C# 프로그램에서 실행할 수 있습니다. 이를 수행하는 방법은 몇 가지가 있습니다. 하나는 비동기 프로세스 명령을 사용하는 것이며, 이는 blog에 나와 있습니다. 당신은 쓰기 만하고 커맨드 라인을 능동적으로 읽는다. 여기에서, 당신이 원하는 것을 찾아 내고 커맨드 라인으로 그것을 수행하는 방법을 이해하십시오. 그럼 당신은 단순히 클래스를 인스턴스화 출력 이벤트를 처리하고, 명령 프롬프트에 typeing 된 것처럼 명령을 쓰기 시작, 프로그램

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; } 
} 
+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; 
     } 
    } 
} 
[C와 함께 # nslookup을 쉘 출력을 캡처]의
+2

코드를 수정하고 [GitHub에 올려 놓은] 클래스 라이브러리를 만들었습니다 (https://github.com/kenny-evitt/ExecuteCommandLineProgram). 그게 어떤 문제 야? –

+1

@KennyEvitt : 저에게 문제 없습니다. 내가 아는 한 코드는 내 것이다 (물론 Scott Hanselman의 블로그에서 코멘트 작성자 "SeemabK"에서 나온 부분은 제외). 나는 내가 그 일을 할 때 일하는 고용주를 위해 더 이상 일하지 않는다. 그러나 나는 그 일에 어떤 권리도 주장하지 않는다. 너 괜찮다고 생각해. –

관련 문제