mat*_*gen 11 .net powershell 32bit-64bit assembly-binding-redirect
我有一个Powershell CmdLet,它在32位模式下运行时运行,在64位模式下运行失败.问题是原因是什么以及如何解决.
Powershell CmdLet引用'OutlookHelper.Common.dll'.最新版本是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>
Run Code Online (Sandbox Code Playgroud)
在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.
Run Code Online (Sandbox Code Playgroud)
以下是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>
Run Code Online (Sandbox Code Playgroud)
在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).
Run Code Online (Sandbox Code Playgroud)
以下是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>
Run Code Online (Sandbox Code Playgroud)
当我让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>
Run Code Online (Sandbox Code Playgroud)
不是100%与32/64位问题相关,但是如果有人对工作程序集重定向解决方案感兴趣,请查看Powershell配置程序集重定向.
您可以使用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)
Run Code Online (Sandbox Code Playgroud)
我首先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)?"
}
Run Code Online (Sandbox Code Playgroud)
更新:Powershell似乎有一个错误,即只需注册程序集解析scriptblock就可能在调用Out-GridView等命令时导致StackOverflowException.我更新了代码以使用使用Add-Type编译的版本,似乎可以解决问题.
在64位机器上有两个配置文件:
C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe.Config
C:\Windows\syswow64\Windowspowershell\v1.0\powershell.exe.Config
Run Code Online (Sandbox Code Playgroud)
你在64位机器上编辑过它们吗?
在 64 位版本的 Windows 上。32 位进程(如 notepad++)由操作系统透明地从 C:\WINDOWS\System32 重定向到 C:\WINDOWS\SysWOW64。
您需要确保使用 64 位文本编辑器(例如内置 notepad.exe)编辑这两个文件。这将保证您不会遇到这个可能导致混乱的微妙问题。