调用System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()

时间:2016-08-03 17:53:36

标签: c# .net powershell dll

我有点奇怪的情况。我得到了一个相当大的PowerShell模块和函数套件,我将它们组合成一个可执行文件是我的职责。要求声明这必须是没有安装程序的单个独立可执行文件,而.net 3.5可能是唯一的依赖项。 Windows Management Framework也不例外,不能假定它存在于计算机上。为了解决这个问题,我添加了System.Management.Automation作为参考,并将其作为嵌入式资源以及所有PowerShell模块文件,并在运行时从反射中加载它们。这似乎工作正常,但我有一些错误,我似乎无法弄清楚,并认为它可能与这个系统有关。

所以问题就出现了:当我开始初始化运行PowerShell命令的东西时,我得到了一个我似乎无法控制的奇怪错误。

以下是代码:

public static void RunCommand(object objcommand)
    {
        //create a script block for toolbox once, get the embeded resource, convert from byte array to string, make scriptblock from string
        ScriptBlock toolbox = System.Management.Automation.ScriptBlock.Create(System.Text.Encoding.Default.GetString(Properties.Resources.toolbox));
        string command = (string)objcommand;
        //get the module name
        string modname = options.Commands[command]["module"];
        //get the module from the embeded resources, convert to string, convert to scriptblock
        var module = System.Management.Automation.ScriptBlock.Create(new System.IO.StreamReader(myasm.GetManifestResourceStream("piramids.Resources." + modname + ".psm1")).ReadToEnd());
        using (var powerShell = PowerShell.Create())
        {
            System.Management.Automation.Runspaces.Runspace rs = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(); //i think this line triggers the exception
            rs.Open();
            powerShell.Runspace = rs;


            //make the necesary powershell modules of the command availible
            powerShell.AddCommand("new-module").AddParameter("ScriptBlock", toolbox).Invoke();
            powerShell.AddCommand("new-module").AddParameter("ScriptBlock", module).Invoke();


            //if inethistory, make dlls availible
            if (modname.Equals("inethistory"))
            {
                powerShell.AddCommand("add-type").AddParameter("Path", sqldll).Invoke();
                powerShell.AddCommand("add-type").AddParameter("Path", esentdll).Invoke();
            }



            ICollection<PSObject> output = new List<PSObject>(0);
            try {
                output = powerShell.AddCommand("get-" + command).AddCommand(format).AddCommand("out-string").Invoke();//pipeline.Invoke();
            } catch (System.Management.Automation.RuntimeException e)
            {
                Console.Error.WriteLine("An Error occured while executing '" + command + "'");
                Console.Error.WriteLine(e.Message);
            }
        //do stuff with the results

这是堆栈跟踪:

Unhandled Exception: System.ArgumentException: The path is not of a legal form.
    at System.IO.Path.NormalizePathFast(String path, Boolean fullCheck)
    at System.IO.Path.NormalizePath(String path, Boolean fullCheck)
    at System.IO.Path.GetFullPathInternal(String path)
    at System.IO.Path.GetFullPath(String path)
    at System.Diagnostics.FileVersionInfo.GetFullPathWithAssert(String fileName)
    at System.Diagnostics.FileVersionInfo.GetVersionInfo(String fileName)
    at System.Management.Automation.PSVersionInfo.GetPSVersionTable()
    at System.Management.Automation.PSVersionInfo.get_PSVersion()
    at Microsoft.PowerShell.DefaultHost..ctor(CultureInfo currentCulture, CultureInfo currentUICulture)
    at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()
    at piramids.Program.RunCommand(Object objcommand)
    at piramids.Program.Main(String[] args)

我相信这一行是异常发生的地方:

System.Management.Automation.Runspaces.Runspace rs = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace();

没有记录CreateRunspace方法来抛出任何异常,并且这个异常来自如此多的层次,因为我不知道这个东西正在检查什么样的路径,因为我从来没有调用过要求路径的函数。 / p>

我很难过。有谁知道造成这种情况的原因是什么?

编辑:经过一番挖掘,这是我发现的。 PSVersionTable是VersionInfo的静态字段,因此静态构造函数在第一次调用此字段时被调用。静态构造函数调用一个名为GetBuildVersion的内部方法,该方法尝试获取PSVersionInfo的程序集位置。根据{{​​3}}:

  

如果从字节数组加载程序集,例如使用Load(Byte [])方法重载时,返回的值为空字符串(“”)。

我从字节数组加载,所以这将是一个空字符串。但是GetBuildVersion使用此位置执行FileVersionInfo.GetVersionInfo,它使用Path.GetFullPath验证路径。根据{{​​3}}:

  

的ArgumentException:
  路径是零长度字符串

所以有问题。现在的问题是,如何为从字节数组加载的程序集分配位置?愿上帝怜悯我。

1 个答案:

答案 0 :(得分:0)

我完全不相信,如果没有安装WMF,期望PowerShell代码能够工作,这甚至是合理的。如果我接到该请求,我会回答所有代码必须用另一种.NET语言(即C#)重建。

不过,也许你可以看看它是否是这种静态方法。您必须对我害怕的代码进行解压缩。 PowerShell加速器只是我进入System.Management.Automation程序集的一种简单方法。该类不公开,并且该类的方法也不公开。

$ verInfo = [PowerShell] .Assembly.GetTypes()| Where-Object Name -eq&#39; PSVersionInfo&#39;    $ verInfo.GetMethod(&#39; get_PSVersion&#39;,[System.Reflection.BindingFlags]&#39; NonPublic,Static&#39;)。Invoke($ null,[System.Reflection.BindingFlags]&#39; NonPublic ,Static&#39;,$ null,@(),$ null)

克里斯