I’d like to pass an associative array from C# to Powershell. As an example I’d like to execute this powershell line of code:
PS C:\> get-command | select name, @{N='Foo';E={'Bar'}} -first 3 Name Foo ---- --- Add-Content Bar Add-History Bar Add-Member Bar
I’d like to do this via a Pipeline of distinct Commands as opposed to a single command marked as a script. Here’s the code:
Runspace runspace = RunspaceFactory.CreateRunspace(); runspace.Open(); Pipeline pipeline = runspace.CreatePipeline(); pipeline.Commands.Add('get-command'); Command c = new Command('select-object'); List properties = new List(); properties.Add('name'); properties.Add('@{N=\'Foo\';E={\'Bar\'}}'); c.Parameters.Add('Property', properties.ToArray()); c.Parameters.Add('First', 3); pipeline.Commands.Add(c); pipeline.Commands.Add('Out-String'); Collection retval = pipeline.Invoke(); runspace.Close(); StringBuilder stringBuilder = new StringBuilder(); foreach (PSObject obj in retval) Console.WriteLine(obj.ToString());
But that associative array being passed in as a parameter to Select-Object isn’t being parsed correctly. This is what comes out the other side:
PS C:\test> c:\test\Bin\Debug\test.exe Name @{N='Foo';E={'Bar'}} ---- -------------------- Add-Content Add-History Add-Member
What’s wrong with how I’m setting up the Select-Object command parameters?
Creating a pipeline through c# and creating a pipeline with native powershell script have one major difference that is actually quite subtle: the parameter binder.
if I write a version of your code in pure script, I will get the same error: the hashtable literal is treated as a string value.
In this case, the command receives an array of two strings, the ‘name’ and the hashtable literal string. This will be broken in exactly the same way as your C#. Now, take a look at the right way to do it (in script) – let me rewrite line 3:
So what changed? I removed the quotes around the hashtable — I am passing a hashtable as the 2nd element of the object array! So, to get your C# example to work, you need to do what the parameter binder does for us at the command line (which is quite a lot!). Replace:
with
I hope this clears it up for you. The parameter binder is probably the least visible but most powerful part of the powershell experience.
-Oisin