Introduction to Objects in PowerShell
One of the features that both makes PowerShell so easy to use yet sometimes difficult to learn is its focus on objects. I have taught PowerShell to many, many people over the last 10 years and this is not as difficult as people make it out to be. That is to say, I think many beginners get it into their heads that because PowerShell is based on the .NET Framework and there is all this talk about objects that they need to start thinking like a developer. Absolutely not.
I always teach PowerShell as a management tool first. PowerShell is made up of numerous building blocks; it is up to you to combine the building blocks into an expression or series of expressions that accomplishes a given task. The big paradigm jump is to realize that when you are running PowerShell commands you are working with objects and not text output. So let’s take a quick look at objects in PowerShell.
An object for our purposes is some thing that was created by a developer. We don’t care how they developed it or how it works internally. It is essentially a black box. What we do care about is the object name, properties and methods. There are additional elements like events but those are advanced features that you aren’t likely to need. Let’s look at this from perspective of a real-world object, a boat. We’ll also consider some boat specific commands.
First off, the name of the object is boat. This can also be referred to as the typename. Understanding the object name is important because you might want to research information about the boat type. Or you want to be able to identify commands that can work with a boat object. I know we’re jumping the gun a bit, but you can get the typename by piping a boat object to Get-Member. This cmdlet will also show you other parts of the object, referred to as its members.
An object has a set of attributes that describe it. These are the objects properties. These are defined by the developer responsible for designing the object, although eventually you will learn in PowerShell how to add your own. For now, let’s look at the boat. Some properties are Read-Only, meaning you can’t change them. For example, a boat might have these constant properties once it is created. All you can do is get them.
Other properties can be modified meaning you can get and set them.
In addition, some properties might be nested objects. In the boat example, there is most likely an Engine property but value is an entirely separate object with its own set of properties.
- Engine [boat property]
- type (inboard or outboard)
All of these properties will have values that themselves are also types of objects. But don’t worry. I’m talking about things like text ([string]), numbers ([int]) and dates ([datetime]). All of these settings describe the current state of the boat.
To reference any of these properties you use a dot notation. On the left side is a reference to the object, such as a variable. On the right side is the property name. You could get the name of the boat like this:
For nested objects you can “drill” down
This example assumes the InstallDate property is a DateTime object which itself has a Year property.
An object usually has a set of methods. These are actions you can do to the boat or have the boat do. Here’s a short list that comes to mind for our boat object.
Again, these methods are created by the developer. We don’t care how they work, only what they are called and how to use them. You can invoke them using the same dot notation.
Some methods don’t require any customization. To start the boat we simply need to invoke the method, although we do need to include the parentheses even if there are no parameters. Other methods might require parameters. For example, the Sell() method might need a parameter for the new owner name, a purchase price and the date. Programmatically it might look like this:
If I were forced to use this native method it might look like this in PowerShell:
Now before you tell yourself you’ll never learn this, let me point out that you shouldn’t have to directly invoke object methods. At least not until you gain experience and better understand where it makes sense to do so. Instead, you should look for cmdlets and other tools that will do the work for you.
Ideally, whoever created the boat object, also created a set of cmdlets for managing them. Cmdlets are easy to discover, easy to use and can additional features like support for Whatif and Confirm. You shouldn’t be forced to use .NET techniques to work with objects in PowerShell. Instead there might be a cmdlet like Get-Boat.
$boat = Get-Boat -manufacturer Manitou -model Oasis
The author of the Get-Boat cmdlet is responsible for creating a boat object with all of the necessary properties and writing it to the pipeline. There might be another cmdlet called Set-Boat that allows you to set things like the name. Ideally, this cmdlet will be designed to recognized pipeline input for boat objects.
$boat | Set-Boat -Name "The Pipeline Queen" -Undock
Of course we may want to then start the boat and start driving it.
$boat | Start-Boat -passthru | Set-Boat -speed 20
Behind the scenes the cmdlets are using the object’s native properties and methods but we don’t care. The cmdlets provide the interface we need to managing boat objects. If the cmdlets are well-written we can pass the boat object from one command to another in a single expression.
$boat = Get-Boat -manufacturer Manitou -model Oasis | Start-Boat -passthru | Set-Boat -speed 20 -Name "The Pipeline Queen" -Undock -passthru
We never have to manipulate text. At the end of the pipeline, PowerShell will write any objects to the hosting application and at that point you see text on the screen. In my pseudo-example, I’m saving the result to a variable which I can then use in my PowerShell session.
Once you understand my hypothetical examples, it shouldn’t be that much of a leap to working with objects in PowerShell. For example, Get-Process will get a collection of process objects. If you pipe these objects to Get-Member, you’ll see that many properties are Read-Only, meaning you can only get them. While other properties could be set. And there are methods as well for terminating processes. But you don’t need to necessarily know how to use the methods, all that matters are the associate cmdlets.
get-process -name notepad | stop-process
Perhaps the trickiest part of working with objects in PowerShell is that things can change inside the pipeline.
Even though the command started with Process objects the end result is a different type of object created by Group-Object. I find it helpful to be able to visualize what is happening in the pipelined expression: “Get all processes where there is a Company property then group the results by the Company property, sort the group objects by the Count and Name in descending order and then select the first 5 objects.” This works because I learned about the Company property on Process objects and the Count,Name properties for GroupInfo objects. Not once did I think about parsing or grepping any of the text on the screen. The object nature of PowerShell made this an easy task that didn’t require any programming or scripting.
Even so, I know this object concept can still be a struggle to embrace and understand. So take some time trying things out in PowerShell. Look at cmdlet help and examples and start trying to visualize what is happening behind your commands. Once this clicks I think whole new worlds of opportunity will open for you.