Otto background

Windows Administration with PowerShell #10: PowerShell Classes

It’s time to get excited because this installment dives into PowerShell classes! Classes were introduced to PowerShell fairly recently with the release of Windows Management Framework 5.0. Due to the recency of the introduction, there aren’t many examples that exist for those interested in classes to reference. It also doesn’t help that the examples that do exist are of very simplistic implementations that don’t do a great job of highlighting exactly how beneficial they are. This installment will try to remedy that problem, but first, let’s go over some of the basics.

What are Classes!?!

If you are curious as to why there are excessive amounts of exclamation points in this post, it is because the addition of classes to PowerShell has opened up a whole new world of opportunities! But what exactly are those opportunities? Well, that’s a multi-part answer, one that is rarely addressed in the scope of a scripting language and requires an understanding of a few key concepts.

Object-Oriented Programming

Object-Oriented Programming is a programming model based on the concept of organizing code around “objects.” Every language has its own way of working with these objects but the underlying concept stays the same: organize your code around “objects” instead of “actions”.  Traditionally, the programming challenge has always been approached from the perspective of how to write logic. The OOP approach focuses on how we want to define the data. What exactly does this mean? Let’s take a look at some sample code to make things a little more clear:

This is the way we have been doing things up until now. Notice how we have essentially been creating a cmdlet for each action that we want to accomplish. Furthermore, take note that PowerShell’s cmdlet naming standard, Verb-Noun, is very action-centric. Now, there is nothing wrong with this implementation. When properly executed, you can have organized and readable code that is modular enough to support all your needs.

There are, however, a few downsides. This particular example isn’t too complex but you will notice that the Update-AxServer cmdlet has quite a few parameters that need to be passed. This can make implementation annoying when having to source all the requested information manually each time you need to update a server. Additionally, you are following patterns that are very specific to PowerShell. Up until now, we have been discussing supportability of your scripts within the scope of PowerShell developers, but imagine someone who is new to PowerShell and is not completely familiar with the syntax having to mess around with your code. It’s not impossible, but PowerShell is unique in many ways and because of that there is a learning curve that needs to be conquered.

So, how could we possibly address an issue like this? Sure, you could collate the required information into an XML or JSON and pass it as one parameter, but then you would have to add login to your script to collate your data in the desired format. Perhaps a function to do so? Maybe, but then you’re back at square one because you will have to pass all the relevant data to that function as well. Even if there was another way to do this, what benefit would we get? By following patterns that are not specific to PowerShell, you increase the ability of developers familiar with other languages to understand your implementation. Both of these issues are solved by OOP and classes.

Defining a PowerShell Class

I’m sure at this point you are tired of hearing about the benefits of PowerShell Classes. Let’s get to the good stuff! How do we use PowerShell classes? Defining a PowerShell class is fairly straightforward, especially if you have already worked with classes in other languages. The first step is to decide what data will be stored as part of that class. In order to provide a good comparison, we are going to write a class that helps us accomplish the same actions as the code above. Let's see what that looks like:

All we did was essentially list out the information that we need to store in this class. But how do we assign values to these attributes? That is where constructors come in. When defining a PowerShell class there is a default constructor that is used that doesn’t really do anything. In order to define your own custom constructor you need to define a function with the same name as your class. Inside that function is where you would execute any actions needed in order to gather the necessary information.

Now you have a class that will give you access to relevant information based on the provided parameters when it is initialized. Let’s do a quick comparison to see how that looks compared to the older way of doing things:

As you can see, there’s not much of a difference so far. The older way reads a little more like English, but if you have been developing in any language for a while the initialization of our new Server class will look more familiar. How do we go about making changes to our data? You can assign directly to the attributes of the class, but this will not update the information in the Automox Console. In order to accomplish that, you will need to define a new function within the class to update any relevant information.

I have also added an additional function for deleting our server from the Automox Console. You will notice that only certain information is being updated in our update method. This is because some of the information contained in the Server object is collated from the Server itself and not intended to be modified by a person.

Surely there has got to be a better way to address that limitation? There are a few different options, however, the underlying issue is that we cannot define attributes as read-only in PowerShell classes. For those familiar with classes in other languages, there is no such thing as private/protected attributes. You can define them as hidden and use getter and setter methods to manipulate the supported data, but this is not a hard gate. Even though you would not be able to see the attributes directly you would still be able to modify them and could potentially introduce the ability to modify unintended data.

Now that we have our class defined, let’s look at how to modify desired data.

In this snippet, the two lines above show how we modified Server data using our cmdlets. Below that, however, you will see the use of the Server class. You will notice how much more intuitive utilizing the class feels then utilizing the cmdlets. I initialize a new server object given its unique id, modify the information I want, then update it. While using the cmdlets accomplishes the same thing, it’s a little harder to think through. I get my server data using its unique id, determine what parameters are required by the Update-AxServer cmdlet, determine which data points from the server match those parameters, modify the desired one, then update the server object.

Conclusion

I will be the first to admit that using classes can be overkill in the scope of things you would generally try to accomplish with a language like PowerShell. However, there are always exceptions to the rule! As usual, it is up to you as the developer to determine what the best solution is for the problem you are trying to tackle. PowerShell classes are just another tool at your disposal. That being said, it’s a pretty awesome tool! If anyone reading this ends up writing their own class, please send them my way. I would love to see what other engineers do with them!

About Automox

Facing growing threats and a rapidly expanding attack surface, understaffed and alert-fatigued organizations need more efficient ways to eliminate their exposure to vulnerabilities. Automox is a modern cyber hygiene platform that closes the aperture of attack by more than 80% with just half the effort of traditional solutions.

Cloud-native and globally available, Automox enforces OS & third-party patch management, security configurations, and custom scripting across Windows, Mac, and Linux from a single intuitive console. IT and SecOps can quickly gain control and share visibility of on-prem, remote and virtual endpoints without the need to deploy costly infrastructure.

Experience modern, cloud-native patch management today with a 15-day free trial of Automox and start recapturing more than half the time you're currently spending on managing your attack surface. Automox dramatically reduces corporate risk while raising operational efficiency to deliver best-in-class security outcomes, faster and with fewer resources.