从C#传递关联数组到PowerShell

7
我想从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命令参数的方式有什么问题吗?

1个回答

13

使用C#创建管道和使用本地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”和散列字面字符串。 这将以与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


除了“Mananagement”类型和“error CS0117: 'System.Management.Automation.ScriptBlock' does not contain a definition for 'Create'”之外,其他都很好。 - xcud
啊,你一定在使用v1 PowerShell(创建静态内容是在v2上的)。抱歉! - x0n
那正是我想的。无论如何都接受解决方案。我根据你提供的内容进行了调整,以获得我所需的并将其应用于实际应用程序中。效果非常好。有史以来最棒的。 - xcud
谢谢!我一直在实例化脚本块,例如 ScriptBlock.Create("{ $_ }"),但实际上我需要使用 ScriptBlock.Create("$_") - Tahir Hassan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接