我想将一个关联数组从C#传递给Powershell.作为一个例子,我想执行这个PowerShell代码行:
PS C:\> get-command | select name, @{N="Foo";E={"Bar"}} -first 3 Name Foo ---- --- Add-Content Bar Add-History Bar Add-Member Bar
我想通过不同命令的管道而不是标记为脚本的单个命令来执行此操作.这是代码:
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());
但是,作为参数传递给Select-Object的关联数组未被正确解析.这是另一方面的结果:
PS C:\test> c:\test\Bin\Debug\test.exe Name @{N="Foo";E={"Bar"}} ---- -------------------- Add-Content Add-History Add-Member
我如何设置Select-Object命令参数有什么问题?
通过c#创建管道并使用native PowerShell脚本创建管道有一个主要区别,实际上非常微妙:参数绑定器.
如果我在纯脚本中编写代码版本,我将得到相同的错误:哈希表文字被视为字符串值.
ps> $ps = $ps.Commands.Add("get-process") ps> $ps = $ps.Commands.Add("select-object") ps> $ps.Commands[1].Parameters.Add("Property", @("Name", '@{N="Foo";E={"Bar"}}'))
在这种情况下,该命令接收两个字符串的数组,"name"和hashtable文字字符串.这将与您的C#完全相同.现在,看看正确的方法(在脚本中) - 让我重写第3行:
ps> $ps.Commands[1].Parameters.Add("Property", @("Name", @{N="Foo";E={"Bar"}}))
那改变了什么?我删除了散列表周围的引号 - 我将散列表作为对象数组的第二个元素传递!因此,要使您的C#示例正常工作,您需要在命令行执行参数绑定器为我们所做的事情(这是非常多的!).更换:
properties.Add("@{N=\"Foo\";E={\"Bar\"}}");
同
properties.Add( new Hashtable { {"N", "Foo"}, {"E", System.Mananagement.Automation.ScriptBlock.Create("\"Foo\"")} } );
我希望这能为你解决这个问题.参数绑定器可能是PowerShell体验中最不可见但最强大的部分.
-Oisin