Windows PowerShell Tip of the Week

Here’s a quick tip on working with Windows PowerShell. These are published every week for as long as we can come up with new tips. If you have a tip you’d like us to share or a question about how to do something, let us know.

Creating Custom Tables

You know, people are funny. For example, suppose you have a new product and you give people the opportunity to choose from a wide variety of colors and sizes. “This is too complicated,” many of these people will complain. “There are too many choices to make. Can’t you just give us one standard model and leave it at that?” And sure, you can do that, you can give everyone a standard model and leave it at that. Of course, the moment you do you’ll set off a new chorus of complaints: “You’re treating us as though we’re all alike. Why can’t you give us the opportunity to individualize and customize this product to meet our own needs?”

In other words, if you give people choices and options they’ll be upset and yet, if you don’t give them choices and options they’ll also be upset. Just what are you supposed to do?

Here’s one suggestion: use Windows PowerShell.

Displaying Process Information in a Custom Table

Granted, Windows PowerShell might not be the answer to all your problems. On the other hand, if your problem happens to involve displaying data in a table then PowerShell definitely gives you the best of both worlds: you can display information using PowerShell’s standard formats or you can create custom table formats all your own. (In fact, you can even modify PowerShell’s standard format; for more information, take a look at the Windows PowerShell Week webcast Amazing But True: Things You Never Dreamt You Could Do With Windows PowerShell.)

For example, suppose you want to retrieve process information and then display that information as a table. Because the Get-Process cmdlet automatically displays data in tabular format you can create such a table by running a command no more complicated than this:


In turn, that’s going to result in output similar to the following:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    101       5     1284       3656    32     0.03   3876 alg
    257       7     4856      10228    69     0.67    872 asghost
    101       4     3080       4696    38     0.36   1744 atiptaxx
    179       7     5568       7008    54     0.22    716 BTSTAC~1
    165       5     3680       6392    52     0.38    632 BTTray
    750      13    11076      20324    77     3.28   2680 CcmExec
    667       7     2844       1688    70    12.81   1196 csrss
    119       5     1204       4260    38     0.58    600 ctfmon
     95       4     1152       3892    36     0.11   1780 DLACTRLW
    205       5     3068       6352    46     0.23   1748 eabservr
    400      14    17436      26120    96    18.28   1032 explorer

So what’s wrong with that? Actually, there might not be anything wrong with that; if that’s the information you need and if you’re comfortable with the format, well, then you’re done. However, there are some potential drawbacks to PowerShell’s default format. Take the headings, for example. NPM(K); what does that stand for?

As it turns out, NPM is shorthand for the property NonpagedSystemMemorySize; the (K) simply indicates that the number being display represent kilobytes of non-paged memory. Speaking of which, what if we don’t care about kilobytes of non-paged memory; what if we wanted to substitute a different property (say, MainWindowTitle) for NonpagedSystemMemorySize? Oh, and why is the process name displayed in the last column; wouldn’t it be better if the process name was displayed in the first column?

We can’t tell you whether or not PowerShell’s default method for displaying process information is “good enough;” that’s entirely up to you. However, we can show you how to modify that display, and show you how you can create a custom table for displaying process data. For example, suppose you want to display three property values, in the following order:

  • Process Name (the ProcessName property).

  • Process ID (the ID property).

  • Window Title (the MainWindowTitle property).

How can you do that, and give each column in the table a more-meaningful title? Here’s how:

$a = @{Expression={$_.Name};Label="Process Name";width=25}, `
@{Expression={$_.ID};Label="Process ID";width=15}, `
@{Expression={$_.MainWindowTitle};Label="Window Title";width=40}

Get-Process | Format-Table $a

And here’s the kind of information you’re going to get back after issuing these two commands:

Process Name                   Process ID Window Title
------------                   ---------- ------------
lsass                                1284
LSSrvc                               2112
MDM                                  2240
notepad                              2348 Untitled - Notepad
notepad                              3944 Untitled - Notepad
OUTLOOK                              1192 Inbox - Microsoft Outlook
powershell                           1348 Script Center

Yes, we know: even though there are just two commands there, this still looks pretty darn complicated. So let’s see if we can explain how it all works.

To begin with, all we’re doing in the first command is assigning a set of formatting instructions to a variable named $a. And no, we don’t have to assign these instructions to a variable; we could have included these instructions as part of our second command, a command that retrieves process information and then pipes that data to the Format-Table cmdlet. However, that made for one really gnarly-looking command. We went with the two-command route because we thought it would be easier for everyone to understand what’s going on.

As long as we’re trying to make things easier to understand, let’s simplify our first command as well: let’s trim it down so that it only contains instructions for formatting a single column, the column featuring the process name. Here’s what the simplified version of our command looks like:

$a = @{Expression={$_.Name};Label="Process Name";width=25}

That’s much better, isn’t it? Again, all we’re doing is assigning formatting instructions for the first (and only) column in our table to the variable $a. As you can see for yourself, the formatting information for this column (as well as any other columns) must be enclosed inside this construction: @{}. And what exactly goes inside that construction? In this case, we have the following three elements, with each element separated by a semi-colon:

  • Expression={$_.Name}. The data that you want displayed in the column; note that this information must be enclosed in a second set of curly braces. In this example we simply want to display the value of the Name property; thus we use the syntax $_.Name, with the $_ representing the current item in the pipeline and the .Name representing the standard “dot notation” for the Name property. (Standard dot notation being a period followed by the property name.)

    Incidentally, you can do some reasonably fancy things inside one of these little script blocks. For example, suppose you decide to display paged memory size (the PagedMemorySize property). By default, this data is displayed in bytes; that means you’ll get back a value like this: 1314816. (Granted, that’s not how the Get-Process cmdlet displays paged memory size, but that’s because Get-Process has been configured to convert this value to kilobytes. Once we pass data to the Format-Table cmdlet we’re no longer using Get-Process’ default formatting.)

    Prefer kilobytes to bytes? Then assign an Expression that divides the value of the PagedMemorySize property by 1024. You know, an Expression like this: Expression={$_.PagedMemorySize / 1024}.

  • Label="Process Name". The heading that appears at the top of each column. This is actually optional; you don’t have to specify a Label. If you don’t, however, Windows PowerShell uses the Expression itself as the column heading; in this case, that means in a column heading of $_.Name.

  • width=25. The width (in character spaces) for the column. This parameter is also optional; leave it off and PowerShell will use default values to assign column widths.

It’s as easy as that. Want to include a second column in your table? That’s fine; just insert a comma and then add information for column 2 (for the sake of readability, we also inserted the ` linebreak character in our example):

$a = @{Expression={$_.Name};Label="Process Name";width=25}, `
@{Expression={$_.ID};Label="Process ID";width=15}

As you can see, in column 2 we want to display the process ID ($_.ID), giving this 15-character-wide column the column heading Process ID:

@{Expression={$_.ID};Label="Process ID";width=15}

Want to limit your fancy formatting to column 1, with column 2 using the default display instructions (and displaying the value of the ID property)? Then assign fancy formatting for the process name (and only the process name) to the variable $a, and use the following as command number 2:

Get-Process | Format-Table $a,ID

In other words, we’re asking Format-Table to display two items in the table: the fancy formatting saved in $a, plus the ID property.

Alternatively, you can do the whole thing in one fell swoop, like so:

Get-Process | Format-Table @{Expression={$_.Name};Label="Process Name";width=25},ID

That’s a good point: we should briefly explain command number 2, shouldn’t we? As you recall, our original command 2 looked like this:

Get-Process | Format-Table $a

The truth is, there really isn’t that much to explain; all we’re doing here is using the Get-Process cmdlet to retrieve process information, then piping all that data to the Format-Table cmdlet. And what do we want Format-Table to do? That’s easy: all we want is for Format-Table to display the property values specified in the variable $a, and to display those values using the formatting instructions that were also specified in $a. That’s all there is to it.

So there you have it: if you want the standard information display you can have the standard information display, and if you want a customized information display, well, you can have a customized information display. Best of all, everyone will be happy.

Well, OK. But at least everyone should be happy.