簡體   English   中英

在 Pipeline.Invoke 拋出后,在 C# 中捕獲 Powershell output

[英]Capturing Powershell output in C# after Pipeline.Invoke throws

我正在從 C# 應用程序運行 Powershell 測試腳本。 該腳本可能會由於錯誤的 cmdlet 而失敗,這會導致 pipe.Invoke() 引發異常。

我能夠捕獲我需要的有關異常的所有信息,但我希望能夠顯示腳本的 output 到那時為止。 我沒有任何運氣,因為拋出異常時結果似乎是 null 。

有什么我想念的嗎? 謝謝!

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?
}

不確定這是否有用。 我猜你正在運行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);
}

我最終使用的解決方案是實現我們自己的PSHost來處理PowerShell的輸出。 最初的信息來自“建築物”中的http://community.bartdesmet.net/blogs/bart/archive/2008/07/06/windows-powershell-through-ironruby-writing-a-custom-pshost.aspx自定義PS主機“部分。

在我的情況下,它確實需要使用自定義PSHostRawUserInterface。

以下是對所做工作的快速概述。 我只列出了我實際上已經實現的功能,但是有許多只是包含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
}

我也有同樣的問題。 pipe.Invoke()拋出異常時獲取輸出的最簡單方法是使用Invoke(IEnumerable輸入,IList輸出)

示例顯示如何以正確的順序獲得所有輸出,錯誤,減弱等

PowerShell腳本

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

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}");
}                                                
}

如果您想在異常之前訪問對象並繼續使用管道而不是 Powershell 實例,您可以使用Pipeline.Output.DataReadyPipeline.Error.DataReady 方法 這是一個將所有流重定向到默認 output(使用MergeMyResults )並監聽默認管道 output 的示例:

Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Output.DataReady += (sender, eventArgs) =>
{
    PSObject obj = ((PipelineReader<PSObject>)sender).Read();
    Console.WriteLine("OUTPUT: "+obj.ToString());
};
pipeline.Commands.AddScript(script);
pipeline.Commands[pipeline.Commands.Count-1]
    .MergeMyResults(PipelineResultTypes.All, PipelineResultTypes.Output);
pipeline.Invoke();
runspace.Close();
}
catch (Exception ex)
{
    Console.WriteLine("ERROR: "+ ex.Message);
}

暫無
暫無

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

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