2014-10-30 42 views
8

来到这里的一个问题...

我有一个PowerShell命令在32位模式下运行时的工作原理,并以64位模式中失败。 问题是什么原因以及如何解决问题。PowerShell的 - 集绑定在应用程序配置文件重定向未找到

形势

PowerShell命令引用 '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> 

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”?
  • 这是什么原因?
  • 你能想出任何解决方案吗?
+0

磁盘上的dll在哪里?他们是否出现在'C:/ WINDOWS/system32/WindowsPowerShell/v1.0 /'或其他地方? – 2014-11-03 21:31:19

+0

ddls喜欢PSEvents.dll,pspluginwkr.dll,pspluginwkr-v3.dll,pwrshmsg.dll,pwrshsip.dll存在于system32和syswow64文件夹中。文件内容不尽相同。 – mathijsuitmegen 2014-11-04 09:01:51

回答

3

在64位机器上有两个配置文件:

C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe.Config 
C:\Windows\syswow64\Windowspowershell\v1.0\powershell.exe.Config 

您编辑两者的64位计算机上?

在64位版本的Windows上。操作系统将32位进程(如记事本++)从C:\ WINDOWS \ System32透明地重定向到C:\ WINDOWS \ SysWOW64。

您需要确保使用64位文本编辑器(如内建的notepad.exe)编辑这两个文件。这将保证你不会受到这个微妙的问题的困扰,这可能会导致混淆。

+0

是的,我尝试了编辑其中一个,然后操作系统更改/同步更改到另一个文件。所以我试图改变system32 - >没有工作。试图改变syswow64中的一个。试图删除这两个,然后测试2场景的位置,我将在第一个场景的system32中添加文件,然后在syswow64文件夹中添加第二个文件 - >不起作用。 – mathijsuitmegen 2014-11-04 08:56:31

+0

您可以在Powershell和Powershell(x86)中运行以下代码并告诉我每个输出: ([xml](gc $([System.AppDomain] :: CurrentDomain.SetupInformation.ConfigurationFile)))。configuration.runtime .assemblyBinding.dependentAssembly.assemblyIdentity – DanL 2014-11-04 09:13:12

+0

感谢您的评论Dan!我用你提供的信息更新了我的问题。似乎64位缺少一些东西。 – mathijsuitmegen 2014-11-04 10:58:54

8

不是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) 

我第一次从什么地方作为GAC的版本是旧的加载的FSharp.Core正确版本的自定义组件重定向(我猜这可能是你的情况太)

您还可以check the real test usage in my project

+0

谢谢。我认为在这里stackoverflow.com网站上的其他答案的链接将工作,并会避免不必要的类似垃圾邮件的复制。这里也增加了其他答案的核心。 不知道为什么反对,这是目前唯一的解决方案。 – davidpodhola 2015-10-23 19:26:24

+0

为了让我的评论更易于理解,现在有一条评论(+ downvote)现在被删除,并说:“虽然这个链接可能回答这个问题,但最好包含答案的基本部分。”评论作者可能没有注意到该链接是另一个StackOverflow文章。 – davidpodhola 2015-11-04 08:01:18

4

基于@ davidpodhola非常有帮助的答案,我开始在我的psm1模块文件中加入类似的东西。如果您的新的组件已加载(通过导入模块为例),这应该工作:

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的似乎已经在那里简单地注册的组件决心脚本块可能会导致StackOverflowException调用一些当一个bug像Out-GridView这样的命令。我更新了代码以使用似乎可以解决问题的使用Add-Type编译的版本。

+0

这很好,但是如何在退出时避免堆栈溢出?如果我离开AssemblyResolve处理程序,那么在退出时PowerShell会崩溃。下面的代码阻止了它['System.AppDomain] :: CurrentDomain.remove_AssemblyResolve($ OnAssemblyResolve)',但是这打破了封装,并且意味着程序集的用户必须知道注销事件处理程序。我试着在AppDomain中卸载并处理退出处理程序,但没有成功。 – ben 2017-03-19 18:45:45

+0

你知道我偶尔会得到这个异常,我认为它是埋在我写的所有互操作代码中的东西,因为它会使进程崩溃。不幸的是,我认为这个问题比仅仅移除解析器更深层次,因为在我的机器上,我可以通过注册一个什么也不做,并且调用out-gridview的解析器来重新编译它100%。 AssemblyResolve的文档表明,如果解析处理程序导致AppDomain.Load或Assembly.Load被调用,您可以得到一个StackOverflowException,但我不确定这样的一小段代码会如何发生: – 2017-03-29 20:51:07

+0

$ OnAssemblyResolve = \t \t [ System.ResolveEventHandler] { \t \t param($ sender,$ resolveEventArgs) Write-Host -fore Green“试图解决某事” return null; } [System.AppDomain] :: CurrentDomain.add_AssemblyResolve($ OnAssemblyResolve); #this will crash crash with a StackOverflowException try { 1..10 |出的GridView } 抓 { #这不会得到打 } – 2017-03-29 20:51:14

相关问题