2009-08-05 17 views
11

Estoy ejecutando un script de prueba Powershell desde una aplicación C#. El script puede fallar debido a un cmdlet incorrecto que hace que pipe.Invoke() arroje una excepción.Captura de la salida Powershell en C# después de Pipeline.Invoke throws

Soy capaz de capturar toda la información que necesito sobre la excepción, pero me gustaría poder mostrar la salida del script hasta ese punto. No he tenido suerte ya que los resultados parecen nulos cuando se lanza una excepción.

¿Hay algo que me falta? ¡Gracias!

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

Respuesta

8

La solución Terminé usando era poner en práctica nuestra propia PSHost para manejar la salida de PowerShell. La información inicial para esto provino del http://community.bartdesmet.net/blogs/bart/archive/2008/07/06/windows-powershell-through-ironruby-writing-a-custom-pshost.aspx en la sección "Creación de un host PS personalizado".

En mi caso, también requirió el uso de una PSHostRawUserInterface personalizada.

Aquí está la descripción rápida de lo que se hizo. Solo he enumerado la función que en realidad realicé, pero hay muchas que solo contienen 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 
} 
+0

Bueno, exactamente lo que estaba buscando. Gracias. –

14

No estoy seguro de que esto es útil. Supongo que estás ejecutando V1. Este enfoque V2 no lanza e imprime el resultado:

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); 
} 
+0

estás en lo correcto, estoy usando la energía shell v1. –

0

Tengo el mismo problema. La forma más fácil de salida cuando pipe.Invoke() lanza una excepción es el uso de Invoke(IEnumerable input, IList output)

ejemplo muestra cómo obtener toda la salida, error, etc. menguante en el orden correcto

script de 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}"); 
}             
} 
Cuestiones relacionadas