Wednesday, December 9, 2009

Capturing Output as String and Variable in Powershell

I'm embedding a posh shell into a C# app I'm writing, and I needed a way to capture the text output of the app, as well as the results as an array. This is what I came up with:

Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();

runspace.SessionStateProxy.SetVariable( "location", "c:\\" );
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript( "get-childitem $location" );

// this splits the output into the text and variable
Command cmd = new Command( "tee-object" );
// this is where the result array will end up
cmd.Parameters.Add( "variable", "invoke_results" );
pipeline.Commands.Add( cmd );
// forces the rest of the output to string
pipeline.Commands.Add( "out-string" );

Collection<PSObject> results = pipeline.Invoke();

var errors = pipeline.Error;

if( 0 < errors.Count )
{
 // there might be more. For now, we read the first
 var oneError = errors.Read( 1 );
 ConsoleColor formerConsoleColor = Console.ForegroundColor;
 Console.ForegroundColor = ConsoleColor.Red;
 Console.WriteLine( "Error: {0}", oneError[0] );
 Console.ForegroundColor = formerConsoleColor;
}
else
// hooray, no errors
{
 object[] resArray = (object[])runspace.SessionStateProxy.GetVariable( "invoke_results" );

 Func<List<String>, object, List<String>> nameAcc =
  ( n, o ) =>
  {
   n.Add( o.ToString() );
   return n;
  };

 List<String> names = resArray.AsEnumerable().Aggregate( new List<String>(),
        nameAcc
  );

 foreach( var list in names )
 {
  Console.WriteLine( list );
 }
}

runspace.Close();
This was much easier than trying to implement my own custom host.

No comments:

Post a Comment