在 Pipeline.Invoke 抛出后捕获 C# 中的 Powershell 输出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1233640/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:00:44  来源:igfitidea点击:

Capturing Powershell output in C# after Pipeline.Invoke throws

c#powershellpowershell-1.0

提问by Nick A

I'm running a Powershell test script from a C# application. The script can fail due to a bad cmdlet which causes pipe.Invoke() to throw an exception.

我正在从 C# 应用程序运行 Powershell 测试脚本。由于 cmdlet 错误导致 pipe.Invoke() 抛出异常,脚本可能会失败。

I'm able to capture all the information I need about the exception, but I'd like to be able to display the script's output up to that point. I haven't had any luck since results appears to be null when an exception is thrown.

我能够捕获我需要的关于异常的所有信息,但我希望能够显示脚本的输出到那时。我没有任何运气,因为抛出异常时结果似乎为空。

Is there something I'm missing? Thanks!

有什么我想念的吗?谢谢!

m_Runspace = RunspaceFactory.CreateRunspace();
m_Runspace.Open();
Pipeline pipe = m_Runspace.CreatePipeline();
pipe.Commands.AddScript(File.ReadAllText(ScriptFile));
pipe.Commands.Add("Out-String");
try {
   results = pipe.Invoke();
}
catch (System.Exception)
{
   m_Runspace.Close();
   // How can I get to the Powershell output that comes before the exception?
}

采纳答案by Nick A

The solution I ended up using was to implement our own PSHost to handle PowerShell's output. The initial information for this came from http://community.bartdesmet.net/blogs/bart/archive/2008/07/06/windows-powershell-through-ironruby-writing-a-custom-pshost.aspxin the "Building a custom PS host" section.

我最终使用的解决方案是实现我们自己的 PSHost 来处理 PowerShell 的输出。这方面的初始信息来自http://community.bartdesmet.net/blogs/bart/archive/2008/07/06/windows-powershell-through-ironruby-writing-a-custom-pshost.aspx中的“Building自定义 PS 主机”部分。

In my case it did require using a custom PSHostRawUserInterface as well.

就我而言,它确实也需要使用自定义 PSHostRawUserInterface。

Here's the quick overview of what was done. I've only listed the function I actually implimented, but there's many that are just contain throw new NotImplementedException();

以下是已完成内容的快速概览。我只列出了我实际实现的函数,但有很多只是包含 throw new NotImplementedException();

private class myPSHost : PSHost
{
   (Same as what the above link mentions)
}
private class myPSHostUI : PSHostUserInterface
{
   private myPSHostRawUI rawui = new myPSHostRawUI();

   public override void Write // all variations
   public override PSHostRawUserInterface RawUI { get { return rawui; } }

}
private class myPSHostRawUI : PSHostRawUserInterface
{
   public override ConsoleColor ForegroundColor
   public override ConsoleColor BackgroundColor
   public override Size BufferSize
}

回答by Doug Finke

Not sure if this is helpful. I am guessing you are running V1. This V2 approach doesn't throw and prints the result:

不确定这是否有帮助。我猜你正在运行 V1。这种 V2 方法不会抛出并打印结果:

Hello World
67 errors

string script = @"
  'Hello World'
  ps | % {
    $_.name | out-string1
  }
";

PowerShell powerShell = PowerShell.Create();

powerShell.AddScript(script);
var results = powerShell.Invoke();

foreach (var item in results)
{
  Console.WriteLine(item);
}

if (powerShell.Streams.Error.Count > 0)
{
  Console.WriteLine("{0} errors", powerShell.Streams.Error.Count);
}

回答by Jan Smuda

I have the same problem. The easiest way to get output when pipe.Invoke() throws an exception is to use Invoke(IEnumerable input, IList output)

我也有同样的问题。pipe.Invoke() 抛出异常时获取输出的最简单方法是使用Invoke(IEnumerable input, IList output)

Example shows how to get all output, error, waning etc. in the correct order

示例显示如何以正确的顺序获取所有输出、错误、衰减等

PowerShell script

PowerShell 脚本

Write-Output "Hello world" 
Write-Error "Some error"
Write-Warning "Some warning"
throw "Some exception"

C#

C#

List<string> RunLog = new List<string>(); 

using (System.Management.Automation.PowerShell psInstance = System.Management.Automation.PowerShell.Create())

{
    psInstance.AddScript(_Script);

psInstance.Streams.Error.DataAdded += (sender, args) =>
{
    ErrorRecord err = ((PSDataCollection<ErrorRecord>)sender)[args.Index];
    RunLog.Add($"ERROR: {err}");
};

psInstance.Streams.Warning.DataAdded += (sender, args) =>
{
    WarningRecord warning = ((PSDataCollection<WarningRecord>)sender)[args.Index];
    RunLog.Add($"WARNING: {warning}");
};

... etc ...

var result = new PSDataCollection<PSObject>();
result.DataAdded += (sender, args) =>
{
    PSObject output = ((PSDataCollection<PSObject>)sender)[args.Index];
    RunLog.Add($"OUTPUT: {output}");
};

try
{
    psInstance.Invoke(null, result);
}
catch(Exception ex)
{
    RunLog.Add($"EXCEPTION: {ex.Message}");
}                                                
}