A PowerShell Tip for Selecting Data Easily

One constant with a technology like PowerShell is that there are always those who are getting started or still learning what all the fuss is about. From my perspective, we can revisit core principals from a new angle. Although there’s nothing in this article that’s necessarily new if you possess moderate PowerShell skills, I hope you’ll stick around, as I showcase some different ways of looking concepts and syntax.

Here’s an expression I recently came across online as an proposed solution to get a list of running Hyper-V machines whose name starts with CHI. Additionally, this expression works by saving information to a text file. I’ve tweaked it slightly to fit my environment.

However, my argument is that the PowerShell solution does nothing to embrace the PowerShell paradigm. When I see code like this, I get the sense the author is still trying to manipulate text and isn’t thinking about working with cmdlets that write objects to the pipeline. I’ve written about this concept before, which you can read in my series on extending objects in the pipeline. Once you get your head around that mindset, PowerShell becomes easier to write and offers more flexibility. Although this example is using the Get-VM cmdlet, what I want to explain applies to other cmdlets.

The ultimate goal is to extract a subset of meaningful data. In this instance, the data comes from a single cmdlet.

Normal results (Image Credit: Jeff Hicks)

The first part of the process is to limit the results to virtual machines that start with CHI and are running. Your first step should be to look at help.

cmdlet help for Get-VM (Image Credit: Jeff Hicks)

This cmdlet doesn’t have any filtering capabilities, which means we’ll need to resort to using Where-Object. That’s fine. But if there’s a way to do any sort of filtering at the beginning, we want to take advantage of it. Actually, there’s another filtering requirement and that’s to limit results based on the virtual machine name.

Name parameter information (Image Credit: Jeff Hicks)

Ideally, we could use a wildcard for the name, although the help says we can’t. Although I always encourage you to read the help, it isn’t infallible.

Grabbing virtual machines by name with a wildcard (Image Credit: Jeff Hicks)

In this case, there’s no harm in trying, and look at that, it works! This means I can use a simpler filter for Where-Object.

PowerShell

1

Get-VM-name"chi*"|where{$_.state-eq"running"}

Filtering results with Where-Object (Image Credit: Jeff Hicks)

Sponsored

The original need was to display a few properties. If you need to do that, then use Select-Object.

PowerShell

1

2

Get-VM-name"chi*"|where{$_.state-eq"running"}|

SelectStatus,Uptime,State,Name

Selecting specific properties (Image Credit: Jeff Hicks)

There was also a need to display the current date and time. Select-Object is already writing an object to the pipeline with the properties that interest us. We can easily add a custom property with a hashtable.

PowerShell

1

2

Get-VM-name"chi*"|where{$_.state-eq"running"}|

Select@{Name="Date";Expression={Get-Date}},Status,Uptime,State,Name

The name value will the name of the new property (Date), and the value will be the result of the Expression scriptblock, which in this case is the result of running Get-Date.

Adding a custom property (Image Credit: Jeff Hicks)

If you are following along at home, I’ve taken a four-step process and simplified it to a one-step command. The original command displayed results in a tabular format. If you need a table, then tell PowerShell to make you one.

PowerShell

1

2

3

Get-VM"chi*"|where{$_.state-eq"running"}|

Select@{Name="Date";Expression={Get-Date}},Status,Uptime,State,Name|

Format-Table-AutoSize

Formatted results (Image Credit: Jeff Hicks)

Or maybe you want something more like the original output without any column headings. If you take the time to read help for Format-Table, you’ll discover you can do that.

PowerShell

1

2

3

Get-VM"chi*"|where{$_.state-eq"running"}|

Select@{Name="Date";Expression={Get-Date}},Status,Uptime,State,Name|

Format-Table–HideTableHeaders-AutoSize

Hiding table headers (Image Credit: Jeff Hicks)

The last piece of the original command is to save the results to a text file. The original code used the legacy redirection character, >>. Although it works, I’m not a big proponent of its use because it brings nothing to the PowerShell party. I much prefer and recommend to use the cmdlet designed for sending output to a text file, Out-File. One of the benefits is that you can control the encoding.

PowerShell

1

2

3

4

Get-VM-name"chi*"|where{$_.state-eq"running"}|

Select@{Name="Date";Expression={Get-Date}},Status,Uptime,State,Name|

Format-Table|

Out-File-FilePathd:\work\vms.txt-Encodingascii

Formatted results (Image Credit: Jeff Hicks)

The other benefit of understanding the pipeline is that I didn’t have to try and do something with each virtual machine using ForEach-Object, as in the original example. Of course, there will be situations where that makes sense and knowing when I think comes from experience. But now I’ve taken a multi-line command that was designed to create a piece of text for each virtual machine with relevant information, to a one-line command that wrote an object to the pipeline with all of the information I needed. I then used other PowerShell commands to get the results into the desired format.

Sponsored

I’m not completely finished with this topic, but that’s all the time I have for today. I hope this makes sense to you and that you recognize the value of the PowerShell paradigm. Comments always welcome.