Search code examples
c#powershelldll.net-standardpowershell-5.0

How to load a custom DLL into PowerShell


I've been trying to load a custom DLL into PowerShell with no luck.

My DLL's are being created based on this repository. My end goal is to be able to load Monster.dll but I figured I'd start with Dice.dll (because it's a static class with practically no dependencies).

What I've tried

In PowerShell:

cd C:\some\repo\dnd\dice\bin\Debug\netstandard2.1

$path = (pwd).Path

$path += "\Dice.dll"

[Reflection.Assembly]::LoadFile("$path")

GAC    Version        Location
---    -------        --------
False  v4.0.30319     C:\some\repo\dnd\dice\bin\Debug\netstandard2.1\Dice.dll

And then I try to call the simple Roll Dice function (which looks like this)

[Dice.Dice]::Roll(20, 1)

And it returns this error:

Unable to find type [Dice.Dice].
At line:1 char:1
+ [Dice.Dice]::Roll(20, 1)
+ ~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (Dice.Dice:TypeName) [], RuntimeException
    + FullyQualifiedErrorId : TypeNotFound

The same thing happens if I try to call:

[Dice]::Roll(20, 1)

What am I doing wrong?

EDIT

Someone suggested that I try:

Add-Type -Path "$path"

and it returns this error:

Add-Type : Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
At line:1 char:1
+ Add-Type -Path "$path"
+ ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Add-Type], ReflectionTypeLoadException
    + FullyQualifiedErrorId : System.Reflection.ReflectionTypeLoadException,Microsoft.PowerShell.Commands.AddTypeCommand

The real "LoadExeption" is

Could not load file or assembly 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its
dependencies. The system cannot find the file specified.

Another suggestion from the comments was to run:

[appdomain]::currentdomain.getassemblies()

I was able to find this data from that command

@{CodeBase=file:///C:/some/Repo/DnD/dice/bin/Debug/netstandard2.1/Dice.dll; FullName=Dice,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null; EntryPoint=; DefinedTypes=; Evidence=System.Security.Policy.Evidence;
PermissionSet=<PermissionSet class="System.Security.PermissionSet"
version="1"
Unrestricted="true"/>
; SecurityRuleSet=Level2; ManifestModule=Dice.dll; ReflectionOnly=False;
Location=C:\some\Repo\DnD\dice\bin\Debug\netstandard2.1\Dice.dll; ImageRuntimeVersion=v4.0.30319;
GlobalAssemblyCache=False; HostContext=0; IsDynamic=False;
EscapedCodeBase=file:///C:/some/Repo/DnD/dice/bin/Debug/netstandard2.1/Dice.dll; ExportedTypes=;
IsFullyTrusted=True; CustomAttributes=; Modules=System.Reflection.RuntimeModule[]}

I also ran this command:

try {
    ([appdomain]::currentdomain.GetAssemblies() | where Location -match 'dice').gettypes()
} catch {
    $_ | select *
}
PSMessageDetails      :
Exception             : System.Management.Automation.MethodInvocationException: Exception calling "GetTypes" with "0" argument(s):
                        "Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more
                        information." ---> System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested
                        types. Retrieve the LoaderExceptions property for more information.
                           at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
                           at System.Reflection.Assembly.GetTypes()
                           at CallSite.Target(Closure , CallSite , Object )
                           --- End of inner exception stack trace ---
                           at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext,
                        Exception exception)
                           at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
                           at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
                           at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
TargetObject          :
CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

Solution

  • The key info is in the "LoadException" message:

    Could not load file or assembly 'netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its
    dependencies. The system cannot find the file specified.
    

    It says that the assembly netstandard, Version=2.1.0.0 can't be found. That prevents PowerShell from loading Dice, because Dice is compiled against .NET Standard 2.1.

    I'm not sure about the nuances of .NET Standard 2.1 support through PowerShell. You might need a newer version of PowerShell, or you might just need to install the right .NET SDK/runtime components.

    If you aren't tied to .NET Standard 2.1, try re-configuring the C# project to target .NET Standard 2.0 or .NET Framework 4.7 (or lower).