Chapter 4. Life on the Assembly Line
The object-oriented pipeline is one of the distinctive features of the PowerShell environment. The ability to refer to properties of arbitrary objects without parsing increases the expressiveness of the language and allows you to work with all kinds of objects with ease.
In this chapter, we will cover the following topics:
- How the pipeline works
- Some of the most common cmdlets to deal with data on the pipeline:
Sort-Object
Where-Object
Select-Object
Group-Object
The pipeline as an assembly line
The pipeline in PowerShell is a mechanism to get data from one command to another. Simply put, the data that is output from the first command is treated as input to the next command in the pipeline. The pipeline isn't limited to two commands, though. It can be extended practically as long as you like, although readability would suffer if the line got too long.
Here is a simple pipeline example:
Tip
In this example, I've used some common aliases for cmdlets (where
, select
) to keep the line from wrapping. I'll try to include aliases when I mention cmdlets, but if you can't figure out what a command is referring to, remember you can always use Get-Command
to find out what is going on. For example, Get-Command
where tells you Where
is an alias for Where-Object
. In this case, select
is an alias for Select-Object
.
The execution of this pipeline can be thought of in the following sequence:
- Get the list of services
- Choose the services that have the
Running
status - Select the first five services
- Output the Name and Display Name of each one
Even though this is a single line, it shows some of the power of PowerShell. The line is very expressive, doesn't include a lot of extra syntactic baggage, and doesn't even require any variables. It also doesn't use explicit types or loops. It is a very unexceptional bit of PowerShell code, but this single line represents logic that would take several lines of code in a traditional language to express.
This isn't your DOS or Linux pipeline
DOS and Linux (and Unix, for that matter) have had pipes for a long time. Pipes in these systems work similar to how PowerShell pipes work on one level. In all of them, output is streamed from one command to the next. In other shells, though, the data being passed is simple, flat text.
For a command to use the text, it either needs to parse the text to get to the interesting bits, or it needs to treat the entire output like a blob. Since Linux and Unix use text-based configurations for most operating system functions, this makes sense. A wide range of tools to parse and find substrings is available in these systems, and scripting can be very complex.
Objects at your disposal
In Windows, however, there aren't a lot of text-based configurations. Most components are managed using the Win32 or .NET APIs. PowerShell is built upon the .NET framework and leverages the .NET object model instead of using text as the primary focus. As data in the pipeline is always in the form objects, you rarely need to parse it and can directly deal with the properties of the objects themselves. As long as the properties are named reasonably (and they usually are), you will be able to quickly get to the data you need.
Dealing with pipeline data
Since commands on the pipeline have access to object properties, several general-purpose cmdlets exist to perform common operations. Since these cmdlets can work with any kind of object, they use Object
as the noun (you remember the Verb-Noun naming convention for cmdlets, right?).
To find the list of these cmdlets, we can use the Get-Command
cmdlet:
Tip
ft
is an alias for the Format-Table
cmdlet, which I'm using here to get the display to fit more nicely on the screen. It will be covered in depth in Chapter 5, Formatting Output.
The Sort-Object
, Select-Object
, and Where-Object
cmdlets are some of the most used cmdlets in PowerShell.
The Sort-Object cmdlet
Sorting data can be interesting. Have you ever sorted a list of numbers only to find that 11 came between 1 and 2? That's because the sort that you used treated the numbers as text. Sorting dates with all the different culture-specific formatting can also be a challenge. Fortunately, PowerShell handles sorting details for you with the Sort-Object
cmdlet.
Let's look at a few examples of the Sort-Object
cmdlet before getting into the details. We'll start by sorting a directory listing by length:
Sorting this in reverse isn't difficult either.
Sorting by more than one property is a breeze as well. Here, I omitted the parameter name (-Property
) to shorten the command-line a bit:
Tip
You try it!
Use the Sort-object
cmdlet in conjunction with dir
(Get-ChildItem
), Get-Service
, or Get-Process
. Try sorting by more than one property or in reverse. Note that the dates and numbers are sorted correctly, even though the text might not be alphabetically sorted.
Looking at the brief help for the Sort-Object
cmdlet, we can see a few other parameters, such as:
-Unique
(return distinct items found in the input)-CaseSensitive
(force a case-sensitive sort)-Culture
(specify what culture to use while sorting)
As it turns out, you will probably find few occasions to use these parameters and will be fine with the –Property
and –Descending
parameters.
The Where-Object cmdlet
Another cmdlet that is extremely useful is the Where-Object cmdlet. Where-Object
is used to filter the pipeline data based on a condition that is tested for each item in the pipeline. Any object in the pipeline that causes the condition to evaluate to a true value is output from the Where-Object
cmdlet. Objects that cause the condition to evaluate to a false value are not passed on as output.
For instance, we might want to find all the files that are below 100 bytes in size in the c:\temp
directory. One way to do that is to use the simplified, or comparison syntax for Where-Object
, which was introduced in PowerShell 3.0. In this syntax, the command would look like this:
Dir c:\temp | Where-Object Length –lt 100
In this syntax, we can compare a single property of each object with a constant value. The comparison operator here is –lt
, which is how PowerShell expresses "less than".
Tip
All PowerShell comparison operators start with a dash. This can be confusing, but the <
and >
symbols have an entrenched meaning in shells, so they can't be used as operators. Common operators include -eq
, -ne
, -lt
, -gt
, -le
, -ge
, -not
, and -like
. For a full list of operators, try get-help about_operators
.
If you need to use PowerShell 1.0 or 2.0, or need to specify a condition more complex than it is allowed in the simplified syntax, you can use the general or scriptblock syntax. Expressing the same condition using this form looks as follows:
Dir c:\temp | Where-Object {$_.Length –lt 100}
This looks a lot more complicated, but it's not so bad. The construction in curly braces is called a scriptblock, and is simply a block of the PowerShell code. In the scriptblock syntax, $_
stands for the current object in the pipeline and we're referencing the Length property of that object using dot-notation. The good thing about the general syntax of Where-Object is that we can do more inside the scriptblock than simply test one condition. For instance, we could check for files below 100 bytes or those that were created after 1/1/2015, as follows:
Dir c:\temp | Where-Object {$_.Length –lt 100 –or $_.CreationTime –gt '1/1/2015'}
Here's this command running on my laptop:
If you're using PowerShell 3.0 or above and need to use the scriptblock syntax, you can substitute $_
with $PSItem
in the scriptblock. The meaning is the same and $PSItem
is a bit more readable. It makes the line slightly longer, but it's a small sacrifice to make for readability's sake.
The examples that I've shown so far, have used simple comparisons with properties, but in the scriptblock syntax, any condition can be included. Also, note that any value other than a logical false value (expressed by $false
in PowerShell), 0
, or an empty string ('') is considered to be true ($true
) in PowerShell. So, for example, we could filter objects using the Get-Member
cmdlet to only show objects that have a particular property, as follows:
Dir | where-object {$_ | get-member Length}
This will return all objects in the current directory that have a Length
property. Since files have lengths and directories don't, this is one way to get a list of files and omit the subdirectories.
Tip
You try it!
Use the Where-Object
cmdlet to find all of the *.ps
* files in $PSHOME
that are larger than 1 kilobyte in size. Remember that you can express 1kilobyte using the KB unit suffix (1KB).
The Select-Object cmdlet
The Select-Object cmdlet is a versatile cmdlet that you will find yourself using often. There are three main ways that it is used:
- Limiting the number of the objects returned
- Limiting the properties of the objects returned
- Retrieving the value of a single property of the objects in the pipeline
Limiting the number of objects returned
Sometimes, you just want to see a few of the objects that are in the pipeline. To accomplish this, you can use the -First
, -Last
, and -Skip
parameters. The -First
parameter indicates that you want to see a particular number of objects from the beginning of the list of objects in the pipeline. Similarly, the -Last
parameter selects objects from the end of the list of objects in the pipeline.
For instance, getting the first two processes in the list from Get-Process
is simple:
Since we didn't use Sort-Object
to force the order of the objects in the pipeline, we don't know that these are the first alphabetically, but they were the first two that were output from Get-Process
.
You can use –Skip
to cause a certain number of objects to be bypassed before returning the objects. It can be used by itself to output the rest of the objects after the skipped ones, or in conjunction with –First
or –Last
to return all but the beginning or end of the list of objects. As an example, -Skip
can be used to skip over header lines when reading a file using the Get-Content
cmdlet.
Limiting the properties of the objects returned
Sometimes, the objects in the pipeline have more properties than you need. To select only certain properties from the list of objects in the pipeline, you can use the –Property
parameter with a list of properties. For instance, to get only the Name
, Extension
, and Length
from the directory listing, you could do something like this:
I used the –First
parameter as well to save some space in the output, but the important thing is that we only got the three properties that we asked for.
Note that, here, the first two objects in the pipeline were directories, and directory objects don't have a length property. PowerShell provides an empty
value of $null
for missing properties like this. Also, note that these objects weren't formatted like a directory listing. We'll talk about formatting in detail in the next chapter, but for now, you should just know that these limited objects are not of the same type as the original objects, so the formatting system treated them differently.
Tip
You try it!
Use the Get-Member
cmdlet to verify that the type of the objects change slightly when you use the –Property
parameter of Select-Object
.
Retrieving the values of a single property
Sometimes, you want to get the values of a single property of a set of objects. For instance, if you wanted to get the display names of all of the services installed on your computer, you might try to do something like this:
This is close to what you were looking for, but instead of getting a bunch of names (strings), you got a bunch of objects with the DisplayName
properties. A hint that this is what happened is seen by the heading (and underline) of DisplayName
. You can also verify this using the Get-Member
cmdlet:
In order to just get the values and not objects, you need to use the –ExpandProperty
parameter. Unlike the –Property
parameter, you can only specify a single property with –ExpandProperty
, and the output is a list of raw values. Notice that with –ExpandProperty
, the column heading is gone:
We can also verify using Get-Member
that we just got strings instead of objects with a DisplayName
property:
There are a few other parameters for Select-Object
, but they will be less commonly used than the ones listed here.
The Measure-Object cmdlet
The Measure-Object cmdlet has a simple function. It calculates statistics based on the objects in the pipeline. Its most basic form takes no parameters, and simply counts the objects that are in the pipeline.
To count the files in c:\temp
and its subfolders, you could write:
Dir c:\temp –recurse –file | Measure-Object
The output shows the count, and also some other properties that give a hint about the other uses of the cmdlet. To populate these other fields, you will need to provide the name of the property that is used to calculate them and also specify which field(s) you want to calculate. The calculations are specified using the –Sum
, -Minimum
, -Maximum
, and –Average
switches.
For instance, to add up (sum) the lengths of the files in the C:\Windows
directory, you could issue this command:
Dir c:\Windows | Measure-Object –Property Length –Sum
Tip
You try it!
Use the
Measure-Object
cmdlet to find the size of the largest file on your C:
.
The Group-Object cmdlet
The Group-Object cmdlet divides the objects in the pipeline into distinct sets based on a property or a set of properties. For instance, we can categorize the files in a folder by their extensions using Group-Object like this:
You will notice in the output that PowerShell has provided the count of items in each set, the value of the property (Extension) that labels the set, and a property called Group, which contains all of the original objects that were on the pipeline that ended up in the set. If you have used the GROUP BY
clause in SQL and are used to losing the original information when you group, you'll be pleased to know that PowerShell retains those objects in their original state in the Group
property of the output.
Tip
You try it!
Can you think of a way to get the original objects out of the Group property? (Hint: one of the ways to use Select-Object
might come in handy here.)
If you don't need the objects and are simply concerned with what the counts are, you can use the –NoElement
switch, which causes the Group property to be omitted.
You're not limited to grouping by a single property either. If you want to see files grouped by mode (read-only, archive, etc.) and extension, you can simply list both properties.
Note that the Name
property of each set is now a list of two values corresponding to the two properties defining the group.
The Group-Object
cmdlet can be useful to summarize the objects, but you will probably not use it nearly as much as Sort-Object
, Where-Object
, and Select-Object
.
The Sort-Object cmdlet
Sorting data can be interesting. Have you ever sorted a list of numbers only to find that 11 came between 1 and 2? That's because the sort that you used treated the numbers as text. Sorting dates with all the different culture-specific formatting can also be a challenge. Fortunately, PowerShell handles sorting details for you with the Sort-Object
cmdlet.
Let's look at a few examples of the Sort-Object
cmdlet before getting into the details. We'll start by sorting a directory listing by length:
Sorting this in reverse isn't difficult either.
Sorting by more than one property is a breeze as well. Here, I omitted the parameter name (-Property
) to shorten the command-line a bit:
Tip
You try it!
Use the Sort-object
cmdlet in conjunction with dir
(Get-ChildItem
), Get-Service
, or Get-Process
. Try sorting by more than one property or in reverse. Note that the dates and numbers are sorted correctly, even though the text might not be alphabetically sorted.
Looking at the brief help for the Sort-Object
cmdlet, we can see a few other parameters, such as:
-Unique
(return distinct items found in the input)-CaseSensitive
(force a case-sensitive sort)-Culture
(specify what culture to use while sorting)
As it turns out, you will probably find few occasions to use these parameters and will be fine with the –Property
and –Descending
parameters.
The Where-Object cmdlet
Another cmdlet that is extremely useful is the Where-Object cmdlet. Where-Object
is used to filter the pipeline data based on a condition that is tested for each item in the pipeline. Any object in the pipeline that causes the condition to evaluate to a true value is output from the Where-Object
cmdlet. Objects that cause the condition to evaluate to a false value are not passed on as output.
For instance, we might want to find all the files that are below 100 bytes in size in the c:\temp
directory. One way to do that is to use the simplified, or comparison syntax for Where-Object
, which was introduced in PowerShell 3.0. In this syntax, the command would look like this:
Dir c:\temp | Where-Object Length –lt 100
In this syntax, we can compare a single property of each object with a constant value. The comparison operator here is –lt
, which is how PowerShell expresses "less than".
Tip
All PowerShell comparison operators start with a dash. This can be confusing, but the <
and >
symbols have an entrenched meaning in shells, so they can't be used as operators. Common operators include -eq
, -ne
, -lt
, -gt
, -le
, -ge
, -not
, and -like
. For a full list of operators, try get-help about_operators
.
If you need to use PowerShell 1.0 or 2.0, or need to specify a condition more complex than it is allowed in the simplified syntax, you can use the general or scriptblock syntax. Expressing the same condition using this form looks as follows:
Dir c:\temp | Where-Object {$_.Length –lt 100}
This looks a lot more complicated, but it's not so bad. The construction in curly braces is called a scriptblock, and is simply a block of the PowerShell code. In the scriptblock syntax, $_
stands for the current object in the pipeline and we're referencing the Length property of that object using dot-notation. The good thing about the general syntax of Where-Object is that we can do more inside the scriptblock than simply test one condition. For instance, we could check for files below 100 bytes or those that were created after 1/1/2015, as follows:
Dir c:\temp | Where-Object {$_.Length –lt 100 –or $_.CreationTime –gt '1/1/2015'}
Here's this command running on my laptop:
If you're using PowerShell 3.0 or above and need to use the scriptblock syntax, you can substitute $_
with $PSItem
in the scriptblock. The meaning is the same and $PSItem
is a bit more readable. It makes the line slightly longer, but it's a small sacrifice to make for readability's sake.
The examples that I've shown so far, have used simple comparisons with properties, but in the scriptblock syntax, any condition can be included. Also, note that any value other than a logical false value (expressed by $false
in PowerShell), 0
, or an empty string ('') is considered to be true ($true
) in PowerShell. So, for example, we could filter objects using the Get-Member
cmdlet to only show objects that have a particular property, as follows:
Dir | where-object {$_ | get-member Length}
This will return all objects in the current directory that have a Length
property. Since files have lengths and directories don't, this is one way to get a list of files and omit the subdirectories.
Tip
You try it!
Use the Where-Object
cmdlet to find all of the *.ps
* files in $PSHOME
that are larger than 1 kilobyte in size. Remember that you can express 1kilobyte using the KB unit suffix (1KB).
The Select-Object cmdlet
The Select-Object cmdlet is a versatile cmdlet that you will find yourself using often. There are three main ways that it is used:
- Limiting the number of the objects returned
- Limiting the properties of the objects returned
- Retrieving the value of a single property of the objects in the pipeline
Limiting the number of objects returned
Sometimes, you just want to see a few of the objects that are in the pipeline. To accomplish this, you can use the -First
, -Last
, and -Skip
parameters. The -First
parameter indicates that you want to see a particular number of objects from the beginning of the list of objects in the pipeline. Similarly, the -Last
parameter selects objects from the end of the list of objects in the pipeline.
For instance, getting the first two processes in the list from Get-Process
is simple:
Since we didn't use Sort-Object
to force the order of the objects in the pipeline, we don't know that these are the first alphabetically, but they were the first two that were output from Get-Process
.
You can use –Skip
to cause a certain number of objects to be bypassed before returning the objects. It can be used by itself to output the rest of the objects after the skipped ones, or in conjunction with –First
or –Last
to return all but the beginning or end of the list of objects. As an example, -Skip
can be used to skip over header lines when reading a file using the Get-Content
cmdlet.
Limiting the properties of the objects returned
Sometimes, the objects in the pipeline have more properties than you need. To select only certain properties from the list of objects in the pipeline, you can use the –Property
parameter with a list of properties. For instance, to get only the Name
, Extension
, and Length
from the directory listing, you could do something like this:
I used the –First
parameter as well to save some space in the output, but the important thing is that we only got the three properties that we asked for.
Note that, here, the first two objects in the pipeline were directories, and directory objects don't have a length property. PowerShell provides an empty
value of $null
for missing properties like this. Also, note that these objects weren't formatted like a directory listing. We'll talk about formatting in detail in the next chapter, but for now, you should just know that these limited objects are not of the same type as the original objects, so the formatting system treated them differently.
Tip
You try it!
Use the Get-Member
cmdlet to verify that the type of the objects change slightly when you use the –Property
parameter of Select-Object
.
Retrieving the values of a single property
Sometimes, you want to get the values of a single property of a set of objects. For instance, if you wanted to get the display names of all of the services installed on your computer, you might try to do something like this:
This is close to what you were looking for, but instead of getting a bunch of names (strings), you got a bunch of objects with the DisplayName
properties. A hint that this is what happened is seen by the heading (and underline) of DisplayName
. You can also verify this using the Get-Member
cmdlet:
In order to just get the values and not objects, you need to use the –ExpandProperty
parameter. Unlike the –Property
parameter, you can only specify a single property with –ExpandProperty
, and the output is a list of raw values. Notice that with –ExpandProperty
, the column heading is gone:
We can also verify using Get-Member
that we just got strings instead of objects with a DisplayName
property:
There are a few other parameters for Select-Object
, but they will be less commonly used than the ones listed here.
The Measure-Object cmdlet
The Measure-Object cmdlet has a simple function. It calculates statistics based on the objects in the pipeline. Its most basic form takes no parameters, and simply counts the objects that are in the pipeline.
To count the files in c:\temp
and its subfolders, you could write:
Dir c:\temp –recurse –file | Measure-Object
The output shows the count, and also some other properties that give a hint about the other uses of the cmdlet. To populate these other fields, you will need to provide the name of the property that is used to calculate them and also specify which field(s) you want to calculate. The calculations are specified using the –Sum
, -Minimum
, -Maximum
, and –Average
switches.
For instance, to add up (sum) the lengths of the files in the C:\Windows
directory, you could issue this command:
Dir c:\Windows | Measure-Object –Property Length –Sum
Tip
You try it!
Use the
Measure-Object
cmdlet to find the size of the largest file on your C:
.
The Group-Object cmdlet
The Group-Object cmdlet divides the objects in the pipeline into distinct sets based on a property or a set of properties. For instance, we can categorize the files in a folder by their extensions using Group-Object like this:
You will notice in the output that PowerShell has provided the count of items in each set, the value of the property (Extension) that labels the set, and a property called Group, which contains all of the original objects that were on the pipeline that ended up in the set. If you have used the GROUP BY
clause in SQL and are used to losing the original information when you group, you'll be pleased to know that PowerShell retains those objects in their original state in the Group
property of the output.
Tip
You try it!
Can you think of a way to get the original objects out of the Group property? (Hint: one of the ways to use Select-Object
might come in handy here.)
If you don't need the objects and are simply concerned with what the counts are, you can use the –NoElement
switch, which causes the Group property to be omitted.
You're not limited to grouping by a single property either. If you want to see files grouped by mode (read-only, archive, etc.) and extension, you can simply list both properties.
Note that the Name
property of each set is now a list of two values corresponding to the two properties defining the group.
The Group-Object
cmdlet can be useful to summarize the objects, but you will probably not use it nearly as much as Sort-Object
, Where-Object
, and Select-Object
.
The Where-Object cmdlet
Another cmdlet that is extremely useful is the Where-Object cmdlet. Where-Object
is used to filter the pipeline data based on a condition that is tested for each item in the pipeline. Any object in the pipeline that causes the condition to evaluate to a true value is output from the Where-Object
cmdlet. Objects that cause the condition to evaluate to a false value are not passed on as output.
For instance, we might want to find all the files that are below 100 bytes in size in the c:\temp
directory. One way to do that is to use the simplified, or comparison syntax for Where-Object
, which was introduced in PowerShell 3.0. In this syntax, the command would look like this:
Dir c:\temp | Where-Object Length –lt 100
In this syntax, we can compare a single property of each object with a constant value. The comparison operator here is –lt
, which is how PowerShell expresses "less than".
Tip
All PowerShell comparison operators start with a dash. This can be confusing, but the <
and >
symbols have an entrenched meaning in shells, so they can't be used as operators. Common operators include -eq
, -ne
, -lt
, -gt
, -le
, -ge
, -not
, and -like
. For a full list of operators, try get-help about_operators
.
If you need to use PowerShell 1.0 or 2.0, or need to specify a condition more complex than it is allowed in the simplified syntax, you can use the general or scriptblock syntax. Expressing the same condition using this form looks as follows:
Dir c:\temp | Where-Object {$_.Length –lt 100}
This looks a lot more complicated, but it's not so bad. The construction in curly braces is called a scriptblock, and is simply a block of the PowerShell code. In the scriptblock syntax, $_
stands for the current object in the pipeline and we're referencing the Length property of that object using dot-notation. The good thing about the general syntax of Where-Object is that we can do more inside the scriptblock than simply test one condition. For instance, we could check for files below 100 bytes or those that were created after 1/1/2015, as follows:
Dir c:\temp | Where-Object {$_.Length –lt 100 –or $_.CreationTime –gt '1/1/2015'}
Here's this command running on my laptop:
If you're using PowerShell 3.0 or above and need to use the scriptblock syntax, you can substitute $_
with $PSItem
in the scriptblock. The meaning is the same and $PSItem
is a bit more readable. It makes the line slightly longer, but it's a small sacrifice to make for readability's sake.
The examples that I've shown so far, have used simple comparisons with properties, but in the scriptblock syntax, any condition can be included. Also, note that any value other than a logical false value (expressed by $false
in PowerShell), 0
, or an empty string ('') is considered to be true ($true
) in PowerShell. So, for example, we could filter objects using the Get-Member
cmdlet to only show objects that have a particular property, as follows:
Dir | where-object {$_ | get-member Length}
This will return all objects in the current directory that have a Length
property. Since files have lengths and directories don't, this is one way to get a list of files and omit the subdirectories.
Tip
You try it!
Use the Where-Object
cmdlet to find all of the *.ps
* files in $PSHOME
that are larger than 1 kilobyte in size. Remember that you can express 1kilobyte using the KB unit suffix (1KB).
The Select-Object cmdlet
The Select-Object cmdlet is a versatile cmdlet that you will find yourself using often. There are three main ways that it is used:
- Limiting the number of the objects returned
- Limiting the properties of the objects returned
- Retrieving the value of a single property of the objects in the pipeline
Limiting the number of objects returned
Sometimes, you just want to see a few of the objects that are in the pipeline. To accomplish this, you can use the -First
, -Last
, and -Skip
parameters. The -First
parameter indicates that you want to see a particular number of objects from the beginning of the list of objects in the pipeline. Similarly, the -Last
parameter selects objects from the end of the list of objects in the pipeline.
For instance, getting the first two processes in the list from Get-Process
is simple:
Since we didn't use Sort-Object
to force the order of the objects in the pipeline, we don't know that these are the first alphabetically, but they were the first two that were output from Get-Process
.
You can use –Skip
to cause a certain number of objects to be bypassed before returning the objects. It can be used by itself to output the rest of the objects after the skipped ones, or in conjunction with –First
or –Last
to return all but the beginning or end of the list of objects. As an example, -Skip
can be used to skip over header lines when reading a file using the Get-Content
cmdlet.
Limiting the properties of the objects returned
Sometimes, the objects in the pipeline have more properties than you need. To select only certain properties from the list of objects in the pipeline, you can use the –Property
parameter with a list of properties. For instance, to get only the Name
, Extension
, and Length
from the directory listing, you could do something like this:
I used the –First
parameter as well to save some space in the output, but the important thing is that we only got the three properties that we asked for.
Note that, here, the first two objects in the pipeline were directories, and directory objects don't have a length property. PowerShell provides an empty
value of $null
for missing properties like this. Also, note that these objects weren't formatted like a directory listing. We'll talk about formatting in detail in the next chapter, but for now, you should just know that these limited objects are not of the same type as the original objects, so the formatting system treated them differently.
Tip
You try it!
Use the Get-Member
cmdlet to verify that the type of the objects change slightly when you use the –Property
parameter of Select-Object
.
Retrieving the values of a single property
Sometimes, you want to get the values of a single property of a set of objects. For instance, if you wanted to get the display names of all of the services installed on your computer, you might try to do something like this:
This is close to what you were looking for, but instead of getting a bunch of names (strings), you got a bunch of objects with the DisplayName
properties. A hint that this is what happened is seen by the heading (and underline) of DisplayName
. You can also verify this using the Get-Member
cmdlet:
In order to just get the values and not objects, you need to use the –ExpandProperty
parameter. Unlike the –Property
parameter, you can only specify a single property with –ExpandProperty
, and the output is a list of raw values. Notice that with –ExpandProperty
, the column heading is gone:
We can also verify using Get-Member
that we just got strings instead of objects with a DisplayName
property:
There are a few other parameters for Select-Object
, but they will be less commonly used than the ones listed here.
The Measure-Object cmdlet
The Measure-Object cmdlet has a simple function. It calculates statistics based on the objects in the pipeline. Its most basic form takes no parameters, and simply counts the objects that are in the pipeline.
To count the files in c:\temp
and its subfolders, you could write:
Dir c:\temp –recurse –file | Measure-Object
The output shows the count, and also some other properties that give a hint about the other uses of the cmdlet. To populate these other fields, you will need to provide the name of the property that is used to calculate them and also specify which field(s) you want to calculate. The calculations are specified using the –Sum
, -Minimum
, -Maximum
, and –Average
switches.
For instance, to add up (sum) the lengths of the files in the C:\Windows
directory, you could issue this command:
Dir c:\Windows | Measure-Object –Property Length –Sum
Tip
You try it!
Use the
Measure-Object
cmdlet to find the size of the largest file on your C:
.
The Group-Object cmdlet
The Group-Object cmdlet divides the objects in the pipeline into distinct sets based on a property or a set of properties. For instance, we can categorize the files in a folder by their extensions using Group-Object like this:
You will notice in the output that PowerShell has provided the count of items in each set, the value of the property (Extension) that labels the set, and a property called Group, which contains all of the original objects that were on the pipeline that ended up in the set. If you have used the GROUP BY
clause in SQL and are used to losing the original information when you group, you'll be pleased to know that PowerShell retains those objects in their original state in the Group
property of the output.
Tip
You try it!
Can you think of a way to get the original objects out of the Group property? (Hint: one of the ways to use Select-Object
might come in handy here.)
If you don't need the objects and are simply concerned with what the counts are, you can use the –NoElement
switch, which causes the Group property to be omitted.
You're not limited to grouping by a single property either. If you want to see files grouped by mode (read-only, archive, etc.) and extension, you can simply list both properties.
Note that the Name
property of each set is now a list of two values corresponding to the two properties defining the group.
The Group-Object
cmdlet can be useful to summarize the objects, but you will probably not use it nearly as much as Sort-Object
, Where-Object
, and Select-Object
.
The Select-Object cmdlet
The Select-Object cmdlet is a versatile cmdlet that you will find yourself using often. There are three main ways that it is used:
- Limiting the number of the objects returned
- Limiting the properties of the objects returned
- Retrieving the value of a single property of the objects in the pipeline
Limiting the number of objects returned
Sometimes, you just want to see a few of the objects that are in the pipeline. To accomplish this, you can use the -First
, -Last
, and -Skip
parameters. The -First
parameter indicates that you want to see a particular number of objects from the beginning of the list of objects in the pipeline. Similarly, the -Last
parameter selects objects from the end of the list of objects in the pipeline.
For instance, getting the first two processes in the list from Get-Process
is simple:
Since we didn't use Sort-Object
to force the order of the objects in the pipeline, we don't know that these are the first alphabetically, but they were the first two that were output from Get-Process
.
You can use –Skip
to cause a certain number of objects to be bypassed before returning the objects. It can be used by itself to output the rest of the objects after the skipped ones, or in conjunction with –First
or –Last
to return all but the beginning or end of the list of objects. As an example, -Skip
can be used to skip over header lines when reading a file using the Get-Content
cmdlet.
Limiting the properties of the objects returned
Sometimes, the objects in the pipeline have more properties than you need. To select only certain properties from the list of objects in the pipeline, you can use the –Property
parameter with a list of properties. For instance, to get only the Name
, Extension
, and Length
from the directory listing, you could do something like this:
I used the –First
parameter as well to save some space in the output, but the important thing is that we only got the three properties that we asked for.
Note that, here, the first two objects in the pipeline were directories, and directory objects don't have a length property. PowerShell provides an empty
value of $null
for missing properties like this. Also, note that these objects weren't formatted like a directory listing. We'll talk about formatting in detail in the next chapter, but for now, you should just know that these limited objects are not of the same type as the original objects, so the formatting system treated them differently.
Tip
You try it!
Use the Get-Member
cmdlet to verify that the type of the objects change slightly when you use the –Property
parameter of Select-Object
.
Retrieving the values of a single property
Sometimes, you want to get the values of a single property of a set of objects. For instance, if you wanted to get the display names of all of the services installed on your computer, you might try to do something like this:
This is close to what you were looking for, but instead of getting a bunch of names (strings), you got a bunch of objects with the DisplayName
properties. A hint that this is what happened is seen by the heading (and underline) of DisplayName
. You can also verify this using the Get-Member
cmdlet:
In order to just get the values and not objects, you need to use the –ExpandProperty
parameter. Unlike the –Property
parameter, you can only specify a single property with –ExpandProperty
, and the output is a list of raw values. Notice that with –ExpandProperty
, the column heading is gone:
We can also verify using Get-Member
that we just got strings instead of objects with a DisplayName
property:
There are a few other parameters for Select-Object
, but they will be less commonly used than the ones listed here.
The Measure-Object cmdlet
The Measure-Object cmdlet has a simple function. It calculates statistics based on the objects in the pipeline. Its most basic form takes no parameters, and simply counts the objects that are in the pipeline.
To count the files in c:\temp
and its subfolders, you could write:
Dir c:\temp –recurse –file | Measure-Object
The output shows the count, and also some other properties that give a hint about the other uses of the cmdlet. To populate these other fields, you will need to provide the name of the property that is used to calculate them and also specify which field(s) you want to calculate. The calculations are specified using the –Sum
, -Minimum
, -Maximum
, and –Average
switches.
For instance, to add up (sum) the lengths of the files in the C:\Windows
directory, you could issue this command:
Dir c:\Windows | Measure-Object –Property Length –Sum
Tip
You try it!
Use the
Measure-Object
cmdlet to find the size of the largest file on your C:
.
The Group-Object cmdlet
The Group-Object cmdlet divides the objects in the pipeline into distinct sets based on a property or a set of properties. For instance, we can categorize the files in a folder by their extensions using Group-Object like this:
You will notice in the output that PowerShell has provided the count of items in each set, the value of the property (Extension) that labels the set, and a property called Group, which contains all of the original objects that were on the pipeline that ended up in the set. If you have used the GROUP BY
clause in SQL and are used to losing the original information when you group, you'll be pleased to know that PowerShell retains those objects in their original state in the Group
property of the output.
Tip
You try it!
Can you think of a way to get the original objects out of the Group property? (Hint: one of the ways to use Select-Object
might come in handy here.)
If you don't need the objects and are simply concerned with what the counts are, you can use the –NoElement
switch, which causes the Group property to be omitted.
You're not limited to grouping by a single property either. If you want to see files grouped by mode (read-only, archive, etc.) and extension, you can simply list both properties.
Note that the Name
property of each set is now a list of two values corresponding to the two properties defining the group.
The Group-Object
cmdlet can be useful to summarize the objects, but you will probably not use it nearly as much as Sort-Object
, Where-Object
, and Select-Object
.
Limiting the number of objects returned
Sometimes, you just want to see a few of the objects that are in the pipeline. To accomplish this, you can use the -First
, -Last
, and -Skip
parameters. The -First
parameter indicates that you want to see a particular number of objects from the beginning of the list of objects in the pipeline. Similarly, the -Last
parameter selects objects from the end of the list of objects in the pipeline.
For instance, getting the first two processes in the list from Get-Process
is simple:
Since we didn't use Sort-Object
to force the order of the objects in the pipeline, we don't know that these are the first alphabetically, but they were the first two that were output from Get-Process
.
You can use –Skip
to cause a certain number of objects to be bypassed before returning the objects. It can be used by itself to output the rest of the objects after the skipped ones, or in conjunction with –First
or –Last
to return all but the beginning or end of the list of objects. As an example, -Skip
can be used to skip over header lines when reading a file using the Get-Content
cmdlet.
Limiting the properties of the objects returned
Sometimes, the objects in the pipeline have more properties than you need. To select only certain properties from the list of objects in the pipeline, you can use the –Property
parameter with a list of properties. For instance, to get only the Name
, Extension
, and Length
from the directory listing, you could do something like this:
I used the –First
parameter as well to save some space in the output, but the important thing is that we only got the three properties that we asked for.
Note that, here, the first two objects in the pipeline were directories, and directory objects don't have a length property. PowerShell provides an empty
value of $null
for missing properties like this. Also, note that these objects weren't formatted like a directory listing. We'll talk about formatting in detail in the next chapter, but for now, you should just know that these limited objects are not of the same type as the original objects, so the formatting system treated them differently.
Tip
You try it!
Use the Get-Member
cmdlet to verify that the type of the objects change slightly when you use the –Property
parameter of Select-Object
.
Retrieving the values of a single property
Sometimes, you want to get the values of a single property of a set of objects. For instance, if you wanted to get the display names of all of the services installed on your computer, you might try to do something like this:
This is close to what you were looking for, but instead of getting a bunch of names (strings), you got a bunch of objects with the DisplayName
properties. A hint that this is what happened is seen by the heading (and underline) of DisplayName
. You can also verify this using the Get-Member
cmdlet:
In order to just get the values and not objects, you need to use the –ExpandProperty
parameter. Unlike the –Property
parameter, you can only specify a single property with –ExpandProperty
, and the output is a list of raw values. Notice that with –ExpandProperty
, the column heading is gone:
We can also verify using Get-Member
that we just got strings instead of objects with a DisplayName
property:
There are a few other parameters for Select-Object
, but they will be less commonly used than the ones listed here.
The Measure-Object cmdlet has a simple function. It calculates statistics based on the objects in the pipeline. Its most basic form takes no parameters, and simply counts the objects that are in the pipeline.
To count the files in c:\temp
and its subfolders, you could write:
Dir c:\temp –recurse –file | Measure-Object
The output shows the count, and also some other properties that give a hint about the other uses of the cmdlet. To populate these other fields, you will need to provide the name of the property that is used to calculate them and also specify which field(s) you want to calculate. The calculations are specified using the –Sum
, -Minimum
, -Maximum
, and –Average
switches.
For instance, to add up (sum) the lengths of the files in the C:\Windows
directory, you could issue this command:
Dir c:\Windows | Measure-Object –Property Length –Sum
Tip
You try it!
Use the
Measure-Object
cmdlet to find the size of the largest file on your C:
.
The Group-Object cmdlet divides the objects in the pipeline into distinct sets based on a property or a set of properties. For instance, we can categorize the files in a folder by their extensions using Group-Object like this:
You will notice in the output that PowerShell has provided the count of items in each set, the value of the property (Extension) that labels the set, and a property called Group, which contains all of the original objects that were on the pipeline that ended up in the set. If you have used the GROUP BY
clause in SQL and are used to losing the original information when you group, you'll be pleased to know that PowerShell retains those objects in their original state in the Group
property of the output.
Tip
You try it!
Can you think of a way to get the original objects out of the Group property? (Hint: one of the ways to use Select-Object
might come in handy here.)
If you don't need the objects and are simply concerned with what the counts are, you can use the –NoElement
switch, which causes the Group property to be omitted.
You're not limited to grouping by a single property either. If you want to see files grouped by mode (read-only, archive, etc.) and extension, you can simply list both properties.
Note that the Name
property of each set is now a list of two values corresponding to the two properties defining the group.
The Group-Object
cmdlet can be useful to summarize the objects, but you will probably not use it nearly as much as Sort-Object
, Where-Object
, and Select-Object
.
Limiting the properties of the objects returned
Sometimes, the objects in the pipeline have more properties than you need. To select only certain properties from the list of objects in the pipeline, you can use the –Property
parameter with a list of properties. For instance, to get only the Name
, Extension
, and Length
from the directory listing, you could do something like this:
I used the –First
parameter as well to save some space in the output, but the important thing is that we only got the three properties that we asked for.
Note that, here, the first two objects in the pipeline were directories, and directory objects don't have a length property. PowerShell provides an empty
value of $null
for missing properties like this. Also, note that these objects weren't formatted like a directory listing. We'll talk about formatting in detail in the next chapter, but for now, you should just know that these limited objects are not of the same type as the original objects, so the formatting system treated them differently.
Tip
You try it!
Use the Get-Member
cmdlet to verify that the type of the objects change slightly when you use the –Property
parameter of Select-Object
.
Retrieving the values of a single property
Sometimes, you want to get the values of a single property of a set of objects. For instance, if you wanted to get the display names of all of the services installed on your computer, you might try to do something like this:
This is close to what you were looking for, but instead of getting a bunch of names (strings), you got a bunch of objects with the DisplayName
properties. A hint that this is what happened is seen by the heading (and underline) of DisplayName
. You can also verify this using the Get-Member
cmdlet:
In order to just get the values and not objects, you need to use the –ExpandProperty
parameter. Unlike the –Property
parameter, you can only specify a single property with –ExpandProperty
, and the output is a list of raw values. Notice that with –ExpandProperty
, the column heading is gone:
We can also verify using Get-Member
that we just got strings instead of objects with a DisplayName
property:
There are a few other parameters for Select-Object
, but they will be less commonly used than the ones listed here.
The Measure-Object cmdlet has a simple function. It calculates statistics based on the objects in the pipeline. Its most basic form takes no parameters, and simply counts the objects that are in the pipeline.
To count the files in c:\temp
and its subfolders, you could write:
Dir c:\temp –recurse –file | Measure-Object
The output shows the count, and also some other properties that give a hint about the other uses of the cmdlet. To populate these other fields, you will need to provide the name of the property that is used to calculate them and also specify which field(s) you want to calculate. The calculations are specified using the –Sum
, -Minimum
, -Maximum
, and –Average
switches.
For instance, to add up (sum) the lengths of the files in the C:\Windows
directory, you could issue this command:
Dir c:\Windows | Measure-Object –Property Length –Sum
Tip
You try it!
Use the
Measure-Object
cmdlet to find the size of the largest file on your C:
.
The Group-Object cmdlet divides the objects in the pipeline into distinct sets based on a property or a set of properties. For instance, we can categorize the files in a folder by their extensions using Group-Object like this:
You will notice in the output that PowerShell has provided the count of items in each set, the value of the property (Extension) that labels the set, and a property called Group, which contains all of the original objects that were on the pipeline that ended up in the set. If you have used the GROUP BY
clause in SQL and are used to losing the original information when you group, you'll be pleased to know that PowerShell retains those objects in their original state in the Group
property of the output.
Tip
You try it!
Can you think of a way to get the original objects out of the Group property? (Hint: one of the ways to use Select-Object
might come in handy here.)
If you don't need the objects and are simply concerned with what the counts are, you can use the –NoElement
switch, which causes the Group property to be omitted.
You're not limited to grouping by a single property either. If you want to see files grouped by mode (read-only, archive, etc.) and extension, you can simply list both properties.
Note that the Name
property of each set is now a list of two values corresponding to the two properties defining the group.
The Group-Object
cmdlet can be useful to summarize the objects, but you will probably not use it nearly as much as Sort-Object
, Where-Object
, and Select-Object
.
Retrieving the values of a single property
Sometimes, you want to get the values of a single property of a set of objects. For instance, if you wanted to get the display names of all of the services installed on your computer, you might try to do something like this:
This is close to what you were looking for, but instead of getting a bunch of names (strings), you got a bunch of objects with the DisplayName
properties. A hint that this is what happened is seen by the heading (and underline) of DisplayName
. You can also verify this using the Get-Member
cmdlet:
In order to just get the values and not objects, you need to use the –ExpandProperty
parameter. Unlike the –Property
parameter, you can only specify a single property with –ExpandProperty
, and the output is a list of raw values. Notice that with –ExpandProperty
, the column heading is gone:
We can also verify using Get-Member
that we just got strings instead of objects with a DisplayName
property:
There are a few other parameters for Select-Object
, but they will be less commonly used than the ones listed here.
The Measure-Object cmdlet has a simple function. It calculates statistics based on the objects in the pipeline. Its most basic form takes no parameters, and simply counts the objects that are in the pipeline.
To count the files in c:\temp
and its subfolders, you could write:
Dir c:\temp –recurse –file | Measure-Object
The output shows the count, and also some other properties that give a hint about the other uses of the cmdlet. To populate these other fields, you will need to provide the name of the property that is used to calculate them and also specify which field(s) you want to calculate. The calculations are specified using the –Sum
, -Minimum
, -Maximum
, and –Average
switches.
For instance, to add up (sum) the lengths of the files in the C:\Windows
directory, you could issue this command:
Dir c:\Windows | Measure-Object –Property Length –Sum
Tip
You try it!
Use the
Measure-Object
cmdlet to find the size of the largest file on your C:
.
The Group-Object cmdlet divides the objects in the pipeline into distinct sets based on a property or a set of properties. For instance, we can categorize the files in a folder by their extensions using Group-Object like this:
You will notice in the output that PowerShell has provided the count of items in each set, the value of the property (Extension) that labels the set, and a property called Group, which contains all of the original objects that were on the pipeline that ended up in the set. If you have used the GROUP BY
clause in SQL and are used to losing the original information when you group, you'll be pleased to know that PowerShell retains those objects in their original state in the Group
property of the output.
Tip
You try it!
Can you think of a way to get the original objects out of the Group property? (Hint: one of the ways to use Select-Object
might come in handy here.)
If you don't need the objects and are simply concerned with what the counts are, you can use the –NoElement
switch, which causes the Group property to be omitted.
You're not limited to grouping by a single property either. If you want to see files grouped by mode (read-only, archive, etc.) and extension, you can simply list both properties.
Note that the Name
property of each set is now a list of two values corresponding to the two properties defining the group.
The Group-Object
cmdlet can be useful to summarize the objects, but you will probably not use it nearly as much as Sort-Object
, Where-Object
, and Select-Object
.
The Measure-Object cmdlet
The Measure-Object cmdlet has a simple function. It calculates statistics based on the objects in the pipeline. Its most basic form takes no parameters, and simply counts the objects that are in the pipeline.
To count the files in c:\temp
and its subfolders, you could write:
Dir c:\temp –recurse –file | Measure-Object
The output shows the count, and also some other properties that give a hint about the other uses of the cmdlet. To populate these other fields, you will need to provide the name of the property that is used to calculate them and also specify which field(s) you want to calculate. The calculations are specified using the –Sum
, -Minimum
, -Maximum
, and –Average
switches.
For instance, to add up (sum) the lengths of the files in the C:\Windows
directory, you could issue this command:
Dir c:\Windows | Measure-Object –Property Length –Sum
Tip
You try it!
Use the
Measure-Object
cmdlet to find the size of the largest file on your C:
.
The Group-Object cmdlet
The Group-Object cmdlet divides the objects in the pipeline into distinct sets based on a property or a set of properties. For instance, we can categorize the files in a folder by their extensions using Group-Object like this:
You will notice in the output that PowerShell has provided the count of items in each set, the value of the property (Extension) that labels the set, and a property called Group, which contains all of the original objects that were on the pipeline that ended up in the set. If you have used the GROUP BY
clause in SQL and are used to losing the original information when you group, you'll be pleased to know that PowerShell retains those objects in their original state in the Group
property of the output.
Tip
You try it!
Can you think of a way to get the original objects out of the Group property? (Hint: one of the ways to use Select-Object
might come in handy here.)
If you don't need the objects and are simply concerned with what the counts are, you can use the –NoElement
switch, which causes the Group property to be omitted.
You're not limited to grouping by a single property either. If you want to see files grouped by mode (read-only, archive, etc.) and extension, you can simply list both properties.
Note that the Name
property of each set is now a list of two values corresponding to the two properties defining the group.
The Group-Object
cmdlet can be useful to summarize the objects, but you will probably not use it nearly as much as Sort-Object
, Where-Object
, and Select-Object
.
The Group-Object cmdlet
The Group-Object cmdlet divides the objects in the pipeline into distinct sets based on a property or a set of properties. For instance, we can categorize the files in a folder by their extensions using Group-Object like this:
You will notice in the output that PowerShell has provided the count of items in each set, the value of the property (Extension) that labels the set, and a property called Group, which contains all of the original objects that were on the pipeline that ended up in the set. If you have used the GROUP BY
clause in SQL and are used to losing the original information when you group, you'll be pleased to know that PowerShell retains those objects in their original state in the Group
property of the output.
Tip
You try it!
Can you think of a way to get the original objects out of the Group property? (Hint: one of the ways to use Select-Object
might come in handy here.)
If you don't need the objects and are simply concerned with what the counts are, you can use the –NoElement
switch, which causes the Group property to be omitted.
You're not limited to grouping by a single property either. If you want to see files grouped by mode (read-only, archive, etc.) and extension, you can simply list both properties.
Note that the Name
property of each set is now a list of two values corresponding to the two properties defining the group.
The Group-Object
cmdlet can be useful to summarize the objects, but you will probably not use it nearly as much as Sort-Object
, Where-Object
, and Select-Object
.
Putting them together
The several *-Object
cmdlets that we've discussed in this chapter will be the foundation to your experience with PowerShell. Although, we only used them with Dir
, Get-Service
, and Get-Process
, this is only because I can be sure that you can use these cmdlets on any system. The way that you use the *-Object
cmdlets is the same whether you're dealing with files and folders, virtual machines, or mailboxes in Exchange. Since PowerShell gives you objects in all of these situations, these cmdlets will enable you to manipulate them using the same techniques.
Here are a couple of concrete examples of how the methods of using these cmdlets are portable between the types of objects. First, to get the largest five files in the c:\Windows
folder, you would do this:
Dir c:\Windows | Sort-Object –Property Length –Descending | Select-Object –First 5
Similarly, getting the five processes that are using the most file handles would look like this:
Get-Process | Sort-Object –Property Handles –Descending | Select-Object –First 5
Can you see that the methodology to solve these two problems is exactly the same? Can you think of other problems that you might solve using a similar approach?
Tip
You Try it!
Use the cmdlets in this chapter to find the five newest files on your C: drive
(use the LastWriteTime
property to determine the age).
Summary
In this chapter, we looked at how to use the pipeline in PowerShell and several of the cmdlets that deal with objects in general. Once you learn to use these cmdlets efficiently, you will be able to solve all kinds of interesting problems in many areas.
In the next chapter, we will investigate PowerShell's versatile formatting system and learn how to format output in different ways.
For further reading
Get-Help about_pipelines
Get-Help Sort-Object
Get-Help Where-Object
Get-Help Select-Object
Get-Help Group-Object
Get-Help about_comparison_operators
Get-Help about_scriptblocks