Powershell - 在應用程序配置文件中找不到程序集綁定重定向
這裡有問題…
我有一個 Powershell CmdLet,它在 32 位模式下執行時工作,在 64 位模式下失敗。問題是原因是什麼以及如何解決。
情況
引用“OutlookHelper.Common.dll”的 Powershell CmdLet。最新版本是 2.0.0.0 CmdLet 還使用日誌記錄並引用“Logging.dll”。
Logging.dll 還引用了“OutlookHelper.Common.dll”,僅針對版本 1.0.0.0 編譯。
我是如何使它工作的,這部分工作
在 Powershell 的應用程序配置文件中使用程序集綁定重定向:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0.30319"/> <supportedRuntime version="v2.0.50727"/> </startup> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="OutlookHelper.Common" publicKeyToken="5e4553dc0df45306"/> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/> </dependentAssembly> </assemblyBinding> </runtime> </configuration>Powershell 32 位工作得很好
在 64 位機器上執行時,使用“Windows Powershell (x86)”可以正常工作。程序集管理器找到程序集綁定重定向:
The operation was successful. Bind result: hr = 0x0. The operation completed successfully. Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll Running under executable C:\Windows\syswow64\Windowspowershell\v1.0\powershell.exe --- A detailed error log follows. === Pre-bind state information === LOG: User = MYDOMAIN\testuser LOG: DisplayName = OutlookHelper.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5e4553dc0df45306 (Fully-specified) LOG: Appbase = file:///C:/Windows/syswow64/Windowspowershell/v1.0/ LOG: Initial PrivatePath = NULL LOG: Dynamic Base = NULL LOG: Cache Base = NULL LOG: AppName = powershell.exe Calling assembly : OutlookHelper.Data.Common, Version=1.0.5295.26925, Culture=neutral, PublicKeyToken=null. === LOG: This bind starts in LoadFrom load context. WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load(). LOG: Using application configuration file: C:\Windows\syswow64\Windowspowershell\v1.0\powershell.exe.Config LOG: Using host configuration file: LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config. LOG: Redirect found in application configuration file: 1.0.0.0 redirected to 2.0.0.0. LOG: Post-policy reference: OutlookHelper.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=5e4553dc0df45306 LOG: GAC Lookup was unsuccessful. LOG: Attempting download of new URL file:///C:/Windows/syswow64/Windowspowershell/v1.0/OutlookHelper.Common.DLL. LOG: Attempting download of new URL file:///C:/Windows/syswow64/Windowspowershell/v1.0/OutlookHelper.Common/OutlookHelper.Common.DLL. LOG: Attempting download of new URL file:///C:/Windows/syswow64/Windowspowershell/v1.0/OutlookHelper.Common.EXE. LOG: Attempting download of new URL file:///C:/Windows/syswow64/Windowspowershell/v1.0/OutlookHelper.Common/OutlookHelper.Common.EXE. LOG: Attempting download of new URL file:///D:/SampleApps/_Common/Bin/Outlook.Extensions.Sample/OutlookHelper.Common.DLL. LOG: Assembly download was successful. Attempting setup of file: D:\SampleApps\_Common\Bin\Outlook.Extensions.Sample\OutlookHelper.Common.dll LOG: Entering run-from-source setup phase. LOG: Assembly Name is: OutlookHelper.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=5e4553dc0df45306 LOG: Where-ref bind Codebase does not match what is found in default context. Keep the result in LoadFrom context. LOG: Binding succeeds. Returns assembly from D:\SampleApps\_Common\Bin\Outlook.Extensions.Sample\OutlookHelper.Common.dll. LOG: Assembly is loaded in LoadFrom load context.這是 Powershell 關於程序集標識的說明:
Windows PowerShell (x86) Copyright (C) 2009 Microsoft Corporation. All rights reserved. PS C:\Users\testuser> ([xml](gc $([System.AppDomain]::CurrentDomain.SetupInformation.ConfigurationFile))).configuratio n.runtime.assemblyBinding.dependentAssembly.assemblyIdentity name publicKeyToken ---- -------------- OutlookHelper.Common 5e4553dc0df45306 PS C:\Users\testuser>這就是麻煩開始的地方…
在 64 位機器上執行時,使用“Windows Powershell”它不起作用。程序集管理器未找到程序集綁定重定向:
The operation failed. Bind result: hr = 0x80070002. The system cannot find the file specified. Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll Running under executable C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe --- A detailed error log follows. === Pre-bind state information === LOG: User = MYDOMAIN\testuser LOG: DisplayName = OutlookHelper.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5e4553dc0df45306 (Fully-specified) LOG: Appbase = file:///C:/WINDOWS/system32/WindowsPowerShell/v1.0/ LOG: Initial PrivatePath = NULL LOG: Dynamic Base = NULL LOG: Cache Base = NULL LOG: AppName = powershell.exe Calling assembly : OutlookHelper.Data.Common, Version=1.0.5295.26925, Culture=neutral, PublicKeyToken=null. === LOG: This bind starts in LoadFrom load context. WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load(). LOG: Using application configuration file: C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe.Config LOG: Using host configuration file: LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config. LOG: Post-policy reference: OutlookHelper.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5e4553dc0df45306 LOG: The same bind was seen before, and was failed with hr = 0x80070002. ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).這是 Powershell 關於程序集標識的說明:
Windows PowerShell Copyright (C) 2009 Microsoft Corporation. All rights reserved. PS C:\Users\testuser> ([xml](gc $([System.AppDomain]::CurrentDomain.SetupInformation.ConfigurationFile))).configuratio n.runtime.assemblyBinding.dependentAssembly.assemblyIdentity PS C:\Users\ccontent01>當我讓 Powershell 獲取它自己的應用程序配置文件的內容時,我得到以下輸出:
Windows PowerShell Copyright (C) 2009 Microsoft Corporation. All rights reserved. PS C:\Users\testuser> gc C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe.Config <?xml version="1.0"?> <configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0.30319"/> <supportedRuntime version="v2.0.50727"/> </startup> </configuration> PS C:\Users\testuser>我試過的…
- 檢查“特定版本”是否設置為“假”-> 是這種情況。
- 刪除並重新添加了應用程序配置文件 -> 沒有修復它。
- 從 SysWOW64 文件夾中的新應用程序配置文件開始 -> 沒有修復它。
- 仔細檢查載入的文件的內容(powershell.exe.Config 和 machine.config)-> 它們是相同的。
我猜
- 程序集管理器找不到程序集重定向綁定。
有什麼解決辦法嗎?
- 為什麼 64 位實例的 Fusion 日誌沒有提及“在應用程序配置文件中找到重定向:1.0.0.0 重定向到 2.0.0.0。”之類的內容?
- 這一切的原因是什麼?
- 你能想出什麼解決辦法嗎?
不是 100% 與 32/64 位問題相關,但是如果有人對工作程序集重定向解決方案感興趣,請查看此處Powershell config assembly redirect。
您可以使用 PowerShell 程式碼進行自定義程序集重定向,例如
$FSharpCore = [reflection.assembly]::LoadFrom($PSScriptRoot + "\bin\LIBRARY\FSharp.Core.dll") $OnAssemblyResolve = [System.ResolveEventHandler] { param($sender, $e) # from:FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a # to: FSharp.Core, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a if ($e.Name -eq "FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") { return $FSharpCore } foreach($a in [System.AppDomain]::CurrentDomain.GetAssemblies()) { if ($a.FullName -eq $e.Name) { return $a } } return $null } [System.AppDomain]::CurrentDomain.add_AssemblyResolve($OnAssemblyResolve)我首先
FSharp.Core從某個地方載入正確的版本,因為 GAC 中的版本很舊(我想這也可能是你的情況)
基於@davidpodhola 非常有用的答案,我開始在我的 psm1 模組文件中添加類似的內容。如果您的較新程序集已經載入(例如通過 Import-Module),這應該可以工作:
if (!("Redirector" -as [type])) { $source = @' using System; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; public class Redirector { public readonly string[] ExcludeList; public Redirector(string[] ExcludeList = null) { this.ExcludeList = ExcludeList; this.EventHandler = new ResolveEventHandler(AssemblyResolve); } public readonly ResolveEventHandler EventHandler; protected Assembly AssemblyResolve(object sender, ResolveEventArgs resolveEventArgs) { Console.WriteLine("Attempting to resolve: " + resolveEventArgs.Name); // remove this after its verified to work foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { var pattern = "PublicKeyToken=(.*)$"; var info = assembly.GetName(); var included = ExcludeList == null || !ExcludeList.Contains(resolveEventArgs.Name.Split(',')[0], StringComparer.InvariantCultureIgnoreCase); if (included && resolveEventArgs.Name.StartsWith(info.Name, StringComparison.InvariantCultureIgnoreCase)) { if (Regex.IsMatch(info.FullName, pattern)) { var Matches = Regex.Matches(info.FullName, pattern); var publicKeyToken = Matches[0].Groups[1]; if (resolveEventArgs.Name.EndsWith("PublicKeyToken=" + publicKeyToken, StringComparison.InvariantCultureIgnoreCase)) { Console.WriteLine("Redirecting lib to: " + info.FullName); // remove this after its verified to work return assembly; } } } } return null; } } '@ $type = Add-Type -TypeDefinition $source -PassThru } #exclude all powershell related stuff, not sure this strictly necessary $redirectExcludes = @( "System.Management.Automation", "Microsoft.PowerShell.Commands.Utility", "Microsoft.PowerShell.Commands.Management", "Microsoft.PowerShell.Security", "Microsoft.WSMan.Management", "Microsoft.PowerShell.ConsoleHost", "Microsoft.Management.Infrastructure", "Microsoft.Powershell.PSReadline", "Microsoft.PowerShell.GraphicalHost" "System.Management.Automation.HostUtilities", "System.Management.Automation.resources", "Microsoft.PowerShell.Commands.Management.resources", "Microsoft.PowerShell.Commands.Utility.resources", "Microsoft.PowerShell.Security.resources", "Microsoft.WSMan.Management.resources", "Microsoft.PowerShell.ConsoleHost.resources", "Microsoft.Management.Infrastructure.resources", "Microsoft.Powershell.PSReadline.resources", "Microsoft.PowerShell.GraphicalHost.resources", "System.Management.Automation.HostUtilities.resources" ) try { $redirector = [Redirector]::new($redirectExcludes) [System.AppDomain]::CurrentDomain.add_AssemblyResolve($redirector.EventHandler) } catch { #.net core uses a different redirect method write-warning "Unable to register assembly redirect(s). Are you on ARM (.Net Core)?" }更新:Powershell 似乎有一個錯誤,在呼叫某些命令(如 Out-GridView)時,簡單地註冊程序集解析腳本塊可能會導致 StackOverflowException。我更新了程式碼以使用使用 Add-Type 編譯的版本,似乎可以解決問題。