The object-oriented model

The moment someone mentions PowerShell or talks about its benefits, one of the first things that comes to people’s minds is how the output is an object. And most of us don’t understand why this should be a big deal that it is made out to be. Or what it even means. I’ve been there, and it took me some time to fully understand its importance.

In this article, we talk about:

Introduction to objects

Any book on object-oriented programming will tell you what an object is, and chances are, you have already heard of it before. If you haven’t, I’m going to take a real world example, as well. Think of a house. Think of it as a class. It has objects such as a window (property), a door (property), a room (property), the ability to guard people from snow (method), the ability to let people live in it (method), and so on. Really, that’s about it. And I’m not going to bore you with abstraction and encapsulation and things like that. Let’s keep that aside for now.

Let’s think about why PowerShell’s being object-oriented matters, and how it helps us. I want you to open a command window. And a PowerShell window. Now, navigate to a location on your disk. Let’s say, C:\Temp. List out the contents of the folder. On the command window, you’d say, dir. And bang, oh, oh, it can list out the contents!

Next, switch to the PowerShell window. Type in Get-ChildItem and hit Enter. Similar output, right? Yes. But what you can do here, is manipulate this output. Because what was output was a collection of objects, and not just text. What you got from cmd was text. It’s a dead end. If you wanted to do anything with it, you would have to do a lot of circus to manipulate the string.

Breaking down the returned object

With PowerShell, you don’t have to do that. For instance, if you want to just list out the year in which the files were last modified:

Get-ChildItem | select LastWriteTime -First 1 | Get-Member

If you look at the Definition column, you’d notice a NoteProperty property, which shows you the long date. Let’s select that.

(Get-ChildItem | select LastWriteTime -First 1).LastWriteTime

It now shows you just the long date.

Let’s zoom in further.

(Get-ChildItem | select LastWriteTime -First 1).LastWriteTime | Get-Member

Nah, let’s filter out the output and make it manageable:

(Get-ChildItem | select LastWriteTime -First 1).LastWriteTime | Get-Member | Where-Object {$_.MemberType -eq 'Property'}

Don’t worry about it being complicated. Just play along for now. Do you see a collection of date-related data? Let’s say we want to pick the year alone:

(Get-ChildItem).LastWriteTime.Year

Seem a little complex?

I just did all that to give you a peek into what a PowerShell object is. What we did was, explode the output that was an object, into objects of it. Within that, we selected the LastWriteTime object, and within that, we selected the Year object.

This seems like a task when we do this for a single piece of information. But when you want this data for say, 10,000 rows, it would be very helpful—the object model. Also, as you start working with PowerShell on a regular basis, you will develop an understanding of the type of object each cmdlet returns and the properties and methods each of those objects contain. Think of this like a mental inventory of information. Your speed and efficiency will only improve from there.

At this point, it may be tempting to argue that we still had to do a lot of work to fetch the year we needed, and that this could have been achieved even by processing the text that CMD returned. However, it is important to remember that we did not do any text manipulation here. Using mere text could severely limit the capabilities. It would reduce our efficiency as well. For example, if you would like to list out all the files that were modified in the last 30 days, it takes only one line of PowerShell code:

Get-ChildItem | Where-Object {$PsItem.LastWriteTime -gt (Get-Date).AddDays(-30)}

Try doing that in a single-lined batch script.

How object output works

In PowerShell, what you see on the screen is a textual representation of the data. Let me explain how it works in the background.

A cmdlet is a specialised .NET class. When you call a cmdlet, the corresponding .NET class is called. This class contains objects. And these could be properties (what the object has) as well as methods (what the object can do). Therefore, within a System.DateTime object (which is returned by Get-Date), you would find properties Date, Month, Year, DayOfWeek, etc., along with methods such as AddDays().

When you call the Get-ChildItem cmdlet, the cmdlet returns two objects: System.IO.DirectoryInfo and System.IO.FileInfo. For now, let us concentrate on System.IO.FileInfo, because this is the object we used for the example above. The object contains a property called LastWriteTime, which is essentially a System.DateTime object. You see this when you call the following and see the TypeName in the output:

(Get-ChildItem).LastWriteTime | Get-Member

This object contains the property, Year, which we called in the end to fetch the year in which the files were modified.

Okay, this seems easy, but what about finding out in which year the files were created?

(Get-ChildItem).CreationTime | Get-Member

But you would’ve noticed, by default, the output of Get-ChildItem only showed Mode, LastWriteTime, Length and Name. Where did CreationTime come from?!

If you noticed at Get-ChildItem | Get-Member, you would see the CreationTime property as well. So why did this not appear in the output?

Simple: if the output object had to show all of its properties at the output, you could quickly drown in a sea of information. Also, PowerShell is for administrators. Therefore, PowerShell uses a set of formatting rules to decide what properties are meaningful to an administrators, and shows them by default. Even though the object returned contains all the information, only a few selected properties are actually shown on the screen as text.

If you would like to get more columns, you could use the cmdlet, Select-Object, which would allow you to select the properties you would like to see. But remember that the moment you pick the properties you want to see, using Select-Object, the object returned by Select-Object would contain only the properties you specified (and omit the ones you did not). This behaviour has its own advantages and limitations, and it is important you remember this.

Also, observe that the date shown in the LastWriteTime column isn’t the long format, but a short one with only numbers. This is also part of the formatting rules. If you would like to format what is shown in the columns, you would need to use what is known as calculated properties that we first looked at in A brief history of Windows.

Understanding Get-Member

One of the points that got downplayed in this post was the use of Get-Member. This cmdlet is among the holy trinity of PowerShell: Get-Command, Get-Help and Get-Member. It may seem self-explanatory to most, but I shall tell you in brief what it is, for the sake of completeness. The properties and methods in an object are collectively called its members. The cmdet, Get-Member, helps you peek into the object returned by a certain cmdlet, and tell you what the object type is and what member it contains. By default, Get-Member shows you the name of the member, the type of the member (method or property), and its definition. Get-Member is among the most-used-during-scripting cmdlets.

We could go on a little more about the object model of PowerShell. However, small chunks of information delivered frequently, aids in better assimilation. So, let’s stop here for now. As we write more scripts, we will get a better understanding of the model, and would be able to leverage it better.

Want to learn PowerShell?

The award-winning book, PowerShell Core for Linux Administrators Cookbook, which I co-authored, uses the recipe-based learning approach to give you a deep understanding of PowerShell. And the best part is, the concepts discussed work across platforms!

The best new PowerShell books

powered by TinyLetter