daisy
daisy

Reputation: 23501

Loading C# DLL with powershell, [System.Type]::GetType returns null

I have a simple DotNet DLL like this

namespace ClassLibrary1
{
    public class Class1
    {
        public static void Test()
        {
           Process.Start("CMD.exe", "/C calc"); 
        }
    }
}

When I try to load this DLL with powershell

$Path      = "c:\\test\\ClassLibrary1.dll";
$Namespace = "ClassLibrary1";
$ClassName = "Class1";
$Method    = "Test";
$Arguments = $null

$Full_Path       = [System.IO.Path]::GetFullPath($Path);
$AssemblyName    = [System.Reflection.AssemblyName]::GetAssemblyName($Full_Path)
$Full_Class_Name = "$Namespace.$ClassName"
$Type_Name       = "$Full_Class_Name, $($AssemblyName.FullName)"
$Type            = [System.Type]::GetType($Type_Name)

$MethodInfo = $Type.GetMethod($Method)
$MethodInfo.Invoke($null, $Arguments)

It does not work, because [System.Type]::GetType($Type_Name) returned $null

Any ideas?

Upvotes: 2

Views: 2184

Answers (1)

mklement0
mklement0

Reputation: 437558

  • Use Add-Type -Path to load your assembly.

  • After loading, to get a reference to that assembly's [ClassLibrary1.Class1] type as a [Type] instance (to use for reflection) via a string variable, simply cast to [Type].

The following corrected and annotated version of your code demonstrates the approach:

# Compile the C# source code to assembly .\ClassLibrary1.dll
Add-Type -TypeDefinition @'
    namespace ClassLibrary1
    {
        public class Class1
        {
            public static void Test()
            {
            System.Diagnostics.Process.Start("CMD.exe", "/C calc"); 
            }
        }
    }
'@ -OutputAssembly .\ClassLibrary1.dll  


# Define the path to the assembly. Do NOT use "\\" as the path separator.
# PowerShell doesn't use "\" as the escape character.
$Path      = ".\ClassLibrary1.dll" 
$Namespace = "ClassLibrary1"
$ClassName = "Class1"
$Method    = "Test"
$Arguments = $null

# Load the assembly by its filesystem path, using the Add-Type cmdlet.
# Use of relative paths works.
Add-Type -Path $Path

$Full_Class_Name = "$Namespace.$ClassName"

# To get type [ClassLibrary1.Class1] by its full name as a string,
# simply cast to [type]
$Type            = [type] $Full_Class_Name

$MethodInfo = $Type.GetMethod($Method)
$MethodInfo.Invoke($null, $Arguments)

As for what you tried:

As PetSerAl points out, [System.Type]::GetType() can only find a given type if:

  • its assembly is already loaded
  • its assembly can be located via standard assembly resolution, as detailed here, which involves many complicated rules, the only two of which likely apply to your scenario is if you're trying to reference a built-in type from the mscorlib assembly, or an assembly located in the GAC (Global Assembly Cache).
    • By definition, only strongly-named assemblies - those signed with a private key matching the public key mentioned in the assembly's full name - can be placed in the GAC.

While you could have called [System.Reflection.Assembly]::LoadFile($Full_Path) first in order to load the assembly via its filesystem path, after which [System.Type]::GetType($Type_Name) would have succeeded, it is ultimately simpler - and more PowerShell-idiomatic - to use Add-Type -Path to load the assembly (which has the added advantage of not requiring a full (absolute) file path), and, once loaded, to use [Type] with just the type's full name (no reference to the assembly needed anymore).

Upvotes: 2

Related Questions