Powershell - Assembly binding redirect NOT found in application configuration file

前端 未结 3 1359
情话喂你
情话喂你 2021-01-11 12:49

Got a problem here...

I have got a Powershell CmdLet that works when running in 32-bit mode and fails in 64-bit mode. Question is what the cause is and how it can

相关标签:
3条回答
  • 2021-01-11 13:29

    Based on @davidpodhola's extremely helpful answer, I started putting something like this in my psm1 module files. If your newer assemblies are already loaded (by Import-Module for instance), this should work:

    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)?"
    }
    

    Update: Powershell appears to have a bug where simply registering an assembly resolve scriptblock can cause a StackOverflowException when calling some commands like Out-GridView. I updated the code to use a version compiled with Add-Type that seems to resolve the issue.

    0 讨论(0)
  • 2021-01-11 13:48

    On a 64-bit machine there are two configuration files:

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

    Have you edited both of them on the 64-bit machine?

    On 64-bit versions of Windows. 32 bit processes (like notepad++) are transparently redirected from C:\WINDOWS\System32 to C:\WINDOWS\SysWOW64 by the OS.

    You will need to make sure you edit both files using a 64-bit text editor like the builtin notepad.exe. This will guarantee you do not suffer from this subtle issue, which can cause confusion.

    0 讨论(0)
  • 2021-01-11 13:48

    Not 100% related to 32/64-bit issue, however if someone is interested in working assembly redirect solution please have a look here Powershell config assembly redirect.

    You can do custom assembly redirect using PowerShell code like

    $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)
    

    I am first loading the correct version of FSharp.Core from somewhere as the version in the GAC is old (I guess this might be your case too)

    0 讨论(0)
提交回复
热议问题