PowerShell Classes: Object-Oriented Programming Basics

PowerShell Classes: Object-Oriented Programming Basics

PowerShell Tips Editor 3 min read
PowerShell Classes: Object-Oriented Programming Basics

PowerShell 5 introduced native class definitions, bringing object-oriented programming patterns to scripting without leaving the language. PowerShell classes let you define reusable data types with typed properties, constructors, and methods — far more structured than [PSCustomObject] and more natural than wrapping everything in C#. This post covers everything from a minimal class definition to inheritance and module integration.

Quick Answer / TL;DR

Define a class with the class keyword, add properties with [type]$Name, add a constructor with a method named the same as the class, and instantiate with [ClassName]::new() or New-Object ClassName.

Define a Class with Properties

A class definition lives in a script or module file. Properties are declared inside the class body with an optional type annotation. If you omit the type, the property accepts any value. PowerShell classes are reference types, so assigning a class instance to multiple variables gives you the same object, not a copy.

class Server {
    [string]$Name
    [string]$IPAddress
    [string]$Environment = 'Production'  # default value
    [bool]$IsOnline

    # Parameterless constructor is implied if you don't define one
}

# Instantiate the class
$srv = [Server]::new()
$srv.Name      = 'web01'
$srv.IPAddress = '10.0.1.20'
$srv.IsOnline  = $true

Write-Host "$($srv.Name) [$($srv.Environment)] - $($srv.IPAddress)"

Add a Constructor

A constructor is a method with the same name as the class. It runs automatically when you instantiate the class and allows you to set initial property values from arguments. PowerShell supports multiple constructors with different parameter signatures (overloads).

class Server {
    [string]$Name
    [string]$IPAddress
    [string]$Environment

    # Constructor with required fields
    Server([string]$name, [string]$ip, [string]$env) {
        $this.Name        = $name
        $this.IPAddress   = $ip
        $this.Environment = $env
    }

    # Overload with default environment
    Server([string]$name, [string]$ip) {
        $this.Name        = $name
        $this.IPAddress   = $ip
        $this.Environment = 'Production'
    }
}

$web01 = [Server]::new('web01', '10.0.1.20', 'Staging')
$web02 = [Server]::new('web02', '10.0.1.21')   # uses Production default

Define Methods

Methods are functions defined inside the class body. They use $this to access instance properties. Specify a return type before the method name — use [void] if the method returns nothing. Methods can call other methods on $this and call external PowerShell cmdlets.

class Server {
    [string]$Name
    [string]$IPAddress

    Server([string]$name, [string]$ip) {
        $this.Name      = $name
        $this.IPAddress = $ip
    }

    [bool] IsReachable() {
        return Test-Connection -ComputerName $this.IPAddress -Count 1 -Quiet
    }

    [string] GetSummary() {
        return "$($this.Name) ($($this.IPAddress))"
    }

    [void] PrintStatus() {
        $status = if ($this.IsReachable()) { 'ONLINE' } else { 'OFFLINE' }
        Write-Host "$($this.GetSummary()) — $status"
    }
}

$srv = [Server]::new('dc01', '10.0.0.1')
$srv.PrintStatus()

Class Inheritance

PowerShell uses colon notation for inheritance — class Child : Parent. The child class inherits all properties and methods from the parent. Override a method by redefining it in the child class. Call the parent constructor with ([ParentClass]$this).Constructor() syntax is not supported — instead, PowerShell automatically calls the matching parent constructor based on the child’s constructor arguments.

class ComputerSystem {
    [string]$Name
    [string]$OS

    ComputerSystem([string]$name, [string]$os) {
        $this.Name = $name
        $this.OS   = $os
    }

    [string] GetInfo() {
        return "$($this.Name) running $($this.OS)"
    }
}

class WindowsServer : ComputerSystem {
    [string]$Role

    WindowsServer([string]$name, [string]$role) : base($name, 'Windows Server 2022') {
        $this.Role = $role
    }

    [string] GetInfo() {
        return "$($this.Name) [$($this.Role)] — $($this.OS)"
    }
}

$dc = [WindowsServer]::new('DC01', 'Domain Controller')
$dc.GetInfo()

Static Properties and Methods

Static members belong to the class itself, not to instances. Access them with [ClassName]::Member. Use static properties for counters, configuration values, or factory methods that don’t need an instance. Mark a member static with the static keyword.

class Server {
    static [int]$Count = 0
    [string]$Name

    Server([string]$name) {
        $this.Name = $name
        [Server]::Count++
    }

    static [string] GetDefaultEnvironment() {
        return 'Production'
    }
}

$s1 = [Server]::new('web01')
$s2 = [Server]::new('web02')
Write-Host "Total servers created: $([Server]::Count)"
Write-Host "Default env: $([Server]::GetDefaultEnvironment())"

Use Class in a Module

Define classes in a .psm1 module file. Classes defined in a module are available after Import-Module. Use using module ModuleName at the top of scripts that reference the class types — this loads the class definitions before the script runs, which is required because classes must be defined before instantiation.

# At top of script that uses classes from a module
using module C:\Modules\ServerTools\ServerTools.psm1

# Now the class is available
$server = [Server]::new('app01', '192.168.1.50')

Common Errors and Fixes

  • Class must be defined before it is instantiated in the script. Unlike functions, PowerShell classes are not automatically available before the line they are defined on. If you try to instantiate a class before its class { } block, you get “Unable to find type [ClassName].” Define classes at the top of the script or use using module to load them from a module.
  • Inheritance syntax differs from C# — uses colon notation. In C# you write class Child : Parent { }; in PowerShell it is the same syntax: class Child : Parent { }. However, calling the base constructor uses ChildConstructor() : base(args), which may trip up developers familiar with C# base() calls inside the method body.

Related Cmdlets / See Also

Wrapping Up

PowerShell classes bring type safety, encapsulation, and inheritance to scripting without requiring a separate compilation step. Use them when your module needs reusable data types with behavior, when multiple functions share a common data structure, or when you want to enforce typed properties. For simple data containers without methods, [PSCustomObject] remains lighter and simpler.

Send-Item -To