1

我需要能够通过 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 中,我已经测试并确保它正在调用 ModuleName。 C:\\Powershell\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

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

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

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

4

3 回答 3

1

我怀疑你需要做两件事:

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

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

于 2012-04-25T13:10:04.607 回答
1

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

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

我测试了这对上述问题很有用。

于 2012-05-09T07:03:06.767 回答
1

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

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

ModuleToProcess = 'ModuleName.psm1'

我将它添加到 NestedModules 中:

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

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

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

于 2012-05-24T17:43:43.333 回答