Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Referencing assemblies inside PS classes causes "Unable to find type" error

I am using PowerShell 5.1 on a Windows 7 box and am trying to reference a type in a .NET assembly from inside a PowerShell class, and am getting an "Unable to find type" error.

My "main" program is FooProg.ps1, where I am creating a new instance of the FooMod class

#Requires -Version 5.1
using module .\FooMod\FooMod.psm1
[FooMod]::new() | out-null

The FooMod class is in a PowerShell module (FooMod.psm1) in the FooMod sub-folder

#Requires -Version 5.1

using assembly .\Foo.dll
using namespace Foo

class FooMod {
   FooMod() {
      Write-Host "Start - Assembly access"
      [Bar] $bar = [Bar]::new()
      Write-Host $bar.Name
      Write-Host $bar.Greeting()
      Write-Host "Finish - Assembly access"
   }
}

My Foo.dll is built from the following Bar.cs, and is in the FooMod sub-folder along with the Module file (FooMod.psm1) and the Module Manifest file (FooMod.psd1)

namespace Foo {
   public class Bar {
      public string Name;

      public Bar(string name) => this.Name = name;

      public Bar() : this("Bar") {
      }

      public string Greeting() {
         return System.String.Format("Hello! My name is {0}", Name);
      }
   }
}

I also have a Module Manifest in the FooMod sub-folder called FooMod.psd1 which contains these relevant entries

RootModule = 'FooMod.psm1'
RequiredAssemblies = 'Foo.dll'

Is there anything else I am missing? Using the assembly outside the class works fine, instantiating a PowerShell class (without referencing an assembly / external type) works fine - but combining PowerShell classes and assembly types is a no-go!

like image 204
hsbatra Avatar asked Oct 20 '25 12:10

hsbatra


1 Answers

Figured it out! It turns out that in the main script, FooProg.ps1, the using statement needs to refer to the Module Manifest and NOT the Module Script.

So instead of using

#Requires -Version 5.1
using module .\FooMod\FooMod.psm1
[FooMod]::new() | out-null

I changed it to

#Requires -Version 5.1
using module .\FooMod\FooManifest.psd1
[FooModule]::new() | out-null

As a result, I also renamed my Module Manifest file from .\FooMod\FooMod.psd1 to .\FooMod\FooManifest.psd1

Also, in the Module Manifest file I changed the entry RootModule = 'FooMod.psm1' to RootModule = 'FooModule.psm1'. This is not a required change, but aids in understanding the structure of the different files.

This obviously led to renaming the module script from FooMod.psm1 to FooModule.psm1 and also to changing the class name within the module script from FooMod to FooModule. Again not a required change, but it is consistent with naming classes the same as the filename in which they are contained.

The whole exercise leads me to believe that the Module Manifest file which is named in the main script needs to be processed first so that the assemblies named in RequiredAssemblies are loaded before the module named in the RootModule is parsed. This makes the types in the external .NET assembly to be available when the module is parsed and prevents the "Unable to find type" error.

Now armed with the new FooModule.psm1 file

#Requires -Version 5.1

using assembly .\Foo.dll
using namespace Foo

class FooModule {
   FooModule() {
      Write-Host "Start - Assembly access"
      Write-Host

      [Bar] $bar1 = [Bar]::new("Romeo")

      Write-Host $bar1.Name
      Write-Host $bar1.Greeting()

      Write-Host

      [Bar] $bar2 = [Bar]::new("Juliet")

      Write-Host $bar2.Name
      Write-Host $bar2.Greeting()

      Write-Host
      Write-Host "Finish - Assembly access"
   }
}

the output I get is as follows

Start - Assembly access

Romeo
Hello! My name is Romeo

Juliet
Hello! My name is Juliet

Finish - Assembly access

The key is to use a Module Manifest, with the RequiredAssemblies key properly set and to reference the Module Manifest rather than the Module Script itself in your main script.

like image 195
hsbatra Avatar answered Oct 23 '25 03:10

hsbatra



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!