Understanding and using objects in PowerShell

How to use PowerShell objects, how to tease more info and functionality out of them and how objects can be useful in scripting scenarios.

One of the things most people do not realize about PowerShell, at least up front, is that PowerShell is based on the .NET Framework, which means that PowerShell can be considered a programming language. In fact, each response you get from running a cmdlet in PowerShell, no matter how simple or complex that cmdlet may be, is actually a .NET object. It might look like text to you, but it can be programmatically manipulated in ways that Linux and UNIX command line diehards can only dream about.

In this piece I'll focus on using PowerShell objects, how to tease more info and functionality out of them, and how objects can be useful in scripting scenarios.

What is an object?

It would probably help to know what an object is so that you can understand just how useful this capability of PowerShell is.

Objects are essentially known quantities of something that programming languages can use, interact with, perform computations and transformations on, and in general "consume." Technically, an object is simply the programmatic representation of anything. Objects are usually considered as two types of things: Properties, which simply describe attributes of whatever the .NET object is representing, and methods, which describe the types of actions (think verbs, or short instructions) that the .NET object can undertake.

For example, let us consider a car as an example. If we were making a car into a .NET object, then its properties would include its engine, doors, accelerator and brake pedals, steering wheel and headlights. Its methods would include turn engine on, turn engine off, open doors, close doors, press accelerator, release accelerator, turn steering wheel left, turn steering wheel right, turn on headlights, turn off headlights, turn on brights and turn off brights. (That is not an exhaustive list, but it should serve to demonstrate to you that the properties of the car are a description of its components, and the methods of the car describe how you can operate and interact with the properties.)[ Further reading: Getting started with PowerShell: The basics ]

In PowerShell, it is a simple matter to see an object's properties and methods: Just use the Get-Member cmdlet to view them. You can do this by piping the output of a cmdlet. Remember that output is an object to the Get-Member cmdlet, like this:

Get-Command | Get-Member

TypeName: System.Management.Automation.AliasInfo

Name

MemberType

Definition

Equals

Method

bool Equals(System.Object obj)

GetHashCode

Method

int GetHashCode()

GetType

Method

type GetType()

ResolveParameter

Method

System.Management.Automation.ParameterMetadata ResolveParameter(string name)

ToString

Method

string ToString()

CommandType

Property

System.Management.Automation.CommandTypes CommandType {get;}

Definition

Property

string Definition {get;}

Description

Property

string Description {get;set;}

Module

Property

psmoduleinfo Module {get;}

ModuleName

Property

string ModuleName {get;}

Name

Property

string Name {get;}

Options

Property

System.Management.Automation.ScopedItemOptions Options

You can see in the middle column that the different methods and properties are delineated, but what is that third column? Those are called data types, and they basically show the classification of answer that will be returned by that method or property (for instance, telling if something is yes or no or true or false would be a Boolean type, whereas a response consisting of text would generally be a string). We will see data types coming into action a little later in our PowerShell series, so stay tuned for that.[ Got a spare hour? Take this online course and learn how to install and configure Windows 10 with the options you need. ][ Further reading: PowerShell tips and tricks ]

You will find as you get into more day-to-day administration with PowerShell that you will be using this Get-Method cmdlet a lot, and the reason is because it is going to tell you exactly how you can interact with various objects.

For example, let us talk about finding files on a shared drive of a certain type. How do you end up knowing exactly what cmdlets and syntax to use to work out how to find specific files with a certain type of file extension? It's through the use of these methods and properties and the PowerShell pipeline, which of course pipes objects and responses through from one cmdlet to the next.

An example

Say you have been infected with Cryptolocker on one of your business' machines. This is a nasty bug that is ransomware; it is malware that silently encrypts the files it finds in a couple of places on your machine (My Documents and mapped drives being a couple of them). And then the bug makes you pay several hundred dollars in untraceable Bitcoin or Green Dot prepaid debit cards to get the key to decrypt them. You either pay up or you lose access to your files.

In our example, let's assume you were able to find the infection before it had the time to encrypt all your files. You immediately shut down the machine, so the encryption process stopped, but as part of your diagnosis of what happened, you need to figure out a list of all the files that were modified in the last day or so. There is a cmdlet called Get-ChildItem, which is your tool of choice when you want to grab something out of a giant container of items -- in this case the file system.

So we know to start with Get-ChildItem, but how do we know what parameters to put along with it?

First, we can check out get-help get-childitem, which will show us that the syntax starts off with -Path, so we know that if we are concerned with potentially encrypted data at the mapped drive S: where shared documents are stored, we would use -Path S:\ to establish where to look.

But what about subdirectories, subfolders, and any sort of nested structure we want to examine as well? From get-help get-childitem we also see the -Recurse parameter; recursive checking means the program will start at the top and then "recurse," or walk down, the hierarchy of files until everything has been properly examined. We'll add that to the cmdlet as well.

That brings us to this partial cmdlet:

Get-ChildItem -Path S:\ -Recurse

You can actually run that, and PowerShell will spit out a list of every single file on the S: volume separated out by subdirectory. But we need to examine more about that huge list of files, so we will use the pipeline function to send that output into another cmdlet.

But what cmdlet helps us select a portion of a big set of data for further processing? That is the job of the Where-Object cmdlet.

So our cmdlet takes on further shape and body:

Get-ChildItem -Path S:\ -Recurse | Where-Object

Remember that we add in curly braces, and then within them we can use the $_, or as I like to affectionately call it, "that thing," to represent the output of a previous cmdlet that is being piped into a new cmdlet. Then, we add a period or dot and then the name of a property of that object that is represented by $.

Here is what we have so far:

Get-ChildItem -Path S:\ -Recurse | Where-Object {$_.

But what is Where-Object going to filter? That's where we need to find out what the properties of Get-ChildItem are; we can use those properties to "tune the antenna," so to speak, of Where-Object so that it is filtering on the right criteria. To find those properties, let us consult with Get-Member.

Get-ChildItem | Get-Member

TypeName: System.IO.DirectoryInfo

Name

MemberType

Definition

LastAccessTime

Property

datetime LastAccessTime {get;set;}

LastAccessTimeUtc

Property

datetime LastAccessTimeUtc {get;set;}

LastWriteTime

Property

datetime LastWriteTime {get;set;}

LastWriteTimeUtc

Property

datetime LastWriteTimeUtc {get;set;}

Name

Property

string Name {get;}

Parent

Property

System.IO.DirectoryInfo Parent {get;}

Root

Property

System.IO.DirectoryInfo Root {get;}

BaseName

ScriptProperty

System.Object BaseName {get=$this.Name;}

TypeName: System.IO.FileInfo

Name

MemberType

Definition

IsReadOnly

Property

bool IsReadOnly {get;set;}

LastAccessTime

Property

datetime LastAccessTime {get;set;}

LastAccessTimeUtc

Property

datetime LastAccessTimeUtc {get;set;}

LastWriteTime

Property

datetime LastWriteTime {get;set;}

LastWriteTimeUtc

Property

datetime LastWriteTimeUtc {get;set;}

Length

Property

long Length {get;}

Name

Property

string Name {get;}

BaseName

ScriptProperty

System.Object BaseName {get=if ($this.Extension.Length -gt 0){$this.Name.Re…

VersionInfo

ScriptProperty

System.Object VersionInfo {get=[System.Diagnostics.FileVersionInfo]::GetVer…

Note we have two tables of information returned: One for type System.IO.DirectoryInfo, and the other for System.IO.FileInfo. Since we are looking for information on specific files, we will use the latter.

Looking at that second table, we see two properties that might be interesting to us for completing our task: LastWriteTime and LastWriteTimeUtc. This is what we're looking for! We need the last time that a file was written to.

In this case, just to make things simple, we will use LastWriteTime rather than worrying about converting timezones to Greenwich Median Time, although you might have a specific purpose for doing so as you progress in your scripting capabilities.

So to put together our fuller picture, here is where we are:

Get-ChildItem -Path S:\ -Recurse | Where-Object {$_.LastWriteTime

So we have identified the last write time, but we obviously need to do something with that; we need to ask ourselves, in constructing this command, the question: "Where the last write time is what, exactly?" So we need a comparison operator.

You may recall from a previous PowerShell story that we can use -lt for "less than" and -gt for "greater than." So in order to figure out what was written in the last day or so, we can pick a date two days ago. In this example, today is May 14, 2015, so if I'm trying to figure out what files have been touched in the last 24 hours, I would want to know files where the last write time is greater than May 12, 2015.

We write this out in standard MM/DD/YYYY format and then enclose it in quotes as it is considered a string. Then we will add the closing curly brace because our comparative clause is complete, and we have the following cmdlet built:

Get-ChildItem -Path S:\ -Recurse | Where-Object {$_.LastWriteTime -gt "05/12/2015"}

Run that, and you will get a list of every file on the S: volume that has been written to on 5/12/2015 or after -- exactly what we were looking for. And we did that by understanding that (a) the output of Get-ChildItem is an object, and (b) we can find the properties of the Get-ChildItem output object using Get-Member and use those properties to (c) pipe to Where-Object to find specific information about a subset of that output.

Extrapolating how to use objects

There are all sorts of convenient ways to use objects and their properties and methods. With all output being an object, it means you can address all sorts of attributes and characteristics of whatever it is you are working on.

For instance, you can display information in a table format that eliminates all of the other facts you do not have any interest in and laser focuses on the facts in which you are interested. For example, let's look at what is available for Get-Service.

Get-Service | Get-Member

If I run that, I will see in the table that results that Status is a property and Start and Stop are methods. So if I wanted to find out all the services on a machine that were in the Stopped state, and then start those services, I might want to build the following cmdlet:

Get-Service | Where-Object {$_.Status -eq "Stopped"} | Start-Process.

What if I wanted to find all of the Exchange mailboxes that been created in my lab Exchange environment and then delete those mailboxes because I am done with my experiment and want to restore my test deployment? First, I would want to see the properties available for the Get-Mailboxcmdlet, a core cmdlet of Exchange or Office 365:

Get-Mailbox | Get-Member

I would see, among dozens of other properties, the WhenChangedproperty. This might work, so I would test this out:

Get-Mailbox | Format-List name,WhenChanged

This gives me a list of mailboxes with the mailbox-friendly name and the value of the WhenChanged property. Looks like what I need, so I will modify the above cmdlet not to display a list but to receive the output of Get-Mailbox into a Where-Object filter, where I will grab the WhenChanged output and pass only those that meet my comparison criteria via the pipeline to the Remove-Mailbox cmdlet for deletion. It ends up looking like this:

Get-Mailbox | Where-Object {$._WhenChanged -gt "05/07/2015"} | Remove-Mailbox

Voila.

The last word

Objects are powerful differentiators that make PowerShell a rich and capable command-line environment. Understanding how to use objects and dig into their properties and methods unlocks the entire universe of PowerShell's abilities for you. Take some time to play around with this.

Last updated