簡體   English   中英

如何從Powershell重定向輸出

[英]How Do I Redirect Output From Powershell

我有一個類似但不同的問題,如如何從TaskScheduler運行的腳本重定向Powershell輸出,並覆蓋默認寬度為80個字符

我很久以前就有一個自定義安裝程序框架。 在其中我可以執行“任務”。 我最近不得不添加一個任務來執行PowerShell腳本。 現在,即使任務是用C#編寫的,我也無法直接調用PowerShell腳本中的命令。 不幸的是,這已不在考慮范圍之內。

簡而言之,我想從C#調用PowerShell可執行文件並將其輸出重定向回我的應用程序。 這是我到目前為止所做的:

我可以使用以下代碼(來自我創建的測試項目)成功調用PowerShell:

  string powerShellExeLocation = null;

  RegistryKey localKey = Registry.LocalMachine;

  RegistryKey subKey = localKey.OpenSubKey(@"SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine");
  powerShellExeLocation = subKey.GetValue("ApplicationBase").ToString();

  if (!Directory.Exists(powerShellExeLocation))
    throw new Exception("Cannot locate the PowerShell dir.");

  powerShellExeLocation = Path.Combine(powerShellExeLocation, "powershell.exe");

  if (!File.Exists(powerShellExeLocation))
    throw new Exception("Cannot locate the PowerShell executable.");

  string scriptLocation = Path.Combine(Environment.CurrentDirectory, "PowerShellScript.ps1");

  if (!File.Exists(scriptLocation))
    throw new Exception("Cannot locate the PowerShell script.");

  ProcessStartInfo processInfo = new ProcessStartInfo();
  processInfo.Verb = "runas";
  processInfo.UseShellExecute = false;
  processInfo.RedirectStandardOutput = true;
  processInfo.RedirectStandardOutput = true;
  processInfo.WorkingDirectory = Environment.CurrentDirectory;

  processInfo.FileName = powerShellExeLocation;
  processInfo.Arguments = "-NoLogo -OutputFormat Text -NonInteractive -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + scriptLocation + "\" ";

  Process powerShellProcess = new Process();
  powerShellProcess.StartInfo = processInfo;
  powerShellProcess.OutputDataReceived += new DataReceivedEventHandler(powerShellProcess_OutputDataReceived);
  powerShellProcess.ErrorDataReceived += new DataReceivedEventHandler(powerShellProcess_ErrorDataReceived);

  powerShellProcess.Start();

  while (!powerShellProcess.HasExited)
  {
    Thread.Sleep(500);
  }

我永遠不會調用我的重定向輸出處理程序:

void powerShellProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)

void powerShellProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)

我相信腳本正在運行。 現在我只有一個輸出PATH內容的測試腳本。

$a = $env:path; $a.Split(";")

我在PowerShell實例中對此進行了測試,並且輸出正確。

我該怎么做才能讓PowerShell輸出重定向到我的C#代碼? 我不想依賴我將執行的腳本來處理自己的日志記錄。 我寧願收集他們的輸出並在框架的日志記錄機制中處理它。

編輯已實現我離開了奇怪的循環,等待該代碼示例中的退出。 我有進程“WaitForExit”:

powerShellProcess.WaitForExit();

編輯
使用@MiniBill的建議。 我想出了以下代碼snippit:

powerShellProcess.Start();
while (!powerShellProcess.HasExited)
{
  string line;
  while (!string.IsNullOrEmpty((line = powerShellProcess.StandardOutput.ReadLine())))
    this.LogInfo("PowerShell running: " + line);
}

這樣可以很好地處理輸出。 它正在削減我的行80個字符:(但我可以忍受,除非其他人可以提供修復它的建議!

更新解決方案

/*
  * The next few lines define the process start info for the PowerShell executable.
  */
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.Verb = "runas";
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
processInfo.WorkingDirectory = Environment.CurrentDirectory;

//this FileName was retrieved earlier by looking in the registry for key "HKLM\SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine" and the value for "ApplicationBase"
processInfo.FileName = powerShellExeLocation;

//if we're going to use script arguments build up the arguments from the process start correctly.
if (!string.IsNullOrEmpty(this.ScriptArguments))
  processInfo.Arguments = "-NoLogo -NonInteractive -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + ScriptLocation + "\" '" + ScriptArguments + "'";
else
  processInfo.Arguments = "-NoLogo -NonInteractive -WindowStyle Hidden -ExecutionPolicy Unrestricted -File \"" + ScriptLocation + "\"";

//create the Process object, set the start info, and start the process
Process powerShellProcess = new Process();
powerShellProcess.StartInfo = processInfo;

powerShellProcess.Start();

/*
  * While the PowerShell process hasn't exited do the following:
  * 
  * Read from the current position of the StandardOutput to the end by each line and
  * update the tasks progress with this information
  * 
  * Read from the current position of StandardError to the end by each line, update
  * the task's progress with this information and set that we have an error.
  * 
  * Sleep for 250 milliseconds (1/4 of a sec)
  */
bool isError = false;
while (!powerShellProcess.HasExited)
{
  string standardOuputLine, standardErrorLine;
  while (!string.IsNullOrEmpty((standardOuputLine = powerShellProcess.StandardOutput.ReadLine())))
  {
    this.UpdateTaskProgress(standardOuputLine);
  }


  while (!string.IsNullOrEmpty((standardErrorLine = powerShellProcess.StandardError.ReadLine())))
  {
    this.UpdateTaskProgress(standardErrorLine);
    isError = true;
  }

  Thread.Sleep(250);
}

/*
  * Now that the process has completed read to the end of StandardOutput and StandardError.
  * Update the task progress with this information.
  */

string finalStdOuputLine = powerShellProcess.StandardOutput.ReadToEnd();
string finalStdErrorLine = powerShellProcess.StandardError.ReadToEnd();

if (!string.IsNullOrEmpty(finalStdOuputLine))
  this.UpdateTaskProgress(finalStdOuputLine);

if (!string.IsNullOrEmpty(finalStdErrorLine))
{
  this.UpdateTaskProgress(finalStdErrorLine);
  isError = true;
}

// there was an error during the run of PowerShell that was output to StandardError.  This doesn't necessarily mean that
// the script error'd but there was a problem.  Throw an exception for this.
if (isError)
  throw new Exception(string.Format(CultureInfo.InvariantCulture, "Error during the execution of {0}.", this.ScriptLocation));

您想要使用Process.StandardOutput屬性。 這是一個流,你可以打開以獲得程序的輸出

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM