Powershell - Assembly binding redirect NOT found in application configuration file
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)
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.
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.