#c# #powershell #.net-core
#c# #powershell #.net-core
Вопрос:
Я создаю несколько командлетов PowerShell с использованием API-интерфейсов C # / .NET, и у меня есть командлет, которому требуется доступ ко всем импортируемым в данный момент модулям. Если я запускаю Get-Module
в терминале, я вижу загруженные модули 10 , но при запуске моего командлета:
using(var ps = PowerShell.Create(RunspaceMode.Current))
{
var modules = ps.AddCommand("Get-Module").Invoke<PSModuleInfo[]>();
/// ...
}
modules
здесь пусто. Это почти как проблема с областью действия, но я подумал RunspaceMode.Current
, что это позволит вам получить доступ к тому базовому пространству выполнения, которое было открыто при первом открытии pwsh
оболочки.
Должно быть, я что-то упускаю или неправильно понимаю, как именно работают пространства выполнения.
Комментарии:
1. «командлет, которому требуется доступ ко всем импортируемым в данный момент модулям», звучит как запах кода… чего вы пытаетесь достичь?
2. Ну, это не совсем тот код, с которым я имею дело, просто базовый пример. Однако мой код выполняет некоторую генерацию прокси-сервера динамического модуля PS, и после того, как мой командлет «выполнен», мне нужно, чтобы он очистился после себя. Итак, я пытаюсь вызвать «Remove-Module» для этих динамических модулей, и, похоже, ничего не происходит, когда это выполняется изнутри командлета. Похоже, это та же проблема, что и у «Get-Module», и это более простой пример, поэтому я использовал это в своем вопросе.
3. Если бы я написал свой командлет непосредственно в PS, все это сработало бы, поэтому, я думаю, я не понимаю, почему это не работает, как только вы попробуете это на C #.
Ответ №1:
Вы не должны возиться с вызывающим пространством выполнения непосредственно из командлета — оно уже занято выполнением вашего командлета. Вы также не можете вызвать a PSCmdlet
непосредственно из другого по той же причине.
Вместо этого вы захотите использовать PSCmdlet.InvokeCommand.InvokeScript()
, чтобы среда выполнения выполняла для вас сценарий (точно так же, как если бы у вас был Get-Module
оператор в функции PowerShell):
[Cmdlet(VerbsCommon.Get, "ModuleProxy")]
public class GetModuleProxyCommand : PSCmdlet
{
// ...
protected override void EndProcessing()
{
foreach(var module in InvokeCommand.InvokeScript("Get-Module"))
{
WriteObject(module);
}
}
}
При этом, если то, что вы делаете, влияет на среду таким образом, что требует от вас выполнения Remove-Module
или очистки в контексте вызывающих абонентов, вам, вероятно, гораздо лучше выполнять свою работу в отдельном пространстве выполнения в любом случае 🙂
Комментарии:
1. Хорошо, спасибо, что, по крайней мере, проясняет «почему», похоже, это не позволяет вам это сделать. Я делаю здесь некоторые очень нетрадиционные вещи с PS, так что это не так просто, как можно было бы подумать. Эти «дополнительные» прокси являются временными и предназначены только для использования в качестве фасада для обеспечения кэширования подключения / авторизации. Это долгая история, ха-ха. Но я постараюсь сделать это другим способом, подобным тому, что вы изложили. Спасибо
2. @MattHintzke Это не звучит особенно нетрадиционно или странно вообще — на самом деле это очень похоже на JEA 🙂
3. Ха-ха, хорошо, это хорошо. Поскольку вы кажетесь гуру PowerShell, вам может быть интересно посмотреть, что мы создаем. skykick.com/manage . Цель состоит в том, чтобы помочь снизить когнитивную нагрузку на управление ИТ, поскольку SaaS, IaaS и PaaS становятся все более сложными.