Хостинг PowerShell: PowerShell против Runspace против RunspacePool против трубопровода
Я пытаюсь добавить довольно ограниченную поддержку PowerShell в свое приложение: я хочу иметь возможность периодически запускать определенный пользователем сценарий PowerShell и показывать любой вывод и (в конечном итоге) иметь возможность обрабатывать уведомления о ходе выполнения и запросы пользователей. Мне не нужна интерактивная поддержка в стиле командной строки или (я думаю) удаленный доступ или возможность запуска нескольких одновременных сценариев, если только пользовательский сценарий не делает это сам из оболочки, которую я размещаю. В конце концов я захочу запустить скрипт асинхронно или в фоновом потоке и, возможно, заполнить оболочку некоторыми начальными переменными и, возможно, командлетом, но настолько "причудливым", как эта функция, скорее всего, получится.
Я читал документацию MSDN о написании кода хост-приложения, но, несмотря на то, что он радостно объясняет, как создать объект PowerShell
, или Runspace
, или RunspacePool
, или Pipeline
, там нет указаний на то, почему один из этих подходов предпочтительнее другого.
Я думаю, что я отношусь к одному из этих двух, но мне нравятся некоторые отзывы о том, какой подход лучше выбрать:
PowerShell shell = PowerShell.Create();
shell.AddCommand(/* set initial state here? */);
shell.AddStatement();
shell.AddScript(myScript);
shell.Invoke(/* can set host! */);
или:
Runspace runspace = RunspaceFactory.CreateRunspace(/* can set host and initial state! */);
PowerShell shell = PowerShell.Create();
shell.Runspace = runspace;
shell.AddScript(myScript);
shell.Invoke(/* can set host here, too! */);
(Одним из обязательных методов класса PSHost
-derived является EnterNestedPrompt()
, и я не знаю, может ли пользовательский скрипт, который я запускаю, вызывать его, или нет. Если это возможно, то я Вы будете ответственны за "запуск нового вложенного цикла ввода" (как здесь)... если это повлияет на то, какой путь выбрать выше, это также было бы полезно знать.)
Спасибо!
Ответы
Ответ 1
Кто они такие?
Конвейер - это способ объединения команд внутри сценария powershell. Пример: вы " Get-ChildeItem
" вывод из Get-ChildeItem
в Where-Object
с помощью |
отфильтровать их:
Get-ChildItem | Where-Object {$_}
Объект PowerShell ссылается на сеанс PowerShell, аналогичный тому, который вы получаете при запуске powershell.exe.
Каждый сеанс powershell имеет свое собственное пространство выполнения (вы всегда будете получать выходные данные из Get-Runspace
). Он определяет состояние сеанса powershell. Следовательно, InitialSessionState
объект/свойство пространства выполнения. Вы можете решить создать новый сеанс PowerShell с собственным пространством выполнения из PowerShell, чтобы включить многопоточность.
И последнее, но не менее важное - RunspacePool. Как следует из названия, это пул пространств выполнения (или сеансов PowerShell), которые можно использовать для обработки множества завершенных задач. Как только одно из пространств выполнения в пуле завершило свою задачу, она может выполнить следующую задачу, пока все не будет сделано. (100 вещей, которые нужно сделать с 10 пространствами выполнения: в avarage они обрабатывают по 10 в каждом, но один может обрабатывать 8, в то время как два других обрабатывают 11...)
Когда использовать что?
Конвейер используется insed из скриптов. Это облегчает создание сложных сценариев и должно использоваться как можно чаще.
Объект powershell используется всякий раз, когда вам нужен новый сеанс powershell. Вы можете создать его внутри существующего скрипта, будь то С# или Powershell. Это полезно для легкого многопоточности. Сам по себе он создаст сеанс по умолчанию.
Если вы хотите создать нестандартный сеанс powershell, вы можете манипулировать объектом runspace перед созданием сеанса powershell с ним. Это полезно, когда вы хотите совместно использовать синхронизированные переменные, функции или классы в дополнительных пространствах выполнения. Чуть более сложная многопоточность.
Как упоминалось ранее, это тяжелый инструмент для тяжелой работы. Когда одно выполнение скрипта занимает часы, и вам нужно делать это очень часто. Например, в сочетании с удаленным взаимодействием вы можете одновременно установить что-то на каждом узле большого кластера и т.п.
Ответ 2
Вы переосмысливаете это. Код, который вы показываете в примерах, является хорошим началом. Теперь вам просто нужно прочитать результат Invoke()
и проверить потоки ошибок и предупреждений.
Хост PowerShell предоставляет несколько хуков, которые RunSpace может использовать для связи с пользователем, таких как вывод потока и форматирования, показ прогресса, сообщения об ошибках и т.д. Для того, что вы хотите сделать, вам не нужен хост PowerShell. Вы можете прочитать результаты обратно из выполнения скрипта с помощью класса PowerShell, проверить наличие ошибок, предупреждений, прочитать выходные потоки и показать уведомление пользователю, используя возможности вашего приложения. Это будет гораздо проще и эффективнее, чем написать весь хост PowerShell, чтобы отобразить окно сообщения при обнаружении ошибок.
Кроме того, у объекта PowerShell есть Runspace при его создании, вам не нужно указывать его. Если вам нужно сохранить пространство выполнения для сохранения среды, просто сохраните весь объект PowerShell и очищайте Commands и все Stream каждый раз после вызова Invoke.
Следующий вопрос, который вы должны задать, - как обработать результат PowerShell::Invoke()
и прочитать PowerShell::Streams
.