【问题标题】:Import a Powershell Module on a Remote Server in a C# Runspace在 C# 运行空间中的远程服务器上导入 Powershell 模块
【发布时间】:2012-03-22 22:40:24
【问题描述】:

我需要能够通过 C# 运行空间导入驻留在远程机器上的模块。

为了明确我的意思:我正在创建的服务驻留在服务器 A 上。它使用以下方法创建到服务器 B 的远程运行空间。通过运行空间,我试图在服务器 B 上导入一个模块。

这是我用来进行远程调用的方法:

internal Collection<PSObject> RunRemoteScript(string remoteScript, string remoteServer, string scriptName, out bool scriptSuccessful)
    {
        bool isLocal = (remoteServer == "localhost" || remoteServer == "127.0.0.1" || remoteServer == Environment.MachineName);

        WSManConnectionInfo connectionInfo = null;

        if (!isLocal)
        {
            connectionInfo = new WSManConnectionInfo(new Uri("http://" + remoteServer + ":5985"));
        }

        PsHostImplementation myHost = new PsHostImplementation(scriptName);

        using (Runspace remoteRunspace = (isLocal ? RunspaceFactory.CreateRunspace(myHost) : RunspaceFactory.CreateRunspace(myHost, connectionInfo)))
        {
            remoteRunspace.Open();
            using (PowerShell powershell = PowerShell.Create())
            {
                powershell.Runspace = remoteRunspace;

                Pipeline pipeline = remoteRunspace.CreatePipeline();

                pipeline.Commands.AddScript(remoteScript);

                Collection<PSObject> results = pipeline.Invoke();

                remoteRunspace.Close();

                scriptSuccessful = myHost.ScriptSuccessful;
                return results;
            }
        }
    }

"remoteScript" 设置为我要运行的 Powershell 脚本。例如:

"Import-Module Modulename;CustomCommand-FromModule -parameter(s) -ErrorAction stop"

模块没有打包在一起,它是一个 psd1、psm1 和一堆脚本文件,它们位于远程服务器(服务器 B)上的 C:\\Powershell\ModuleName 中,我已经测试并确保它正在调用C:\\Powershell\ModuleName 目录中的 ModuleName.psd1 文件。

ModuleName.psd1 文件里面有一行:

ModuleToProcess = 'ModuleName.psm1'

但是,如果我尝试通过 c# 运行空间运行它,则会收到一个非常奇怪的错误。

如果我将以下内容作为参数发送到“remoteScript”:

"Import-Module Modulename"

我收到以下错误:

System.Management.Automation.RemoteException:处理“ModuleName.psm1”的模块,列在模块清单“C:\Powershell\ModuleName\ModuleName.psd1”的字段“ModuleToProcess”中,因为没有有效模块在任何模块目录中找到。

该模块确实存在于“$env:PSModulePath 位置之一,并且在您运行时会显示:

get-module -listAvailable

我还尝试将 ModuleName.psm1 文件的完全限定路径放入 psd1 文件中。当我这样做时(或下面 x0n 的建议),我得到几乎完全相同的错误:

未处理模块清单“C:\Powershell\ModuleName\ModuleName.psd1”的“ModuleToProcess”字段中列出的用于处理“C:\Powershell\ModuleName\ModuleName.psm1”的模块,因为未找到有效模块在任何模块目录中。

在这一点上,我真的不确定该去哪里,或者即使这实际上是可能的。我到处搜索,发现了一些看似相关的东西,但从来都不完全相同,往往是我已经克服或(据我所知)还没有遇到的问题。任何帮助,将不胜感激!谢谢!

【问题讨论】:

  • 尝试在 PSD1 中使用 ModuleToProcess = Join-Path $psscriptroot 'modulename.psm1'。
  • 感谢 x0n,但我仍然收到错误消息。我在原始帖子中添加了更多细节。
  • 能否通过命令行远程导入模块?
  • 有完整源代码的最终解决方案吗?什么是 PsHostImplementation ?
  • @AdamDriscoll 抱歉,我真的不记得导入是否通过手动远程会话进行。我认为它有效,但我不再确定。如果你需要知道你正在尝试解决的问题,我可以尝试测试它(我已经解决了这个问题,所以我必须小心测试)。

标签: c# powershell module runspace


【解决方案1】:

我怀疑你需要做两件事:

  1. 使用.psd1 文件的绝对路径:否则只会考虑在$env:PSModulePath 中找到的模块(与执行加载的脚本运行的位置无关)。

  2. 确保您可以加载远程脚本。默认或RemoteSigned 执行策略将阻止远程脚本,除非签名。

【讨论】:

  • 感谢您的反馈。您提到的两个步骤绝对是任何人都需要做的事情(这些是我确保在我的故障排除过程中完成的事情),但这些都不是最终的问题。我将发布我的最终解决方案。
【解决方案2】:

我发现,如果您的模块是在较新的 .net 运行时(例如 .net 4.0)上构建的,并且您试图在 powershell 2.0(基于 .net 3.5)中加载它,这可能是一个问题......要解决这个,你需要确保在.net 4.0 clr中加载powershell或调用进程。

您可以通过在 *.exe.config 中为支持的运行时添加一个实体来执行此操作(如果不存在,则创建 powershell.exe.config)。

我测试了这对上述问题非常有效。

【讨论】:

  • 我已经解决了这个问题(我还没有发布解决方案,我的错)但是如果问题再次出现,这听起来很棒。谢谢!
【解决方案3】:

自从我解决这个问题以来已经有一点时间了,所以我为延迟道歉。这个问题的解决方案实际上很简单,虽然有点奇怪。

为了解决这个问题,我在 ModuleName.psd1 中注释掉了:

ModuleToProcess = 'ModuleName.psm1'

我将它添加到 NestedModules 中:

NestedModules = Join-Path $psscriptroot 'ModuleName.psm1'

坦率地说,我不确定为什么这会让模块成功加载,但它对我有用。

我解决这个问题已经有一段时间了,所以我可能在这里错过了一些微小的步骤。如果这对您不起作用,请告诉我您遇到了什么问题,然后我可以让您知道这是否是我必须做的其他事情。我相当肯定这就是全部。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-10
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多