1

我有一个“核心”程序集,其中包含一系列用 C# 编写的 PowerShell Cmdlet。我还有一个使用这个“核心”程序集的 WPF“gui”应用程序。为了使用和编译“核心”,我显然需要 PowerShell 的类型,因此我添加了对System.Management.Automation.dll我的项目的引用。我通过简单地从我的本地机器 GAC 添加对该 DLL 的引用来做到这一点。一切都在我的机器上编译并顺利运行。

当我在另一台机器上部署和运行我的“gui”时,我得到了奇怪的错误。例如:

System.MissingMethodException: Method not found: 'System.Management.Automation.PSDataCollection`1<System.Management.Automation.InformationRecord> System.Management.Automation.PSDataStreams.get_Information()'

我已将原因缩小到这一点:我的“gui”实现了一个自定义 PowerShell 主机并加载“核心”并执行它的 cmdlet。它是这样完成的:

  Host = new MyCustomHost();
  var rs = RunspaceFactory.CreateRunspace(Host);
  PsInstance = PowerShell.Create();

  PsInstance.Runspace = rs;
  rs.Open();

  PsInstance.Streams.Information.DataAdded += delegate (object s, DataAddedEventArgs e)
  {
    nvtLogger.WriteInformation(PsInstance.Streams.Information[e.Index].MessageData.ToString());
  };

显然,PsInstance.Streams.Information在运行时找不到该属性。

我发现System.Management.Automation.dll我作为项目参考添加的那个不一定是加载的那个。该框架首先查看 GAC,如果它在那里找到一个副本,它会使用那个副本而不是我的副本。

我知道问题的原因是部署机器安装了旧版本的 PowerShell,它没有实现我正在使用的属性 - 并引发上述异常。

然而,我不明白的是:当它与我构建的程序集不兼容时,框架如何从 GAC 加载这个程序集?

据我所知,该框架使用 AssemblyVersion、Name 和 PublicKeyToken 来识别程序集。

我的本地集会(工作):

Assembly Location: C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
Assembly Fullname: System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
File ProductVersion: 10.0.14393.1532
File Size: 7,1MB

服务器组件(不工作):

Assembly Location: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
Assembly Fullname: System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
File ProductVersion: 6.3.9600.18728
File Size: 5,8MB

这两个文件无疑是不同的。但根据 AssemblyName,它们是相同的。这样,框架将加载一个或另一个。

两个明显不同的文件(即使只看文件的大小)怎么会有相同的 AssemblyName 呢?

我想补充一点,目标机器是 Windows Server 2012R2,但它并不是我注意到这一点的唯一机器。我还在新安装的 Windows 7 和另一个 Windows 2012 Server 上注意到它。

4

1 回答 1

0

我最终在 NuGet 上使用了官方的 Powershell 参考组件包,从此过上了幸福的生活。尽可能保持兼容,我现在几乎总是使用Microsoft.PowerShell.3.ReferenceAssemblies. 从此再无问题。

于 2020-07-15T19:07:15.500 回答