10

I am using System.Management.Automation DLL which allows me to call PowerShell within my C# application like so:

PowerShell.Create().AddScript("Get-Process").Invoke();

What I am trying to do is call PowerShell but supply the input list. For example, in:

1, 2, 3 | ForEach-Object { $_ * 2 }

I am trying to supply the left hand side 1, 2, 3 when invoking:

// powershell is a PowerShell Object
powershell.Invoke(new [] { 1, 2, 3 });

However this does not work. The workaround I came up with was using ForEach-Object and then passing the array as an InputObject with the { $_ } as the Process:

// create powershell object
var powershell = PowerShell.Create();

// input array 1, 2, 3
Command inputCmd = new Command("ForEach-Object");
inputCmd.Parameters.Add("InputObject", new [] { 1, 2, 3 });
inputCmd.Parameters.Add("Process", ScriptBlock.Create("$_"));
powershell.Commands.AddCommand(inputCmd);

// ForEach-Object { $_ * 2 }
Command outputCmd = new Command("ForEach-Object");
outputCmd.Parameters.Add("Process", ScriptBlock.Create("$_ * 2"));
powershell.Commands.AddCommand(outputCmd);

// invoke
var result = powershell.Invoke();

Although the above is working code is there any way of using Invoke passing in the input array because I would have though that this would be desirable way of calling it?

2 Answers 2

14

A little bit late but:

PowerShell ps = PowerShell.Create();
ps.Runspace.SessionStateProxy.SetVariable("a", new int[] { 1, 2, 3 });
ps.AddScript("$a");
ps.AddCommand("foreach-object");
ps.AddParameter("process", ScriptBlock.Create("$_ * 2"));
Collection<PSObject> results = ps.Invoke();
foreach (PSObject result in results)
{
    Console.WriteLine(result);
}

returns:

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

3 Comments

This works but you are passing 1,2,3 as a string rather than an array i.e. new int[] { 1,2,3 }. The second one is needed if I am to pass structured data to the pipeline.
@TahirHassan The only way I know to pass .net object created is using SessionStateProxy.SetVariable(string name, object value). Look at my edited answer.
You have answered my question on how to start the pipeline with an array (without passing it to ForEach-Object using the InputObject parameter as described in my question). Thanks.
2

I have done my research and PowerShell.Invoke( IEnumerable ) will set the InputObject of the first command in the list. Therefore instead of setting InputObject on inputCmd above, we can instead pass it through the Invoke method. We still need the first ForEach-Object call to pass the input array to.

1 Comment

This is genius! I would never look for it there!

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.