Разное поведение для одного и того же кода, когда в модуле powershell vs прямо в моем скрипте
У меня были проблемы с загрузкой одной из наших библиотек DLL, в которых есть ссылки, для которых требуется Newtonsoft.Json.dll версии 8.0.0.0 или 6.0.0.0, но наша сборка использует 9.0.1.0. Это не проблема с привязкой редиректов в его app.config при использовании в другом месте нашего решения, но при загрузке нашего бинарного файла в powershell вызывается одна из его функций.
После ответа Давидподхолы я сделал именно то, что он предложил, чтобы перенаправить версию =8.0.0.0 или версию =6.0.0.0 файла Newtonsoft.Json.dll на версию 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 ответ
Из моего собственного исследования, кажется, что:
- Новый сеанс PS создается, когда модуль импортируется для этого модуля
- При запуске одной из функций модуля она запускается из сеанса PS модуля, а не из сеанса PS скрипта
Это будет означать, что двоичный файл, который я пытался загрузить (и выполнить перенаправление привязки), загружается и перенаправляется только правильно в сеансе PS модуля, а не в сеансе моего вызывающего скрипта.