2011-01-03 11 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メソッドを使って試してみましたが、うまくいきましたが、リモートマシン上のレジストリを照会できません。

詳細情報が必要な場合はお知らせください。

SOLUTION:

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

[C#のでnslookupをシェル出力をキャプチャ]の可能性のある重複あなたは 'RegistryKey.OpenRemoteBaseKeyを試してみました'? http://msdn.microsoft.com/en-us/library/8zha3xws.aspx –

+0

PowerShellがはるかに優れた選択肢になります。 – TrueWill

答えて

27

あなたはこれを少し微調整する必要がありますが、ここでの処理のための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(); 

     } 
+0

この度はありがとうございます。私はちょうどそれを実装して実行しようとしました。 ImはOutput.AppendText(output + "\ n");を使用してit.currentlyから出力を取得することに問題があります。で出力を印刷する。これは正しいです?私は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

ドキュメントの発言部分を必ずお読みください。 ProcessOutクラスの特定のプロパティは、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; 
     } 
    } 
} 
+2

あなたのコードを修正し、[私はGitHubを実装しました](https://github.com/kenny-evitt/ExecuteCommandLineProgram)というクラスライブラリを作成しました。それに問題はありますか? –

+1

@KennyEvitt:私からは問題ありません。私の知る限り、コードは私のものです(Scott Hanselmanのブログのコメント者 "SeemabK"から来たものはもちろんです)。私はそれを書いたときに働いていた雇用者のために働いていませんが、私は彼らにもそれがあるとは思いません。だから私はあなたが大丈夫だと思う。 –

関連する問題