Load a Custom DLL from PowerShell

One of the amazing features of PowerShell is its amazing reach.  You can interact with the file system, the registry, certificate stores, COM, WMI, XML, cmdlets, providers … the list seems to go on forever.


One important extension point is the ability to seamlessly interact with .NET DLLs. These are most commonly shipped in SDKs, and many people have made use of this.  For example:



When pre-built API DLLs don’t suit your need, you have yet another option — writing your own! If you are comfortable with any of the .NET languages, it is quite simple to compile a DLL and load it into your PowerShell session.


Take, for example, a simple math library.  It has a static Sum method, and an instance Product method:




namespace MyMathLib
{
  public class Methods
  {
    public Methods()
    {
    }


    public static int Sum(int a, int b)
    {
      return a + b;
    }

    public int Product(int a, int b)
    {
      return a * b;
    }
  }
}

Here is everything required to get that working in your PowerShell system:



[C:\temp]


PS:25 > notepad MyMathLib.cs


 


(…)


 


[C:\temp]


PS:26 > csc /target:library MyMathLib.cs


Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.42


for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727


Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.


 


 


[C:\temp]


PS:27 > [Reflection.Assembly]::LoadFile(“c:\temp\MyMathLib.dll”)


 


GAC    Version        Location


—    ——-        ——–


False  v2.0.50727     c:\temp\MyMathLib.dll


 


 


 


[C:\temp]


PS:28 > [MyMathLib.Methods]::Sum(10, 2)


12


 


[C:\temp]


PS:29 > $mathInstance = new-object MyMathLib.Methods


Suggestion: An alias for New-Object is new


 


[C:\temp]


PS:30 > $mathInstance.Product(10, 2)


20

9 Responses to “Load a Custom DLL from PowerShell”

  1. kt writes:

    Cool tip. Thanks.

  2. Jonathan writes:

    I’m struggling with a situation similar to this. I am loading two assemblies through reflection, one of which instantiates objects whose types are contained in the second assembly.

    The assemblies are SharpZipLib from ICSharpCode and SharpZipWrapper from Kellerman Software. I’m compiling and signing both assemblies. I then place them on a network share, use reflection to load both assemblies, and try to instantiate the ZipHelper class in the SharpZipWrapper assembly. I verify both assemblies are loaded with [AppDomain]::CurrentDomain.GetAssemblies().

    I get the error:

    New-Object : Exception calling ".ctor" with "0" argument(s): "Could not load file or assembly ‘ICSharpCode.SharpZipLib, Version=0.85.1.271, Culture=neutral, PublicKeyToken=1b03e6acf1164f73′ or one of its dependencies. The system cannot find the file specified."

    If I put the assemblies (or rather, just the SharpZipLib assembly) in the $PSHome directory, it finds the SharpZipLib assembly and returns the desired object. But this is not the desired deployment.

    How can I get PowerShell to find both assemblies from the network drive?

  3. Lee writes:

    Hi Jonathan;

    Code Access Security in the .NET Framework generally restricts the loading of assemblies from a network share. Can you load the SharpZipLib directly?

    Lee

  4. Jonathan writes:

    I’m not sure what you mean by directly, but I can load the SharpZipLib assembly from a network share and interact with it (create a zip file, add a file to it, etc). But I am only going to be doing basic operations with the Zip library – generally adding files and not saving path information. That’s what made the wrapper class appealing to me.

    Where I run into problems is when I also load the SharpZipWrapper assembly from a network share. I can instantiate an object from that assembly, but it cannot instantiate objects that are defined in the SharpZipLib assembly.

    I don’t yet know much about CASPOL, but I’ll take a look to see if I can make sense of it. The list groups option gives me this:

    1. All code: Nothing
    1.1. Zone – MyComputer: FullTrust
    1.1.1. StrongName – 00240000048000009400000006020000002400005253413100040
    0000100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C834C99921EB23BE
    79AD9D5DCC1DD9AD236132102900B723CF980957FC4E177108FC607774F29E8320E92EA05ECE4E82
    1C0A5EFE8F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8
    A12436518206DC093344D5AD293: FullTrust
    1.1.2. StrongName – 00000000000000000400000000000000: FullTrust
    1.2. Zone – Intranet: LocalIntranet
    1.2.1. All code: Same site Web
    1.2.2. All code: Same directory FileIO – ‘Read, PathDiscovery’
    1.3. Zone – Internet: Internet
    1.3.1. All code: Same site Web
    1.4. Zone – Untrusted: Nothing
    1.5. Zone – Trusted: Internet
    1.5.1. All code: Same site Web

    The UNC share on which these assemblies are stores is configured to be in the Intranet zone. Do you have any suggestions for the best way to configure CASPOL to allow these assemblies to execute?

    I am trying to avoid having to copy these assemblies to the local drive of each the servers I am managing.

    Your feedback is appreciated.

    Thanks.

  5. Lee writes:

    I would suggest viewing the Fusion Log (fuslogvw.exe — an internet search should provide examples.) That gives more detail why binding fails.

    However, you might just find it easier to write a script to add files to a zip archive. I have a script to do this in my upcoming book: http://www.oreilly.com/catalog/9780596528492/. You can download the examples already, although currently the zip of the examples is broken, and the script to generate zips has a bug :) I gave a new version to O’Reilly, so it should be posted soon.

    Lee

  6. Jonathan writes:

    Thanks for the info. I will look into Fusion Log and CASPOL more this weekend when I can spend a bit more time on this.

    I will definitely check out your script, too. However, the O’Reilly link to examples currently provides a 7KB ZIP file of a bunch on 0-byte files. They might want to fix that.

    The scripts I have seen up to this point have either used a 3rd party COM/ActiveX component (something that isn’t on a default OS install), used the Shell.Application COM/ActiveX component (which I’ve had trouble getting to compress a month of logs without throwing an error), and the PSCX implementation Write-Zip (which uses SharpZipLib, but currently doesn’t allow adding files to existing ZIPs). Unfortunately, none of those have met my needs.

  7. Nic writes:

    I get a similar error except all my custom assemblies are in the (current) directory. I load them as shown above but get the "make sure that the assembly containing this type is loaded.

    I can fix this by adding all my assemblies to the GAC but that solution is not desired in slightest as these assemblies are changed often as they are still under development.

    It is interesting to note that the assemblies will load and show up in [AppDomain]::CurrentDomain.GetAssemblies() but members of the custom assemblies will be "missing" as in powershell will notify me that a static member is not defined when I know it is. (this problem also fixed by adding the assembly to the GAC)

    Weird!

  8. Nic writes:

    I found the answer and probably the solution for you Jonathan

    LoadFile doesn’t quite work exactly as expected for us.

    But this does!

    [Reflection.Assembly]::LoadFrom("fullpath:\to\dll")

    This will correctly load other libraries needed in that path as well.

    Cheers!

  9. 浅谈Windows PowerShell - Rex's Blog writes:

    […] cmd丰富以及强大的PowerShell获得了很大的潜力。这里有个例子演示了如何在PowerShell里面加载和执行.net […]

Leave a Reply