在 powershell 模块中与直接在我的脚本中相同代码的不同行为

Different behaviour for same code when in a powershell module vs directly in my script

我在加载我们的一个 DLL 时遇到问题,该 DLL 的引用需要 Newtonsoft.Json.dll 版本 8.0.0.0 或 6.0.0.0,但我们的程序集使用 9.0.1.0。当在我们的解决方案中的其他地方使用时,在其 app.config 中绑定重定向不是问题,但在 powershell 中加载我们的二进制文件以调用其函数之一时会出现问题。

davidpodhola's answer 之后,我完全按照他的建议进行操作,以便将 Newtonsoft.Json.dll 的 Version=8.0.0.0 或 Version=6.0.0.0 重定向到我们使用的版本 9.0.1.0在我们所有的项目中。我们需要在不同的脚本中多次加载该 dll,因此我制作了一个 powershell 模块以调用如下所示的函数:

function LoadTfsToolsDll(
    [Parameter(Mandatory=$true)]
    [string] $pathToTfsToolsDll
    )
{
    Try
    {
        $parentFolder = Split-Path -Path $pathToTfsToolsDll
        $pathToNewtonSoft = [io.path]::combine($parentFolder, 'Newtonsoft.Json.dll')
        $newtonsoft = [reflection.assembly]::LoadFrom($pathToNewtonSoft) 

        $OnAssemblyResolve = [System.ResolveEventHandler] {
          param($sender, $e)

          # from:NewtonsoftJson, Version=8.0.0.0 or Version=6.0.0.0
          # to:  NewtonsoftJson, Version=9.0.1.0
          if ($e.Name -eq "Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed") { return $newtonsoft }
          if ($e.Name -eq "Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed") { return $newtonsoft }

          foreach($a in [System.AppDomain]::CurrentDomain.GetAssemblies())
          {
            if ($a.FullName -eq $e.Name)
            {
              return $a
            }
          }
          return $null
        }

        [System.AppDomain]::CurrentDomain.add_AssemblyResolve($OnAssemblyResolve)
    }
    Catch
    {
        throw [System.Exception]::new("Problem doing Newtonsoft.Json's binding redirect. See Inner exception.", $PSItem.Exception)
    }

    Try
    {
        Add-Type -Path $pathToTfsToolsDll
    }
    Catch
    {
        throw [System.Exception]::new("Problem loading TfsTools.dll. See Inner exception.", $PSItem.Exception)
    }
}

Export-ModuleMember -Function LoadTfsToolsDll

不幸的是,使用 Import-Module 导入上面的模块,并直接在我的脚本顶部复制上面的代码(所以在使用我们的程序集的功能之前先 运行 )不会导致同样的行为。

当直接写在我的脚本中时,它是 运行 无一例外,然后我可以毫无问题地调用我的程序集的函数。然而,当在我的脚本开头导入模块时,没有抛出异常,但是当调用我的程序集函数时,我得到以下异常,这应该由我的模块代码修复:

Exception calling "getSpecificBuildVNext" with "4" argument(s): "Could not load file or assembly 'Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The 
system cannot find the file specified."
At C:\Script\Test Run Scripts\Vision Tests\GCS Tests\Steps\InstallSC.ps1:70 char:4
+             $build = [TFS]::getSpecificBuildVNext('https://tfs.genete ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : FileNotFoundException

这两种解决方案有什么区别,我怎样才能让它与 powershell 模块一起工作,而不是直接在不同的脚本中多次复制相同的代码?

根据我自己的研究,似乎是:

  1. A new PS session is created when a module is imported for that module
  2. When running one of the module's function, it is ran from the module's PS session, and not the script's PS session

这意味着我试图加载(并对其进行绑定重定向)的二进制文件仅在模块的 PS 会话中正确加载和重定向,而不是我的调用脚本的会话。