How to load assemblies in PowerShell?

How to load assemblies in PowerShell?

LoadWithPartialName has been deprecated. The recommended solution for PowerShell V3 is to use the Add-Type cmdlet e.g.:

Add-Type -Path C:Program FilesMicrosoft SQL Server110SDKAssembliesMicrosoft.SqlServer.Smo.dll

There are multiple different versions and you may want to pick a particular version. 🙂

[System.Reflection.Assembly]::LoadWithPartialName(Microsoft.SqlServer.Smo)

How to load assemblies in PowerShell?

Most people know by now that System.Reflection.Assembly.LoadWithPartialName is deprecated, but it turns out that Add-Type -AssemblyName Microsoft.VisualBasic does not behave much better than LoadWithPartialName:

Rather than make any attempt to parse your request in the context of
your system, [Add-Type] looks at a static, internal table to translate the
partial name to a full name.

If your partial name doesnt appear in their table, your script will
fail.

If you have multiple versions of the assembly installed on your
computer, there is no intelligent algorithm to choose between them.
You are going to get whichever one appears in their table, probably
the older, outdated one.

If the versions you have installed are all newer than the obsolete one
in the table, your script will fail.

Add-Type has no intelligent parser of partial names like
.LoadWithPartialNames.

What Microsofts .Net teams says youre actually supposed to do is something like this:

Add-Type -AssemblyName Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

Or, if you know the path, something like this:

Add-Type -Path C:WINDOWSMicrosoft.NetassemblyGAC_MSILMicrosoft.VisualBasicv4.0_10.0.0.0__b03f5f7f11d50a3aMicrosoft.VisualBasic.dll

That long name given for the assembly is known as the strong name, which is both unique to the version and the assembly, and is also sometimes known as the full name.

But this leaves a couple questions unanswered:

  1. How do I determine the strong name of whats actually being loaded on my system with a given partial name?

    [System.Reflection.Assembly]::LoadWithPartialName($TypeName).Location;
    [System.Reflection.Assembly]::LoadWithPartialName($TypeName).FullName;

These should also work:

Add-Type -AssemblyName $TypeName -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
  1. If I want my script to always use a specific version of a .dll but I cant be certain of where its installed, how do I determine what the strong name is from the .dll?

    [System.Reflection.AssemblyName]::GetAssemblyName($Path).FullName;

Or:

Add-Type $Path -PassThru | Select-Object -ExpandProperty Assembly | Select-Object -ExpandProperty FullName -Unique
  1. If I know the strong name, how do I determine the .dll path?

    [Reflection.Assembly]::Load(Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a).Location;

  2. And, on a similar vein, if I know the type name of what Im using, how do I know what assembly its coming from?

    [Reflection.Assembly]::GetAssembly([Type]).Location
    [Reflection.Assembly]::GetAssembly([Type]).FullName

  3. How do I see what assemblies are available?

I suggest the GAC PowerShell module. Get-GacAssembly -Name Microsoft.SqlServer.Smo* | Select Name, Version, FullName works pretty well.

  1. How can I see the list that Add-Type uses?

This is a bit more complex. I can describe how to access it for any version of PowerShell with a .Net reflector (see the update below for PowerShell Core 6.0).

First, figure out which library Add-Type comes from:

Get-Command -Name Add-Type | Select-Object -Property DLL

Open the resulting DLL with your reflector. Ive used ILSpy for this because its FLOSS, but any C# reflector should work. Open that library, and look in Microsoft.Powershell.Commands.Utility. Under Microsoft.Powershell.Commands, there should be AddTypeCommand.

In the code listing for that, there is a private class, InitializeStrongNameDictionary(). That lists the dictionary that maps the short names to the strong names. Theres almost 750 entries in the library Ive looked at.

Update: Now that PowerShell Core 6.0 is open source. For that version, you can skip the above steps and see the code directly online in their GitHub repository. I cant guarantee that that code matches any other version of PowerShell, however.

Update 2: Powershell 7+ does not appear to have the hash table lookup any longer. Instead they use a LoadAssemblyHelper() method which the comments call the closest approximation possible to LoadWithPartialName. Basically, they do this:

loadedAssembly = Assembly.Load(new AssemblyName(assemblyName));

Now, the comments also say users can just say Add-Type -AssemblyName Forms
(instead of System.Windows.Forms). However, thats not what I see in Powershell v7.0.3 on Windows 10 2004.

# Returns an error
Add-Type -AssemblyName Forms

# Returns an error
[System.Reflection.Assembly]::Load([System.Reflection.AssemblyName]::new(Forms))

# Works fine
Add-Type -AssemblyName System.Windows.Forms

# Works fine
[System.Reflection.Assembly]::Load([System.Reflection.AssemblyName]::new(System.Windows.Forms))

So the comments appear to be a bit of a mystery.

I dont know exactly what the logic is in Assembly.Load(AssemblyName) when there is no version or public key token specified. I would expect that this has many of the same problems that LoadWithPartialName does like potentially loading the wrong version of the assembly if you have multiple installed.

Leave a Reply

Your email address will not be published.