Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/apache-flex/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何重定向Powershell的输出_C#_Powershell - Fatal编程技术网

C# 如何重定向Powershell的输出

C# 如何重定向Powershell的输出,c#,powershell,C#,Powershell,我有一个类似但不同的问题 我有一个很久以前编写的自定义安装程序框架。在它里面,我可以执行“任务”。我最近不得不添加一个任务来执行PowerShell脚本。现在,即使任务是用C#编写的,我也不能直接调用PowerShell脚本中的命令。不幸的是,这是不可能的 简而言之,我想从C#调用PowerShell可执行文件,并将其输出重定向回我的应用程序。以下是我迄今为止所做的工作: 我可以使用以下代码(从我创建的测试项目中)成功调用PowerShell: 从未调用重定向输出的我的处理程序: void po

我有一个类似但不同的问题

我有一个很久以前编写的自定义安装程序框架。在它里面,我可以执行“任务”。我最近不得不添加一个任务来执行PowerShell脚本。现在,即使任务是用C#编写的,我也不能直接调用PowerShell脚本中的命令。不幸的是,这是不可能的

简而言之,我想从C#调用PowerShell可执行文件,并将其输出重定向回我的应用程序。以下是我迄今为止所做的工作:

我可以使用以下代码(从我创建的测试项目中)成功调用PowerShell:

从未调用重定向输出的我的处理程序:

void powerShellProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)

我相当有信心脚本正在运行。现在我只有一个测试脚本,它输出路径内容

$a = $env:path; $a.Split(";")
我在PowerShell实例中对此进行了测试,结果显示输出正确

我可以做什么来让PowerShell输出重定向到我的C#代码?我不想依赖我将执行的脚本来处理它们自己的日志记录。我宁愿收集它们的输出并在框架的日志机制中处理它

编辑 意识到在那个代码示例中,我离开了奇怪的循环等待退出。我经历了“WaitForExit”过程:

编辑
使用@MiniBill的建议。我提出了以下代码snippit:

powerShellProcess.Start();
while (!powerShellProcess.HasExited)
{
  string line;
  while (!string.IsNullOrEmpty((line = powerShellProcess.StandardOutput.ReadLine())))
    this.LogInfo("PowerShell running: " + line);
}
这可以很好地处理输出。它把我的台词删减到80个字符:(,但我可以接受,除非有人能提供建议来解决这个问题

更新解决方案


您想使用
进程.StandardOutput
属性。这是一个可以打开以获取程序输出的流

是否有一种方法可以通知我(事件)当输出发生在控制台上时。似乎如果我使用StandardOutput属性,我将不得不等到进程退出。你可以生成一个新线程,当它找到一些输出时将引发事件。你认为在haseExit上像我发布的那样进行等待循环是可以接受的吗?我应该在该循环中睡觉还是让它飞起来?如果你同意我们的话e循环您应该完全休眠,否则您将无所事事地占用大量CPU。80个字符的截断是powershell,iirc固有的。您可以使用以下内容来代替使用循环:好的,我认为休眠将是一个好主意。我只想在powershell可执行文件将其写入StandardOut时获取输出。等待退出到get所有的输出都不是很理想,因为这不仅仅是为了将其记录在安装程序框架中,而是为了向用户显示当前状态/输出。
$Host.UI.RawUI
有一个
BufferSize
WindowSize
属性,即使它没有写入任何可见的东西,也可能仍然有效。@Kiquenet我已经证明了我在“任务”结构中使用了我的解决方案,该结构使用脚本调用PowerShell可执行文件并记录输出。“UpdateTaskProgress”方法只处理日志记录到我的日志结构和更新我的UI。我很确定Windows也不允许您跨管理/非管理安全边界重定向标准输入/输出/错误。您必须找到不同的方法从以管理员身份运行的程序中获取输出-参考:stackoverflow.com/a/8690661您缺少进程ss.BeginOutputReadLine();和process.BeginErrorReadLine();调用请参见
$a = $env:path; $a.Split(";")
powerShellProcess.WaitForExit();
powerShellProcess.Start();
while (!powerShellProcess.HasExited)
{
  string line;
  while (!string.IsNullOrEmpty((line = powerShellProcess.StandardOutput.ReadLine())))
    this.LogInfo("PowerShell running: " + line);
}
/*
  * 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));