Передача ассоциативного массива из С# в Powershell

Я хотел бы передать ассоциативный массив из С# в 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?


person xcud    schedule 06.03.2009    source источник


Ответы (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"}}'))

В этом случае команда получает массив из двух строк: «имя» и литеральную строку хеш-таблицы. Это будет сломано точно так же, как ваш С#. Теперь взгляните на правильный способ сделать это (в сценарии) — позвольте мне переписать строку 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.

-Ойсин

person x0n    schedule 06.03.2009
comment
введите «Управление», также ошибка CS0117: «System.Management.Automation.ScriptBlock» не содержит определения для «Создать» - кроме этого, отлично работает - person xcud; 06.03.2009
comment
ах, вы, должно быть, используете powershell v1 (статическое создание находится в v2). простите! - person x0n; 07.03.2009
comment
Вот что я понял. Решение все равно принято. Я адаптировал то, что вы предоставили, чтобы получить то, что мне было нужно, и применил это к реальному приложению. Работает отлично. Лучший когда-либо. - person xcud; 07.03.2009
comment
Благодарю вас! Я постоянно создавал блок сценария как ScriptBlock.Create("{ $_ }"), когда вместо этого мне нужно было ScriptBlock.Create("$_") - person Tahir Hassan; 06.11.2012