Powershell - assembly binding redirection NOT found in application configuration file

Here's the problem ...

I have a CmdLet Powershell that works when working in 32-bit mode and does not work in 64-bit mode. The question is what is the cause and how can it be fixed.

Situation

Powershell CmdLet refers to "OutlookHelper.Common.dll". The newest version 2.0.0.0 CmdLet also uses logging and links "Logging.dll".
Logging.dll also refers to "OutlookHelper.Common.dll", it has only been compiled against version 1.0.0.0.

How I did it, it partially works

Using assembly binding redirection in a Powershell application configuration file:

<?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> 

32-bit Powershell versions work fine

When working on a 64-bit machine using "Windows Powershell (x86)", it works. The assembly manager detects assembly binding redirection:

 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. 

Here's what Powershell says about build identity:

 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> 

This is where the problem begins ...

When working on a 64-bit machine using "Windows Powershell" it does not work. The assembly manager does NOT find the assembly binding redirection:

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

Here's what Powershell says about build identity:

 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> 

When I let Powershell get the contents of my own application configuration file, I get the following output:

 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> 

What have I tried ...

  • Check if the "Specific Version" is set to "false" -> it is.
  • The deleted and re-added application configuration file → did not fix it.
  • I started working with a new application configuration file in the SysWOW64 folder → did not fix it.
  • Double check the contents of downloaded files (powershell.exe.Config and machine.config) → they are the same.

My suggestion

  • The assembly manager cannot find the assembly redirection binding.

Any solutions?

  • Why doesn't the Fusion log for a 64-bit instance mention something like "Redirection found in application configuration file: 1.0.0.0 redirected to 2.0.0.0."?
  • What could be causing this?
  • Can you think of any solutions?
+8
powershell 32bit-64bit assembly-binding-redirect
source share
3 answers

There are two configuration files on a 64-bit machine:

 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 a 64-bit machine?

On 64-bit versions of Windows. 32-bit processes (for example, Notepad ++) are transparently redirected from C: \ WINDOWS \ System32 to C: \ WINDOWS \ SysWOW64 by the operating system.

You will need to make sure that you edit both files using a 64-bit text editor, for example the built-in notepad.exe. This ensures that you will not suffer from this subtle problem, which can cause confusion.

+3
source share

Not 100% related to the 32/64-bit problem, however, if anyone is interested in a working solution to redirect the assembly, please see the Powershell redirect configuration assembly here.

You can perform custom assembly redirection 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 first download the correct version of FSharp.Core from somewhere, since the version in the GAC is deprecated (I think this could be your case too)

You can also check the actual use of the test in my project .

+8
source share

Based on @davidpodhola's extremely useful answer, I started to put something like this in my psm1 module files. If your new assemblies are already loaded (e.g. Import module), 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 seems to have a bug where just registering a scriptblock build solution can throw a StackOverflowException when calling some commands, such as Out-GridView. I updated the code to use the version compiled using Add-Type, which seems to fix the problem.

+4
source share

All Articles