Loading
0x110Lesson 18 of 24

Classes and enums

Name fixed sets of values with enums and flags, and model the sanctuary with classes, constructors, methods and inheritance.

32 min 7-question quiz 2 code exercises
By the end of this lesson you can
  • 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.

enums.ps1
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' }
Output
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().

flags.ps1
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'
Output
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(...).

dragon-class.ps1
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' }
Output
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.
  • hidden keeps a property out of Get-Member and table output - handy for internals.
  • static members 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.

inheritance.ps1
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]
Output
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].

0 of 8 sortedScore 0/0
  • “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 enum names a fixed set of values; [Flags()] enums combine them with -bor and test with .HasFlag().

  • Classes have typed properties, constructors and methods; $this is the current object and methods must return their value.

  • static members belong to the class; hidden hides internals; class B : A inherits and can override methods.

  • Use using module to 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.

Exercise 1

The egg incubator

+25 XP

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 to Warmth.
  • [bool] IsHatched() is true once Warmth reaches HatchAt.
  • [string] ToString() returns Firedrake egg: 33/30 - hatched! or Wisp egg: 5/12 - still warming.
  • A static Hatched counter goes up once for every egg that hatches.

Print each egg, then hatched 2 of 3.

  • Three eggs
  • Cold night
script.ps1
Loading editor…

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.

Exercise 2

Keeper permissions

+25 XP

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 print Ada: 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 then can feed: <keepers>, in input order, or nobody.
  • Three keepers
  • A made-up chore
script.ps1
Loading editor…

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…

Did you like the lesson? 😆👍
Consider a donation to support our work: