When you run a command in Windows PowerShell, objects are written to the pipeline and possibly even passed from one cmdlet or function to the next. If there are any objects left in the pipeline at the end, PowerShell displays them. But sometimes the display is less than optimal. To overcome this, you'll need to take control of PowerShell's formatting system.
How Formatting Works
Without getting too deep into the technical details, here's how PowerShell handles formatting: At the end of the pipeline, PowerShell looks at the remaining objects and determines their types. PowerShell then looks through a set of XML configuration files for instructions on how to format each specific object type. It might see a default display for a table or list. If so, PowerShell passes the objects to the appropriate formatting cmdlet, which displays the results on screen. Or PowerShell might only find a default list of properties. Depending on the number of properties, PowerShell will decide if it needs a table or a list and again call the appropriate formatting cmdlet. As a last resort, if no instructions are found, PowerShell will display all object properties.
You can override this formatting system by explicitly running the formatting cmdlets. The formatting cmdlets that you're most likely to use are Format-Wide, Format-Table, and Format-List.
How to Use the Format-Wide Cmdlet
The Format-Wide cmdlet, which has an alias of fw, will display a single property in wide format. In the Windows Cmd.exe shell, you might have used a command like dir /w to see a wide directory listing. Format-Wide provides the same type of display for any object type. For example, the following command displays the results from the Get-Process cmdlet in wide format:
You can see the results in Figure 1.
With Format-Wide, most object types have a defined default property, which is usually a name. However, you can specify a different property. For example, instead of displaying service names in wide format, you can display the DisplayName property in wide format by using the command:
Format-Wide -Property DisplayName
Format-Wide usually does a good job of maximizing the display, but you can fine tune it if you want. For example, when Get-Process was piped to Format-Wide in the first example, the results were in two columns, as shown in Figure 1. You can force Format-Wide to use more columns using the -Column parameter:
Now the results are in three columns, as Figure 2 shows.
You can force Format-Wide to squeeze as much as it can into the display using the -AutoSize parameter. For example, the following command returns services that start with the letter m, maximizing the amount of data displayed:
Notice that in this instance, I'm using the alias fw. Figure 3 shows the results.
You might want to combine the auto-size feature with the grouping feature of Format-Wide. When using the -GroupBy parameter, PowerShell will format the output in groups based on a specified property. But be careful. Look at this command:
You might think that this command will get the services, then display them in wide format grouped by the Status property. But look at the result in Figure 4.
It's probably not what you expected. PowerShell took the incoming service objects and formatted them as they arrived. This problem is easily solved by sorting first with the Sort-Object cmdlet, which has an alias of sort:
This command returns only those services starting with the letter w so that you can see all the results, which are shown in Figure 5. In the results, notice that the stopped services are displayed using five columns and the running services are displayed using only four columns. Auto-sizing results will vary depending on the length of each property value.
The -GroupBy parameter is supported by all the formatting cmdlets. The -AutoSize parameter is supported by Format-Wide as well as Format-Table, which I'll discuss next.
How to Use the Format-Table Cmdlet
As its name suggests, the Format-Table cmdlet, which has an alias of ft, formats output as a table. Formatting results as a table is commonly done by administrators, and PowerShell even does it by default in some cases. For example, running
produces the same results as running
As I mentioned in the "How Formatting Works" section, PowerShell uses a set of configuration files to determine what to display and how. Some object types have predefined formatted outputs. In this case, the configuration files tell PowerShell to format the process objects as a table. In theory, this means that you don't need to include the Format-Table cmdlet when using Get-Process if you want the results formatted in a table. However, how many times have you run a command only to find that the output isn't exactly optimal? Take, for example, the following command that uses the Select-Object cmdlet, which has an alias of select, to return the ID, Name, and WorkingSet (WS) properties:
As you can see in Figure 6, the output is in a table, but the columns' size and placement aren't ideal.
PowerShell did the best job it could, but selecting properties isn't the same as formatting them. You can help by piping the results to the Format-Table cmdlet with the -AutoSize parameter to force PowerShell to auto-size the results in the table:
As Figure 7 shows, the output is nicer.
If you know from the beginning that you want the output to be formatted in a table, you can skip the Select-Object step and simply specify the properties when calling Format-Table:
This will produce the same output. If all you want to do is look at the results, this is perfectly fine. But there's something about formatting that trips up many PowerShell beginners, which I'll discuss in a bit.
Besides -AutoSize, another Format-Table parameter that you'll probably use often is the -View parameter. A view is an alternative layout. Using the -View parameter tells PowerShell to use one of the alternative displays. For example, if you run the following command, you'll get a different set of properties automatically grouped by the PriorityClass property:
Notice that I used the alias ft, which you'll probably end up using a lot. Also notice that I sorted first to improve the display output, just as I did when grouping earlier with Format-Wide. Figure 8 should give you an idea of what to expect. You might get errors because some processes like Idle and System are protected. You can ignore the errors.
Here's another example I'll leave for you to try:
Like the previous command, this command might generate errors because some processes won't have start times.
Discovering alternative views takes a little detective work. First, you use the Get-Member cmdlet to find the object type. In the case of the last Get-Process example, you'd run:
The results show that the object type is System.Diagnostics.Process. Then, you run the following command to expand the definition property:
Select -ExpandProperty FormatViewDefinition
In the results shown in Figure 9, the Name column contains the view names. The Control column gives you a hint about what formatting cmdlet to use to see the corresponding view. Note that you won't necessarily see views for every object type, so you might still need to do a lot of manual testing.
How to Use the Format-List Cmdlet
Another common way to format output is a list. You can force PowerShell to output a list by using the Format-List cmdlet, which has an alias of fl. For example, if you run the following command, you'll find that PowerShell formats the results as a table:
If you'd rather have the output formatted as a list, you can pipe the results to Format-List like this:
Figure 10 shows the results.
Like the other formatting cmdlets, Format-List lets you specify one or more properties to display. You can even use wildcards, including the asterisk (*) to get all the properties.
Although piping Get-Process output to Get-Member can help you discover an object's properties, sometimes it helps even more to see the values for those properties. A great way to use Format-List is to get a single object and list all its properties and their values:
With output like that in Figure 11, you'll have a better idea of what the properties mean and can begin devising a more detailed command.
As with Format-Table, Format-List might have different views defined for different object types. Take, for example, the command:
The results in Figure 12 show that PowerShell has a view defined for service objects when they're formatted as a list.
To learn about the views available, you can try using Get-FormatData and looking for ListControl in the Control column. Alternatively, you can experiment by running commands piped to Format-Table and Format-List. You might be surprised at what you discover.
Format at the End
You might have noticed that in all my examples, the formatting cmdlet was at the end of the command. In classes and forums, I often see PowerShell novices try to do something like this:
ft name,length,LastWriteTime,CreationTime |
But when they look at the .csv file, it's gibberish. Here's another command that will fail, but at least there's an error message that explains why:
ft name,length,LastWriteTime,CreationTime |
Figure 13 shows the error message. Admittedly, this message isn't easy to understand, so I'll explain what it means. When you invoke one of the formatting cmdlets, it creates a different type of object and passes it back to PowerShell. So, in the failed command, Format-Table wrote formatting directive objects to the pipeline, which PowerShell then tried to sort on the Length property. But at this point, the pipeline is no longer working with file objects, so the command fails. This gets confusing because if you replace Format-Table with Select-Object, it works.
The rule of thumb is that formatting should be the last part of a PowerShell command. As long as you don't try to do anything after a formatting cmdlet, you shouldn't run into any problems. The assumption is that you're formatting to make the results easier to read and nothing else. However, there's one exception. You can pipe any formatted output to any of the Out cmdlets, such as Out-File or Out-Printer. For example, the following command pipes the Format-Table output to Out-File:
ft name,length,LastWriteTime,CreationTime |
PowerShell will take the same output you'd see on screen and send it to the file.
Give Them a Try
I recommend that you take a few minutes to read the Help files and look at the examples for the formatting cmdlets, then give them a try. Don't be afraid to experiment. Once you understand how formatting works, you'll be bending PowerShell to your will in no time.