In this article, you’ll understand why classes are important in PowerShell administrative scripting, and you’ll learn how to define and use a simple class.

Increasingly more Windows systems administrators find themselves in a DevOps environment that requires them to know “some stuff” about programming, source control, and related development matters.

Along the same lines, Windows PowerShell Desired State Configuration (DSC) has historically been rather cumbersome to configure, with some DevOps-minded sysadmins complaining, “Why can’t we use classes to define DSC resources? It would be a heck of a lot easier than using cumbersome configuration scripts.”

Well, those sysadmins are correct, and Windows Management Framework (WMF) v5 includes native support for classes. The class implementation is far from complete, but we don’t need to delve into the nether regions of object-oriented programming (OOP) theory to learn the basics.

What are classes, and why should I care? ^

A class is a blueprint for an object. What’s cool about classes is that once you have your model in place, you can duplicate them to create as many instances of that class as you need.

Another thing that’s awesome about classes is that they consist of properties, or descriptive attributes, and methods, which represent actions that the class can perform. As you might have heard, all data in Windows PowerShell are represented as objects.

Let’s take a concrete example. We’ll start by creating a variable to store our Windows 8.1 computer’s Spooler service:

$spool = Get-Service -Name spooler

Next, we’ll pipe to Get-Member in order to check its data type and members:

$spool | Get-Member

Viewing object members

Viewing object members.

As you can see, our Spooler object is represented as an instance of the ServiceController class. If you’re so inclined, you can learn all about the .NET Framework class library by visiting the MSDN Web site.

By the way, we refer to classes as types or data types. When we create an instance of a class blueprint, that’s called instantiating the class. In this example, our $spool variable represents a single instance of the ServiceController class.

Now look at the MemberType column in the above screenshot. Don’t worry about the AliasProperty and ScriptMethod entries; instead, focus on the Properties and Methods.

We can get and set object properties by using “dot notation.” For instance, let’s check the status of our spooler service:

$spool.Status
Running

The “dot” in dot notation separates our variable from a specific object member (property or method, recall).

We also use dot notation to call methods. Remember that methods define actions that an object can take. Let’s stop the Spooler service now on our test workstation:

$spool.Stop()

If you’ve ever used functions, then you’ll find methods are similar inasmuch as you use parentheses () to enclose input arguments. As it happens, we don’t need an input argument for the Stop() method.

For grins, we’ll get the Status property one more time to verify that our change went into effect:

$spool.Status
Stopped

You’ll find that most of the .NET classes have read-only properties. You can get their values, but you can’t set them. For instance, the following screenshot shows what happens if we try to change the value of the spooler service’s CanShutDown property from False to True.

Most system properties are set to read-only by default

Most system properties are set to read-only by default.

All of the preceding is a great crash course for understanding classes, but that doesn’t answer the question, “Why would we want to create our own custom classes in PowerShell?”

Besides the chief reason of creating class-based DSC resources for your configuration management needs, the other great advantage of PowerShell classes is that they allow you to store “buckets” of data that can actually perform actions on their own. You also have excellent code reuse because you can instantiate as many class instances as you want, sharing some or all of the parent object’s properties and methods.

PowerShell functions (both of the simple and advanced varieties) are both beautiful and useful. For instance, if we need to track multiple object properties, there’s nothing wrong with using PSObjects and hash table “splatting” (thanks to PowerShell MVP Stephane van Gulick for the example):

function New-ComputerAsset {
     $Properties @{Name= ‘‘; Description=‘‘; Type=‘‘; Ower’’}
     $NewComputer = New-Object -type PSObject -property $Properties
     $NewComputer
 }
 New-ComputerAsset
 

PowerShell functions can mimic classes somewhat

PowerShell functions can mimic classes somewhat.

For those who are unfamiliar, let me break down the above code for you. A PSObject is nothing more than a generic .NET object. In the previous example, we’re casting a hash table (stored in the $properties variable) into that new object.

A hash table, also called an associative array, is nothing more than a collection of key/value pairs. In this example, we define four keys: Description, Name, Owner, and Type. “Splatting” is a technique whereby we apply a hash table to a new object. Basically, splatting saves us a lot of extra typing!

So, functions are great and all, but in the above example, what if we needed to create 20 or 200 separate computer asset objects, each with its own set of properties? Furthermore, what if we wanted to use only some of the properties or different ones altogether? Now we start to see the power of classes.

Creating a (very) simple class in PowerShell v5 ^

I have Windows Management Framework (WMF) v5 Release to Manufacturing (RTM) installed on my Windows 8.1 administrative workstation:

$PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      0      10586  51

In an elevated Windows PowerShell ISE session, we’ll use the PowerShell v5 Class keyword and a set of curly braces to start our new class definition (again, thanks to Stephane for the example):

Class Computer {
    [String]$Name
    [String]$Description
    [String]$Type
    [String]$Owner = ‘Tim Warner’
}

In the above example, we create properties by specifying a .NET datatype in square brackets (here’s a reference from MSDN if you want to learn more about these), followed by a unique variable name. Note I’ve statically assigned ‘Tim Warner’ to the $Owner variable.

Now we’ll expand our test Computer class to include a method. We’ll add some sample code to specify a system restart action:

Class Computer {
    [String]$Name
    [String]$Description
    [String]$Type
    [String]$Owner = ‘Tim Warner’

    [void]Restart() {
        Write-Host ‘The computer should restart now’ `
        -ForegroundColor Green
    }
}

[void] indicates that the method won’t return any data. Instead, we simply want it to perform some action. The empty parentheses after the method name, Restart(), means that we don’t need to pass any input parameters when we call the method.

Technically, we could make the method do an actual Restart-Computer-Force, but instead, I used Write-Host to print some sample output to the screen.

Instantiating our new class ^

Run the script containing your new class definition in order to load the code into your current PowerShell runspace. Next, we’ll use what’s called a constructor to spawn a new instance of the Computer class:

$NewComputer = New-Object 'Computer'

Name Description Type Owner     
---- ----------- ---- -----     
                      Tim Warner

Remember that we pre-populated the Owner property in our source code. Why don’t we go ahead and populate the object’s remaining properties by using dot notation? You can see in the following screenshot how the Windows PowerShell ISE IntelliSense lists our properties and methods for easy retrieval.

PowerShell ISE IntelliSense helps with properties and methods

PowerShell ISE IntelliSense helps with properties and methods.

$NewComputer.Name = ‘ultra1’
$NewComputer.Description = ‘Lenovo Yoga 900’
$NewComputer.Type = ‘Ultrabook’

You can echo $NewComputer again to test that the properties are correctly associated with our new Computer object. Now let’s test the Restart() method:

$NewComputer.Restart()

The computer should restart now

Finally, we’ll pipe $NewComputer to Get-Member to verify the data type and object members:

PS C:\> $NewComputer | Get-Member

   TypeName: Computer

Name        MemberType Definition                    
----        ---------- ----------                    
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()             
GetType     Method     type GetType()                
Restart     Method     void Restart()                
ToString    Method     string ToString()             
Description Property   string Description {get;set;} 
Name        Property   string Name {get;set;}        
Owner       Property   string Owner {get;set;}       
Type        Property   string Type {get;set;}

Look at that TypeName! I hope you found this brief tutorial insightful. Trust me — if you’re beginning to use PowerShell DSC, then you’ll want to get started using class-based resources sooner rather than later.

3 Comments
  1. LP 6 years ago

    Didn’t you forgot how to make a new instance of the class ? You just “typed” $NewComputer and voila you have your class instantiated ?

  2. LP 6 years ago

    OK, I confirm there’s commands missing. Just the “$NewComputer” doesn’t to anything (that’s normal). You have to type “$NewComputer = new-object Computer” to instantiate the class 🙂

  3. Author
    Timothy Warner 6 years ago

    LP, thanks for your sharp eyes–I did indeed forget to define the constructor. Post updated! Cheers, Tim W.

Leave a reply

Your email address will not be published.

*

© 4sysops 2006 - 2022

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account