5 minute read
There are 3 different approaches that can be used to define classes and enums in PowerShell.
This article will compare the pros, cons, and performance of each approach.
The 3 approaches
- PowerShell classes: Introduced in PowerShell 5.0, PowerShell has native support for classes.
- Inline C# classes: C# classes defined in a string in PowerShell and compiled and imported at runtime.
- Compiled assembly C# classes: C# classes defined in a .cs file, compiled to a .dll, and the .dll imported at runtime.
PowerShell class example
This blog post is a great overview of PowerShell classes.
Inline C# class example
When using this method, to make editing easier and still get syntax highlighting and intellisense, I recommend putting the C# code in a .cs file and importing it with:
Compiled assembly C# class example
The C# code is then compiled using Visual Studio / MSBuild / dotnet.exe to create a dll file, and the dll is imported in PowerShell with:
Performance comparison
The results of the test are below:
Class | PowerShell Classes | Inline C# Classes | Compiled Assembly C# Classes |
---|---|---|---|
Basic1 | 89ms | 764ms | 10ms |
Basic2 | 10ms | 25ms | 9ms |
Basic3 | 9ms | 36ms | 8ms |
Large1 | 13ms | 230ms | 8ms |
Large2 | 11ms | 55ms | 8ms |
Large3 | 12ms | 28ms | 8ms |
PowerShell class results
The first PowerShell class declared is a little slow to import, but subsequent declarations are much faster.
I suspect this is due to PowerShell loading some assemblies into memory that it needs to import a PowerShell class/enum.
Once those assemblies are loaded, subsequent imports are much faster.
It appears that the size of the class may have a bit of impact on the import time, but it is not significant.
Inline C# class results
Inline C# classes are very slow to import.
I suspect this is because the C# code is compiled at runtime before being loaded into memory.
The first import is especially slow.
Also, any dependencies that the class references need to be loaded into memory.
The Large class references some types not referenced by the Basic class, so I think that is why the initial Large class import is slow even after the Basic class has already been loaded.
Compiled assembly C# class results
Compiled assembly C# classes are the fastest to import every time, since the code has been pre-compiled.
Other considerations
- If creating a module with PowerShell classes, you must define them directly in the .psm1 file; they cannot be defined in another file and dot-sourced into the .psm1 file.
This prevents organizing your class code into multiple files. - If creating a module with PowerShell classes, consumers of the module must use
using module YourModule
instead ofImport-Module YourModule
to be able to reference to the class and enum types, otherwise PowerShell will give an error that it cannot find the type.
C# classes and enums, whether inline or compiled, do not have these limitations.
However, using C# code in PowerShell does have its own drawbacks:
- You are not able to step into C# code from PowerShell to debug it.
- You can not write to the Debug, Verbose, or Warning streams from C#.
Additional PowerShell class considerations
- In addition to the module limitations mentioned above, PowerShell classes were introduced in PowerShell 5.0, so we can’t use them if we want to support PowerShell 3.0 and 4.0.
Additional Inline C# class considerations
Additional Compiled assembly C# class considerations
- You must compile the C# classes into an assembly, which is an extra development step.
- The assembly must be compiled against .NET Standard 2.0 so that it can be used in both Windows PowerShell and PowerShell Core.
This means it supports C# v7.3, but not newer features.
See the list of C# versions and their features to know which C# features you can use.
My recommendation
If you are not creating a module, but instead just writing a script, I recommend using PowerShell classes.
It avoids context switching between languages and is still very fast to run.
If you are creating a module and don’t intend for consumers of the module to use the classes and enums; that is, they will only be referenced internally by your module, then using PowerShell classes may still be fine.
If you are creating a module and intend to expose your classes and enums for consumers to use, then I recommend using C# classes and enums.
If the module load time is not a concern, then inline C# classes may be fine.
If you add many inline C# classes though, it could take several seconds to load the module.
Since you are not able to debug C# classes when running PowerShell, nor write to all of the output streams, I recommend keeping your classes very simple and using them mostly as a data structure.
They should mostly just be properties with no or very few methods.
If complex operations need to be performed on the class data, create PowerShell functions that accept the class as a parameter and perform the operation.
This will allow you to step through and debug the complex code, and write to all of the output streams if needed.
Create your module in C# instead of PowerShell
Conclusion
In this article we’ve seen the pros, cons, and performance of the 3 different ways to define and import classes and enums in PowerShell.
I hope this helps you decide which approach is best for your scenario.
If you have any questions or comments, please leave them below.
I am trying to build a “type”, for the Timecode convention used in Film/Animation.
$MyTimeCode = [TimeCode]::new("08:06:04.10", 12)
and in other cases, directly with parameters belonging to the classes constructor:
$MyTimeCode = [TimeCode]::new(, 8, 6, 4, 10, 12)
#If I had constructor such as the foloowing in my class definition:
#TimeCode([String]$TimeStamp, [Int]$Hours, [Int]$Minutes, [Int]$Seconds, [Int]$Frames, [Int]$FrameRate)
`
class HelloWorld {
[String]$Hello
[String]$World
HelloWorld([String]$Hello, [String]$World) {
$This.Hello = $Hello
$This.World = $World
}
}
MethodException: Cannot find an overload for "new" and the argument count: "1".
I have been watching some lectures here and there but they are not structured at all and they quickly advance.
The official docs are usually my go to but the “About_Classes” page quickly advances to “inheriting” and “subclasses” etc with the “Rack” and “Devices” examples and its not clear to me how one begins to work with just a single class.
My goal is to familiarise myself with classes and what they can do. The Timecode is secondary.
Why Choose New Horizons for Your Microsoft Technical Training?
Microsoft Gold Learning Partner
New Horizons is a Gold Learning Partner with Microsoft. That means that our certified subject matter experts only deliver content authorized by Microsoft to best prepare you for your next Microsoft IT initiative or certification.
Custom Training Solutions
Make sure your business objectives are being met by customizing the
class to specifically address your needs. Our subject matter experts can
customize the class to specifically address the unique goals of your team.
Free Re-Takes
Most completed New Horizons courses carry our unbeatable Learning
Guarantee. This guarantee allows students to repeat most courses, if they
are the same version, FREE OF CHARGE, within six months of course completion.
Exceptions: Cisco, Citrix, VMware, Red Hat, and courses provided by affiliated
3rd party training providers.
Guaranteed to Run Schedule
Schedule your Guaranteed to Run (GTR) class with confidence.
Choose from hundreds of GTR dates across a diverse catalog of
course titles and never worry about your class cancelling at the last
minute.