将关联数组从 C# 传递到 Powershell

发布于 2024-07-14 05:48:22 字数 1528 浏览 3 评论 0原文

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

携君以终年 2024-07-21 05:48:22

通过 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 体验中最不可见但最强大的部分。

-奥辛

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.

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

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:

ps> $ps.Commands[1].Parameters.Add("Property", @("Name", @{N="Foo";E={"Bar"}}))

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:

properties.Add("@{N=\"Foo\";E={\"Bar\"}}");

with

properties.Add(
    new Hashtable {
        {"N", "Foo"},
        {"E", System.Mananagement.Automation.ScriptBlock.Create("\"Foo\"")}
    }
);

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文