Classes and enums
Name fixed sets of values with enums and flags, and model the sanctuary with classes, constructors, methods and inheritance.
- Define enums, including [Flags] enums that combine values
- Write classes with typed properties, constructors, methods and static members
- Inherit from a base class, override methods, and choose between a class and a [pscustomobject]
[pscustomobject] is perfect for data: a report row, a parsed CSV line. But some things have rules and behavior - an egg that hatches once it’s warm enough, a mood that can only be one of four words. Since version 5, PowerShell lets you define your own types with enum and class.
Start with an enum: a named list of allowed values. Typos fail immediately instead of quietly flowing through your script, and tab completion knows the names.
1enum Mood {
2 Sleepy
3 Playful
4 Grumpy
5 Furious = 10
6}
7$mood = [Mood]::Grumpy
8$mood
9[int]$mood
10[Mood]'playful'
11[Mood]10
12[enum]::GetNames([Mood]) -join ', '
13$mood -eq 'Grumpy'
14try { [Mood]'hangry' } catch { 'hangry is not a Mood' }Grumpy 2 Playful Furious Sleepy, Playful, Grumpy, Furious True hangry is not a Mood
Each name stands for a number, counting from 0 unless you say otherwise. Add [Flags()] and give each value its own bit (1, 2, 4, 8...) and an enum can hold several values at once - perfect for diets, permissions or days of the week. Combine with -bor, test with .HasFlag().
1[Flags()] enum Diet {
2 None = 0
3 Meat = 1
4 Fish = 2
5 Fruit = 4
6 Insects = 8
7}
8$glim = [Diet]::Insects -bor [Diet]::Fruit
9$glim
10$glim.HasFlag([Diet]::Fruit)
11$glim.HasFlag([Diet]::Meat)
12[Diet]'Fish, Meat'
13[int][Diet]'Meat, Fish'Fruit, Insects True False Meat, Fish 3
Classes
A class is a blueprint for objects: typed properties, constructors that set them up, and methods that act on them. Inside a method, $this is the object itself.
Methods are stricter than functions: they declare a return type ([string], [bool], or [void] for nothing), and only what you return comes back - stray output is discarded rather than leaking out. Create objects with [Dragon]::new(...).
1enum Mood {
2 Sleepy
3 Playful
4 Grumpy
5}
6class Dragon {
7 [string]$Name
8 [int]$Wingspan
9 [Mood]$Mood = 'Sleepy'
10
11 Dragon([string]$name, [int]$wingspan) {
12 $this.Name = $name
13 $this.Wingspan = $wingspan
14 }
15
16 [string] Roar() {
17 return 'R' + ('A' * $this.Wingspan) + 'WR!'
18 }
19
20 [string] ToString() {
21 return "$($this.Name) the $($this.Mood.ToString().ToLower()) dragon"
22 }
23}
24$ember = [Dragon]::new('Ember', 5)
25$ember.Roar()
26$ember.Mood = 'Grumpy'
27"$ember"
28$glim = [Dragon]::new('Glim', 1)
29$glim.Roar()
30try { $glim.Mood = 'hangry' } catch { 'Glim cannot be hangry - not a Mood' }RAAAAAWR! Ember the grumpy dragon RAWR! Glim cannot be hangry - not a Mood
A few more tools:
- Overloaded constructors: define several with different parameters. If you define none, you get an empty one for free - and then
[Dragon]@{ Name = 'Pebble'; Wingspan = 3 }builds an object straight from a hashtable. hiddenkeeps a property out ofGet-Memberand table output - handy for internals.staticmembers belong to the class itself, not to each object:[Dragon]::Count,[math]::Pi.- Validation attributes work on properties:
[ValidateRange(0, 40)][int]$Wingspan.
Inheritance
class Dragon : Creature makes a Dragon a kind of Creature: it gets every property and method, and can override a method by defining it again. Call the parent’s constructor with : base(...). Methods are virtual, so code in the base class that calls $this.Speak() gets each subclass’s version.
1class Creature {
2 static [int]$Count = 0
3 [string]$Name
4 Creature([string]$name) {
5 $this.Name = $name
6 [Creature]::Count++
7 }
8 [string] Speak() { return '...' }
9 [string] Introduce() { return "$($this.Name) says $($this.Speak())" }
10}
11class Dragon : Creature {
12 Dragon([string]$name) : base($name) { }
13 [string] Speak() { return 'RAAAWR' }
14}
15class Wisp : Creature {
16 Wisp([string]$name) : base($name) { }
17 [string] Speak() { return '*twinkle*' }
18}
19$residents = [Dragon]::new('Ember'), [Wisp]::new('Glim'), [Creature]::new('Mystery egg')
20$residents | ForEach-Object { $_.Introduce() }
21"residents: $([Creature]::Count)"
22$residents[0] -is [Creature]Ember says RAAAWR Glim says *twinkle* Mystery egg says ... residents: 3 True
Try it
Object, class or enum?
Pick the lightest tool that does the job for each need. Rules and behavior call for a class; a fixed list of names calls for an enum; plain data is happiest as a [pscustomobject].
“A report row: a dragon’s name and total kilograms”
“The three enclosure sizes, so a typo fails fast”
“An Egg that can Warm() itself and knows when it has hatched”
“A CSV row you’ll export again as JSON”
“A Sensor type with Thermometer and Hygrometer subtypes”
“Keeper permissions that combine: Feed, Clean, Medicate”
“Quick output from a function for Format-Table”
“A Rota that refuses to give one keeper two shifts at once”
Key takeaways
An
enumnames a fixed set of values;[Flags()]enums combine them with-borand test with.HasFlag().Classes have typed properties, constructors and methods;
$thisis the current object and methods mustreturntheir value.staticmembers belong to the class;hiddenhides internals;class B : Ainherits and can override methods.Use
using moduleto import classes, and keep reaching for[pscustomobject]when you only need data.
Lesson quiz
7 questions · pass with 5 correct · up to 50 XP
Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.
Practice: write PowerShell scripts
Write a script in the editor and run it for real against sample input, which is piped into your script as $input. Scripts run on PowerShell 6.2 through Try It Online (tio.run), a free public service, so these exercises avoid PowerShell 7-only syntax; your script and test input are sent there.
The egg incubator
Each input line is Species HatchAt warmings...: an egg’s species, the warmth it needs to hatch, and the degrees it gets warmed by, one session at a time. Finish the Egg class:
[void] Warm([int]$degrees)adds toWarmth.[bool] IsHatched()is true onceWarmthreachesHatchAt.[string] ToString()returnsFiredrake egg: 33/30 - hatched!orWisp egg: 5/12 - still warming.- A static
Hatchedcounter goes up once for every egg that hatches.
Print each egg, then hatched 2 of 3.
- Three eggs
- Cold night
Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.
Keeper permissions
Define a [Flags()] enum Chore with Feed = 1, Clean = 2 and Medicate = 4. Each input line is a keeper and a comma-separated list of chores, like Ada Feed,Clean.
- Convert the list to a
[Chore]and printAda: Feed, Clean (3)- the enum, then its number. - If the list has a chore that doesn’t exist, the cast throws: catch it and print
Pip: unknown chore in Feed,Dance(and leave Pip out of what follows). - Finish with
can medicate: <keepers>and thencan feed: <keepers>, in input order, ornobody.
- Three keepers
- A made-up chore
Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.
Questions about this lesson
Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.
Loading posts…