【问题标题】:How do you access underlying PowerShell runspace from C# Cmdlet?如何从 C# Cmdlet 访问底层 PowerShell 运行空间?
【发布时间】:2021-03-03 07:13:02
【问题描述】:

我正在使用 C#/.NET API 构建一些 PowerShell cmdlet,并且有一个 cmdlet 需要访问所有当前导入的模块。如果我在终端中运行Get-Module,我可以看到加载了 10 多个模块,但是当我的 cmdlet 运行时:

using(var ps = PowerShell.Create(RunspaceMode.Current))
{
    var modules = ps.AddCommand("Get-Module").Invoke<PSModuleInfo[]>();
    /// ...
}

modules 这里是空的。它几乎就像一个范围问题,但我认为RunspaceMode.Current 将允许您访问在您首先打开pwsh shell 时打开的底层运行空间。

我一定是遗漏了什么或者误解了运行空间的工作原理。

【问题讨论】:

  • “需要访问所有当前导入的模块的 cmdlet”听起来像是代码异味……您要完成什么?
  • 嗯,这不是我正在处理的代码,只是一个基本示例。但是,我的代码会生成一些动态 PS 模块代理,并且在“完成”我的 cmdlet 之后,我需要它自行清理。所以我试图在这些动态模块上调用“Remove-Module”,当从 cmdlet 内部运行时似乎什么都没有发生。它似乎与“Get-Module”有同样的问题,它是一个更简单的例子,这就是我在我的问题中使用它的原因。
  • 如果我直接在 PS 中编写我的 Cmdlet,这一切都会奏效,所以我想我不明白为什么当你在 C# 中尝试它时这不起作用。

标签: c# powershell .net-core


【解决方案1】:

您不应该直接从 cmdlet 内部弄乱调用运行空间 - 它已经忙于执行您的 cmdlet。出于同样的原因,您也不能直接从另一个人调用PSCmdlet

相反,您需要使用 PSCmdlet.InvokeCommand.InvokeScript() 让运行时为您执行脚本(就像您在 PowerShell 函数中有 Get-Module 语句一样):

[Cmdlet(VerbsCommon.Get, "ModuleProxy")]
public class GetModuleProxyCommand : PSCmdlet
{
    // ...

    protected override void EndProcessing()
    {
        foreach(var module in InvokeCommand.InvokeScript("Get-Module"))
        {
            WriteObject(module);
        }
    }
}

话虽如此,如果您正在做的事情以需要您执行 Remove-Module 或在调用者上下文中清理内容的方式影响环境,那么您最好在单独的运行空间中进行工作无论如何:)

【讨论】:

  • 好的,谢谢,至少澄清了“为什么”它似乎不允许你这样做。我在这里用 PS 做一些非常非传统的事情,所以它不像人们想象的那么简单。这些“额外”代理是暂时的,仅作为提供连接/身份验证缓存的外观。说来话长,哈哈。但我会尝试以类似于你所说的另一种方式来做到这一点。谢谢
  • @MattHintzke 这听起来一点也不特别不传统或奇怪——事实上它听起来很像JEA :)
  • 哈哈,好吧,那很好。由于您看起来像 PowerShell 专家,因此您可能有兴趣了解我们正在构建的内容。 skykick.com/manage。旨在帮助减少 IT 管理的认知负担,因为 SaaS、IaaS 和 PaaS 变得更加复杂。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-07
  • 1970-01-01
  • 1970-01-01
  • 2016-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多