I am creating a PowerShell module that defines a class. For example:
class MyClass
{
[string] $Name
}
If I put the class definition directly in the psm1 file then everything works fine. However, if I move the class to its own file and include it using using module .PathToMyClass.ps1
then Pester fails in GitHub Actions with the error message:
Unable to find type [MyClass]
I have created this small sample repo that reproduces the problem.
The weird thing is that if I start a new PowerShell session on my local machine and run Invoke-Pester
it all works as expected; it seems to only fail in GitHub Actions.
Below are the 2 modules’ files and their Pester tests.
First, the module that defines the class directly in the psm1 file and everything works fine everywhere:
ModuleWithClassInPsm1.psm1:
class MyClassInPsm1
{
[string] $Name
}
function Get-MyClassInPsm1
{
return [MyClassInPsm1]::new()
}
Export-ModuleMember -Function Get-MyClassInPsm1
ModuleWithClassInPsm1.Tests.ps1:
using module .ModuleWithClassInPsm1.psm1
Describe 'Module' {
It 'Should return a new class instance without error' {
$instance = Get-MyClassInPsm1
$instance | Should -Not -Be $null
}
}
And here is the other module that defines the class in a separate file:
ClassesMyClassInSeparateFile.ps1:
class MyClassInSeparateFile
{
[string] $Name
}
ModuleWithClassInSeparateFile.psm1:
using module .ClassesMyClassInSeparateFile.ps1
function Get-MyClassInSeparateFile
{
return [MyClassInSeparateFile]::new()
}
Export-ModuleMember -Function Get-MyClassInSeparateFile
ModuleWithClassInSeparateFile.Tests.ps1:
using module .ModuleWithClassInSeparateFile.psm1
Describe 'Module' {
It 'Should return a new class instance without error' {
$instance = Get-MyClassInSeparateFile
$instance | Should -Not -Be $null
}
}
I have verified that both my local machine and GitHub Actions are using Pester v5.5.0. I am using PowerShell v7.3.6 on my local Windows machine, while GitHub Actions is using PowerShell v7.2.13 on both Ubuntu and Windows. You can view the failing GitHub Actions here.
The PowerShell class docs and using docs state:
The using module statement imports classes from the root module (ModuleToProcess) of a script module or binary module. It doesn’t consistently import classes defined in nested modules or classes defined in scripts that are dot-sourced into the module. Classes that you want to be available to users outside of the module should be defined in the root module.
I guess in that statement "module" means just the psm1 file itself, and not the other things/files brought into the module? It is strange thought that everything works fine locally (in a fresh PowerShell session), but not in the GitHub Actions. Maybe it’s just a bug with GitHub Actions?
I plan on defining several classes in my module, and am following the convention of putting each function in its own file within a Public
or Private
directory (shown here and here, so I’d like to also put each class in its own file instead of stuffing them all in the psm1 file.
I’m open to any suggestions. Thanks in advance!
2
Answers
MadBoy's answer of using dot-sourcing and
Import-Module
will work in some scenarios, but it does not give the full picture. Using the sample repo I created, I setup various tests and found the following.Using PowerShell classes
The only way to be able to reference the class type by name outside of the module (e.g.
[MyClass]::new()
) is:using module
.If you use dot-sourcing or
Import-Module
, everything within the module itself can reference the class name fine, but if something outside of the module references the class name it will get theUnable to find type
error.Using C# classes
Everything just works when using C# classes. You can define them in separate files and dot-source them into the .psm1 file, and they will be fully available within the module and to consumers of the module whether they use
Import-Module
orusing module
.This is an example of what MyClass would look like as a C# class in PowerShell:
For more details, check out this blog post.
I own Mailozaurr module which uses Class in a separate file
As part of PSM1 file I use dot sourcing:
As part of the file with Class I just have classes, and I use Import-Module instead of using and it works just fine.
You can take a look what I do, but that’s about it and everything works fine. Your problem may be with "using" rather then class itself. I’ve seen people using "using" but i’ve not done that for the last 3+ years.