【问题标题】:Strange DLL loading behavior in Powershell 7Powershell 7 中奇怪的 DLL 加载行为
【发布时间】:2021-07-28 04:42:55
【问题描述】:

我已经设法将我的测试归结为一个简单的命令:

PS C:\Users\CpUser> [System.Reflection.Assembly]::LoadFrom("C:\Users\CpUser\.nuget\packages\njsonschema\10.4.0\lib\net45\NJsonSchema.dll")
MethodInvocationException: Exception calling "LoadFrom" with "1" argument(s): "Could not load file or assembly 'NJsonSchema, Version=10.4.0.0, Culture=neutral, PublicKeyToken=c2f9c3bdfae56102'."

我在 Windows 10 上使用 64 位 Powershell v7.1.3。以管理员身份运行。它无法加载我给它的 DLL,这对我来说很奇怪。它也没有给我任何关于它为什么不能加载它的细节。当我尝试使用较低版本的 NJsonSchema.dll 时,它可以工作,但它从一个意外的位置加载它:

PS C:\Users\CpUser> [System.Reflection.Assembly]::LoadFrom("C:\Users\CpUser\.nuget\packages\njsonschema\9.10.52\lib\net45\NJsonSchema.dll")

GAC    Version        Location
---    -------        --------
False  v4.0.30319     C:\Program Files\PowerShell\7\NJsonSchema.dll

它是从C:\Program Files\Powershell\7 加载的,这对我来说似乎是错误的。我发送到该 DLL 的属性 -> 详细信息,它说它是版本 10.2.2似乎在这里发生的事情是:

  1. Powershell 采用我在LoadFrom() 调用中提供的程序集版本
  2. 它在C:\Program Files\PowerShell\7 中搜索版本等于或大于上一步中获得的版本的同一个DLL
  3. 如果没有找到,失败。

我期望它使用我给它的绝对路径加载 DLL。

作为一种解决方法,我找到了另一个似乎确实有效的解决方案:

$AssemblyPath = "C:\Users\CpUser\.nuget\packages\njsonschema\10.4.0\lib\net45\NJsonSchema.dll"
$bytes = [System.IO.File]::ReadAllBytes($AssemblyPath)
[System.Reflection.Assembly]::Load($bytes)

当我在脚本中运行上述内容时,我得到了成功的结果:

PS C:\Users\CpUser> .\testLoadDll.ps1

GAC    Version        Location
---    -------        --------
False  v4.0.30319

所以我觉得这排除了 DLL 本身的任何问题。我完全迷失在这里。有人可以解释我看到的行为以及如何获得我期望的行为吗?

【问题讨论】:

标签: c# .net powershell


【解决方案1】:

根据文档,对于Assembly.LoadFrom Method

LoadFrom 方法有以下缺点。考虑使用 Load 代替。

                 ...

如果使用 LoadFrom 加载程序集,并且探测路径包括 具有相同标识但位置不同的程序集, InvalidCastException、MissingMethodException 或其他意外 行为可能发生。

更新

根据Resolving PowerShell module assembly dependency conflicts

PowerShell 和 .NET

PowerShell 在 .NET 平台上运行。 NET 最终负责 用于解析和加载程序集依赖项,所以我们必须了解 .NET 如何在此处操作以了解依赖冲突。

我们还必须面对这样一个事实,即不同版本的 PowerShell 在不同的 .NET 实现上运行。一般来说,PowerShell 5.1 和 下面在 .NET Framework 上运行,而 PowerShell 6 及更高版本在 .NET 上运行 核。 .NET 加载和处理程序集的这两种实现 不同。这意味着解决依赖冲突可能会有所不同 取决于底层的 .NET 平台。

因此,如果使用 Powershell 版本 6 及更高版本,请确保将 DLL 加载到 netstandard2.0 文件夹中。

尝试以下方法:

打开 PowerShell 7.1.3 版:

  • 在“输入此处进行搜索”框中,输入pwsh
  • 右击PowerShell 7 (x64)
  • 选择Run as administrator

获取 PowerShell 版本

Get-Host | Select-Object Version

获取加载的程序集

[System.AppDomain]::CurrentDomain.GetAssemblies()

加载 NJsonSchema.dll

注意:由于我们使用的是 PowerShell 7.x.x,因此请使用 netstandard2.0 文件夹中的 NJsonSchema.dll 文件。

$Assembly = [System.Reflection.Assembly]::Loadfile('C:\Users\CpUser\.nuget\packages\njsonschema\10.4.0\lib\netstandard2.0\NJsonSchema.dll')

获取加载的程序集(再次):

[System.AppDomain]::CurrentDomain.GetAssemblies()

检查 NJsonSchema.dll 的版本

$Assembly.GetName()

【讨论】:

  • 我将$env:PATH$env:PSModulePath 设置为单个目录(我正在加载的DLL 的位置),它STILL 失败。当我调用 Load("NJsonSchema") 时,它仍然从 Program Files 位置加载它。这让我发疯了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-31
  • 2014-02-16
  • 1970-01-01
  • 1970-01-01
  • 2021-10-02
  • 2018-10-17
  • 2016-11-06
相关资源
最近更新 更多