【问题标题】:Passing an associative array from c# to Powershell将关联数组从 c# 传递到 Powershell
【发布时间】:2025-12-27 00:15:11
【问题描述】:

我想将一个关联数组从 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

我想通过 distinct 命令的管道而不是标记为脚本的单个命令来执行此操作。代码如下:


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# powershell associative-array


    【解决方案1】:

    通过 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"}}'))
    

    在这种情况下,命令接收一个包含两个字符串的数组,即“名称”和哈希表文字字符串。这将以与您的 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 体验中最不显眼但最强大的部分。

    -奥辛

    【讨论】:

    • 在“管理”上输入,还有“错误 CS0117:“System.Management.Automation.ScriptBlock”不包含“创建”的定义”——除此之外,效果很好
    • 啊,您必须使用 v1 powershell(创建静态在 v2 上)。对不起!
    • 我就是这么想的。无论如何都接受了解决方案。我调整了您提供的内容以获得我需要的内容并将其应用于真实的应用程序。效果很好。有史以来最好的。
    • 谢谢!我一直在将脚本块实例化为ScriptBlock.Create("{ $_ }"),而我需要ScriptBlock.Create("$_")