Windows PowerShell is all about objects. That should be the mantra for every PowerShell-loving IT professional. PowerShell's elegance is derived in large part by how you work with objects in the pipeline. And one cmdlet that you absolutely need to master is Select-Object. This cmdlet does exactly what the name suggests: It selects objects. Actually, it can select objects in a few ways, which I'll explain and demonstrate. I'll be using PowerShell 3.0 for the demonstrations.

Selecting a Number of Objects

The first way to use the Select-Object cmdlet (which has the alias of Select) is to select the first or last X number of objects. This is especially useful when you only need a sampling or subset of data. You use the -First parameter to select from the beginning of the data and the -Last parameter to select from the end of the data.

For example, suppose you're interested in discovering more about the methods and properties of the eventlog object, which you'd like to use to manage your event logs. You can use a command like this:

Get-EventLog -List | Select -First 1 | Get-Member

Here's how this command works:

  1. The Get-EventLog cmdlet gets a list of the eventlog objects.
  2. The list is piped (i.e., sent) to the Select-Object cmdlet. The -First 1 parameter tells PowerShell to select the first eventlog object in that list.
  3. That object is piped to the Get-Member cmdlet, which lists its properties and methods. I should point out that if all I wanted was member information, I didn't need to use Select-Object. But I wanted to demonstrate how to use it. Plus, if the initial command returned numerous objects, this technique would improve performance.

When it comes using the Select-Object cmdlet to select a number of objects, a more common usage is using it after some objects are sorted. For example, suppose you want to find the most recently modified file in your Scripts folder. To accomplish this, you can run the command:

Dir C:\scripts -File | Sort LastWriteTime | Select -Last 1

Here's how this command works:

  1. The Get-ChildItem cmdlet (which has the alias Dir) with the -File parameter lists the files contained in the specified directory (C:\scripts). Note that the -File parameter was introduced in PowerShell 3.0. If you aren't running that version, you'll get an error.
  2. The files are piped to the Sort-Object cmdlet (which has the alias Sort) and sorted based on the LastWriteTime property. The -Property parameter is the first positional parameter, so its parameter name (-Property) isn't required.
  3. The sorted list is piped to the Select-Object cmdlet with the -Last 1 parameter to select the last object (i.e., the most recently modified script).

The Sort-Object cmdlet's default sort order is in ascending order, but you can change that behavior by including the cmdlet's -Descending parameter. Here's a good example:

Dir $env:USERPROFILE\Documents -File |
  Sort Length -Descending |
  Select -First 5

(Although this line wraps here, you'd enter it all on one line in the PowerShell console. The same holds true for the other commands that wrap.) As Figure 1 shows, this command lists the five largest files in my Documents folder. To do so, it retrieves all the files, sorts them based on the Length property in descending order, and selects the first five files. The objects written to the pipeline are unchanged. All this command does is tell PowerShell how many objects to select, then passes those selected objects to the pipeline.

Figure 1: Listing the Five Largest Files in the Documents Folder

You can even go a step further and calculate the total size of the five largest files using the Measure-Object cmdlet with the -Sum parameter. As the following command shows, you pipe the five largest files to the Measure-Object cmdlet, telling it to sum the values of the Length property:

Dir $env:USERPROFILE\documents -File |
  Sort Length -Descending |
  Select -First 5 | Measure-Object Length -Sum

In my case, the command returned the sum of 10834708 bytes.

Selecting Properties

Many objects in PowerShell have more properties than you see by default, and you might need to see some of the nondefault properties. This is another way to use Select-Object. You can select the properties you want to view. You use the -Property parameter and specify a comma-separated list of property names. For example, suppose you want to view the DisplayName and Status properties of the Background Intelligent Transfer Service (BITS) on your machine. You can use the Get-Service cmdlet to get the information for BITS and pipe the results to Select-Object with those properties specified, like this:

Get-Service bits | Select -Property DisplayName,Status

Figure 2 shows the results.

Figure 2: Selecting the DisplayName and Status Properties of BITS

You can use any property or property set when you pipe something to Select-Object. The following command uses the Get-Process cmdlet to get information about the Winword.exe process and pipes it to Select-Object, which selects the PSResources property:

Get-Process Winword | Select PSResources

Like the -Property parameter of the Sort-Object cmdlet, the -Property parameter of the Select-Object cmdlet is positional, so you don't have to specify the parameter name (-Property). Figure 3 shows the results.

Figure 3: Selecting the PSResources Property of the Winword.exe Process

Selecting properties is the primary way most IT pros use Select-Object. You can also select properties using wildcards, which can save you some typing.

Selecting Expanded Properties

Some object properties are collections of values or nested objects. When you select them, you might not get the output you expect. Take, for example, this command:

Get-Service bits | Select DisplayName,RequiredServices

In the output shown in Figure 4, notice that the value for RequiredServices is in curly brackets.

Figure 4: Selecting Properties That Are Collections of Values or Nested Objects

To see those values, you need to expand the property by using the -Expand parameter:

Get-Service bits | Select -Expand RequiredServices

Unfortunately, you can only expand a single property. The output of the second command in Figure 4 shows the expanded service objects that are required for BITS.

Selecting Isn't Formatting

When you select properties with the Select-Object cmdlet, you'll notice that sometimes the output isn't formatted very well. You can see an example in Figure 5.
Figure 5: Selecting Isn't the Same as Formatting
This is to be expected. Selecting isn't the same as formatting. PowerShell does the best it can. If you want to pretty it up, you can pipe the results from the Select-Object cmdlet to the Format-Table cmdlet, using the -AutoSize parameter, as I did in Figure 6.

Figure 6: Formatting the Output from the Select-Object Cmdlet

Formatting must be at the end of your command, unless you are piping to one of the "Out" cmdlets such as Out-File. Most of the time, though, you'll be selecting properties to obtain only the data you want so that you can do something with it, such as export to a .csv file or convert it to HTML.

Take the Time

Take the time to learn how to use Select-Object. You'll be amazed by what you can accomplish in PowerShell when you use it.