You can define and use custom classes in PowerShell modules by placing the class definition inside a .psm1 file, exporting it via
Export-ModuleMember, and then importing the module in your session. This approach allows you to encapsulate complex logic and data structures within a reusable module, making your code more modular and easier to maintain across different scripts and environments without exposing internal implementation details unnecessarily.
Creating the Module Structure
To begin using classes within a PowerShell module, you must first establish the correct directory structure. A standard PowerShell module consists of a folder named after the module itself. Inside this folder, you will create a script module file with the
.psm1 extension. This file serves as the primary container for your functions, variables, and class definitions. It is crucial to understand that while you can place class definitions directly in the
.psm1 file, they are not automatically available to consumers of the module unless explicitly exported or if the module is imported in a way that exposes them.
Create a new folder on your system, for example,
C:\Modules\MyCustomClasses. Inside this folder, create a file named
MyCustomClasses.psm1. This file will hold both the class definition and any helper functions that might interact with instances of that class. The structure ensures that when you import the module, PowerShell knows exactly where to look for the definitions. You do not need a separate manifest file (
.psd1) for simple class usage, but it is good practice to include one if your module grows in complexity or requires specific versioning information.
Defining the Class
PowerShell supports object-oriented programming through classes defined using the
class keyword. Within your
.psm1 file, you can define a class just like you would in C# or Java. Let us create a simple example class called
UserAccount. This class will have properties for username and email, along with a method to validate the email format.
class UserAccount {
[string]$Username
[string]$Email
# Constructor
UserAccount([string]$user, [string]$email) {
$this.Username = $user
$this.Email = $email
}
# Method to check if email is valid
[bool]IsValid() {
return $this.Email -match "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$"
}
# Method to get a summary string
[string]GetSummary() {
return "User: $($this.Username), Email: $($this.Email)"
}
}
By defining the class inside the module file, you encapsulate the logic. Note that the constructor name must match the class name exactly. Properties are declared with their type in square brackets before the variable name. Methods follow similar syntax to functions but operate on the instance of the class via the
$this automatic variable. This separation keeps your code clean and organized, allowing you to manage state and behavior together.
Exporting the Class
Simply defining the class is not enough; you must make it accessible outside the module scope. In PowerShell, classes are treated similarly to other members regarding visibility. To export the
UserAccount class, add the following line at the end of your
.psm1 file:
Export-ModuleMember -Class UserAccount
This command tells PowerShell that the
UserAccount class should be visible to anyone who imports this module. Without this step, the class remains private to the module's internal scope, and attempts to instantiate it from an external script will fail. If you have multiple classes, you can list them all in a single
Export-ModuleMember call or use wildcards if appropriate, though explicit listing is safer for clarity.
Using the Module Class
Once the module is created and saved, you can test it in a new PowerShell session. First, ensure your execution policy allows running scripts if necessary, though module loading often bypasses strict restrictions depending on your configuration. Import the module using the
Import-Module cmdlet, specifying the path to the module folder.
Import-Module -Name 'C:\Modules\MyCustomClasses'
After importing, you can instantiate the class and use its methods. For example:
$account = New-Object UserAccount -ArgumentList 'johndoe', '[email protected]'
$account.IsValid()
$account.GetSummary()
The output will confirm whether the email is valid and provide the formatted summary string. This demonstrates how seamlessly you can integrate custom types into your workflow. You can also pipe objects or use them in arrays, leveraging the full power of PowerShell's object pipeline. For further reading on managing PowerShell environments, you might find
Running PowerShell Commands with Spaces using WSL helpful for context on cross-platform scripting nuances.
Best Practices and Maintenance
When working with classes in modules, consider organizing your code into logical sections. Keep related classes together and avoid creating overly large modules that become difficult to navigate. Use comments to document the purpose of each class and its methods, which aids future maintenance. Additionally, be mindful of performance; while classes are powerful, instantiating them frequently in tight loops can impact performance compared to simpler hash tables or PSCustomObjects for lightweight data transfer.
If you encounter issues with class visibility, verify that the
Export-ModuleMember command is present and correctly spelled. Also, ensure that the module path is included in your
$PSModulePath environment variable if you want to load the module by name alone rather than by full path. This setup simplifies calling your classes across different projects. For more advanced scenarios involving remote sessions or complex configurations, understanding how PowerShell interacts with other systems is vital, such as seen in
WSL2: Administrator Accounts and PowerShell Installation.
Frequently Asked Questions
Can I define multiple classes in one module file?
Yes, you can define as many classes as needed within a single
.psm1 file. Just ensure that each class you wish to expose is listed in the
Export-ModuleMember command at the end of the file.
What happens if I forget to export the class?
If you do not export the class, it remains scoped to the module. Any attempt to create an instance of that class from an external script will result in an error stating that the type cannot be found or is not recognized.
Do classes support inheritance in PowerShell?
Yes, PowerShell classes support inheritance. You can derive a new class from an existing one by using the
: ParentClassName syntax after the class name, allowing you to reuse and extend functionality effectively.
How do I handle errors within a class method?
You can use standard try-catch blocks within your class methods just as you would in regular functions. This allows for robust error handling and ensures that exceptions are properly propagated to the caller.
Is there a performance difference between classes and PSCustomObjects?
Classes generally offer better performance and stricter typing compared to PSCustomObjects, especially for large datasets or frequent instantiation. However, PSCustomObjects are more flexible for ad-hoc data structures where schema consistency is less critical.