Import PowerShell Classes from modules

This blog post is continuation of series of posts on understanding classes in PowerShell. Part 06 of series can be read at here. If you have defined PowerShell class inside a module, its not easy to import class in the current session. By default, it does not load classes. Let’s understand the details of it.

Import-Module does not import Classes

Import-Module has been a standard way of importing functions defined in a PowerShell module. It also comes with -verbose parameter so that you can see what has been imported. For understanding the case with classes, let’s define a simple PowerShell module HelloModule.psm1 as below code:

Class HelloWorld{

HelloWorld(){
Write-Host "New Object initiated of HelloWorld Class"
}

[String] sayHello(){
return "Hello World!"
}

}

function sayHello([String]$user){

Write-Output "Hello! $user"

}

Let’s import this module into script console. We’ll use the -verbose parameter to see what has been imported.

PS C:\Users\mohitgoyal\desktop> import-module .\HelloModule.psm1 -PassThru -Verbose
VERBOSE: Loading module from path 'C:\Users\mohitgoyal\desktop\HelloModule.psm1'.
VERBOSE: Exporting function 'sayHello'.
VERBOSE: Importing function 'sayHello'.

ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0 HelloModule sayHello

We don’t see any classes imported. In fact, if we try to find the PowerShell class, it will throw an error like this:

PS C:\Users\mohitgoyal\desktop> [HelloWorld]
Unable to find type [HelloWorld].
At line:1 char:1
+ [HelloWorld]
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (HelloWorld:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound

#Requires Does Not Import Classes

To understand this, let’s define a data file for our module with some attributes like below:

@{
ModuleVersion = "1.0.0.0"
Author = "Mohit Goyal"
Copyright = "mohitgoyal.co"
PowerShellVersion = "5.0"
DotNetFrameworkVersion = "4.0"
FunctionsToExport = "sayHello"
}

We’ll save it as HelloModule.psd1. Now, let’s try to import this module using #Requires:

#Requires -Module @{ModuleName="HelloWorld.psm1";RequiredVersion="1.0.0.0"}

Again, when checking for our class, we’ll get same error:

PS C:\Users\mohitgoyal\desktop> [HelloWorld]
Unable to find type [HelloWorld].
At line:1 char:1
+ [HelloWorld]
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (HelloWorld:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound

Import Classes using Using Module Statement

The using statement was introduced in the PowerShell v5. It has two uses. It imports assemblies (using namespace) and it imports modules (using module), including their classes. The assembly-importing feature is a convenience; the module-importing feature is a requirement, because there’s no other way to import classes from script modules. The Using statement has a module parameter that takes a module name string or a ModuleSpecification object.

We can import our class using below syntax:

PS C:\Users\mohitgoyal\desktop> using module C:\Users\mohitgoyal\desktop\HelloModule.psm1

And when checking for the class object:

PS C:\Users\mohitgoyal\desktop> [HelloWorld]

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False HelloWorld System.Object

After this, we can simply create a new variable from the class like explained in previous posts:

PS C:\Users\chrisgreen\desktop> $h1 = [HelloWorld]::new()
New Object initiated of HelloWorld Class
PS C:\Users\chrisgreen\desktop> $h1.sayHello()
Hello World!

You can also create a version-specific Using module statement with a ModuleSpecification object.

Note that if you had multiple modules you wanted to access the class definitions in, you would simply have multiple lines of “using module”, each line referencing the module you wanted.

using module 'C:\Users\mohitgoyal\desktop\mymodule.psm1' 
using module 'C:\Users\mohitgoyal\desktop\anothermodule.psm1'

This should cover how to use PowerShell modules with PowerShell Classes.

3 thoughts on “Import PowerShell Classes from modules

  1. What I hate about this is: you HAVE to place the using statement at the very first lines of a script. This is ok unless you want to have code to get the path right for example $currentdirectory\file.psm1 -I can’t run the code to set the $currentdirectory var

    Like

    • Use instead a script block, invoke it using ‘.’ instead of ‘&’, that will keep the types loaded in the main script
      If you do that with multiple scriptblocks, it will only keep the types loaded from the latest scriptblock; make sure you load the types from all the modules within the same scriptblock
      $MyFolder = read-host ‘Where is your module?’
      . ([ScriptBlock]::Create(@”
      using module ‘$MyFolder\mymodule.psm1’
      using module ‘$MyFolder\anothermodule.psm1’
      “@))
      [HelloWorld]

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s