PowerShell classes in a module

I am starting to use classes to allow for strong typing and consistency in object parameter types.
I’m adding them to an existing PowerShell module containing multiple functions and psm1 files. Does anyone have a good example of how to export classes in the module so they can be more easily used in the PS session when the module is imported (i.e. for IntelliSense) or across functions in different psm1 files?

Others with more experience can probably chime in but my understanding is that Import-Module does not make the class definitions available in the session.
This blog post has some good examples of how Using module vs Import-Module pertains to class use.
It’s going to feel like double the work but the approach I adopted was mirrors what is discussed in that blog post:
image
Since not all classes necessarily need to be exposed to the user I’ll write a public function used to instantiate the object.

I haven’t done this a lot but here’s an example:
Class definition

Class CipherObject {
    [String]  $Encryption
    [String]  $CipherText
    hidden[String]  $DPAPIIdentity
    CipherObject ([String]$Encryption, [String]$CipherText) {
        $this.Encryption = $Encryption
        $this.CipherText = $CipherText
        $this.DPAPIIdentity = $null
    }
}

function definition

Function New-CipherObject {
    [cmdletbinding()]
    Param (
        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateSet("DPAPI","AES")]
        [String]$Encryption,
        [Parameter(Mandatory = $true, Position = 1)]
        [String]$CipherText
    )
 
    [CipherObject]::New($Encryption,$CipherText)
    
}

That blog post is very enlightening. So I need a function for each class I want to use, and that is used to create objects across the module (and in scripts that use the module).

But the thing I’m running into is that other functions in my module don’t recognize the class. For example…

one.psm1:
Function get-object {
    create an object of the class 'blah'
    populates the properties
}
class blah {}

two.psm1
Function use-object {param([blah]$inputobject)}

get-object | use-object -> InvalidOperation: Unable to find type [blah]

This is what I feel like should work but doesn’t. The scope of the class definition seems to be confined to the psm1 file and not the entire module.

i didn’t know you could have multiple psm1 files in a module. I thought it was a psm1, and/or a psd1 file.
I believe the class definitions are contained within the scope of a single psm1, but typically that means it’s the scope of a module.

You sure can - you have to list the files in the module manifest under NestedModules, but we have dozens of psm1 files in our team module.

Bummer then for shared class defnitions :frowning:

it sounds hacky, but I wonder if in your module directory you could store all your class definition files in a folder called “Classes” and then in each psm1 you’d add a loop where you do a Get-ChlidItem on that directory, and for each class definition you dot source it?
Then it’s technically getting sourced in each psm1 file, but you only have to maintain it in one place.

It does sound kind of hacky, but worth a try.

It just seems odd that PS would have classes, but no best-practice way to implement them across a PS module.

I am sure you both did the google thing, but just in case, will this solve your problem? Not a user of classes myself but always willing to learn.

1 Like

I think I got this to work. I used code from here in my root module:

Then I put my class definitions in a ps1 file in my module folder structure and dot sourced it in the root psm1 file.

For pester testing, I had to also dot source the relevant class files in each function’s psm1 and Tests.ps1 file. So far it seems to do the trick.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.