7

Fairly new to C#, not so new to PowerShell.

I want to use C# to execute PowerShell code. However the output of objects isn't in the same as running commands in a PowerShell window. I get back the object's name rather than its data. Here's what I'm trying:

string script = @"
    get-process | ft
";

PowerShell powerShell = PowerShell.Create();

powerShell.AddScript(script);
var results = powerShell.Invoke();
foreach (var item in results)
{
    Console.WriteLine(item);
}

Returns:

Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData

However in a PowerShell command line window it returns a more formated table view:

PS C:\Dropbox\PowerShell> ps | ft

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id SI ProcessName ------- ------ ----- ----- ----- ------ -- -- ----------- 131 12 1980 2572 85 0.45 13216 1 acrotray

Really would like two things:

  1. code that will produce the same output as the PowerShell command window
  2. an explanation of what is going on so I can learn how to navigate it better

Thanks in advance!

1

2 Answers 2

6

I figured it out, thanks to a code example on codeproject I figured out that the command "out-string" needs to be added to the end of all commands. So the extra code to add is:

ps.AddCommand("Out-String");

I wonder if the console is simply doing this or if there is more to it.

Sign up to request clarification or add additional context in comments.

2 Comments

I think that the host is doing that (so whether it's the console host, or ISE host, that's part of its function). When you use a runspace it in C# that won't happen by default, so what you're doing now is fine, or you can have your application be a full-fledged host and implement it in there.
PowerShell engine implicitly pipe any unclaimed object to Out-Default command, and Out-Default turn them into text on host.
0

PowerShell uses its own XML formatting document to return table style output in the console and ISE. Out-String is where this formatting comes into play in your case as it will preserve the formatting(you can use the '-Stream' switch with out string to return each line as it is executed).

It is possible to extract information from an object passed back to C# without using out-string; however, in my experience if you are just displaying this information; it is your best option to return a string. However, if you need to do additional processing on the object you can return an object and then perform conditionals based on what type of object you are dealing with. For example, if I need to manipulate objects once returned from PowerShell (not using 'out-string') I use the following:

System.Diagnostic.Process is your returned object type from the Get-Process Command - Make sure you know exactly what object type you are passing back to C#

using (PowerShell psRunspace = PowerShell.Create())
        {
            psRunspace.AddCommand("Get-Process");
            psRunspace.AddParameter("ComputerName", computerName);

            Collection<PSObject> outputObj = psRunspace.Invoke();

            foreach (PSObject obj in outputObj)
            {
                var objProperties = obj.Properties;
                var objMethods = obj.Methods;
                var baseObj = obj.BaseObject;

                if (baseObj is System.Diagnostic.Process) 
                {
                    var p = (System.Diagnostic.Process)baseObj;
                    //you can now access all members of this object normally
                    //Do something here with p.Properties or p.Methods etc...
                }
            }

I would also recommend, since I don't see it in your question, consider using a 'using' statement to execute your powershell command. this will open and close the pipeline/runspace for you. In your example is doesn't seem like you closed that pipeline unless you just omitted it from your example code. Also, be specific in your invoke command that you use the appropriate type for the objects you are returning and use a Collection as shown above with the type of objects you are returning (PSObject).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.