Section 1.5. Display Data


1.5. Display Data

So far, we've been building commands with little attention to the output, other than assuming it will be displayed in the console window. How does MSH know how to neatly display the objects, especially if it's not familiar with their structure? It turns out that there is a fair bit of plumbing in MSH to make sure that console output is displayed in a useful form for a wide range of types.

The default formatter is a standard part of the shell. If and when an object reaches the end of the pipeline, MSH inspects its type and compares it to a list of known objects. If a match is found, MSH understands how to best format the object for display; if not, MSH displays the .NET properties of the object.

The type of the first object to reach the end of the pipeline generally governs how subsequent objects will be displayed. Alternatively, a command or script can explicitly insert formatting cmdlets (from the format-* family) and/or outputting cmdlets (from the out-* family) in the pipeline for more explicit control over how and where objects should be displayed.

Let's take a look at some of the different tools available for presenting data.

Appearance Counts

Presentation is important. Of course, working in a command-line shell, we're not necessarily concerned about character spacing or pixel-perfect placement, but if we're relying on some piece of information to determine whether a script worked as expected or actually gather the results of some processing, it's critical that the information is legible and accurate.

MSH has a set of basic formatters that serve a simple purposethey take raw data and output it in a fashion more suited to the destination. Whether that destination is a console window, an XML file, or some other representation, there's a formatter to do the transforming. These common formatters provide a measure of consistency to how different kinds of objects are displayed and relieve the cmdlet writers from the burden of writing complex and potentially different formatting and output code.


1.5.1. How Do I Do That?

Armed with the knowledge that there is a default formatter at work, we can look at the output of get-process in a new light. The default formatter knows about Process objects because they are one of the common data types used in shell work. The default formatter is configured to pick out some of the more interesting aspects of a process and tabulate them for display:

     MSH D:\MshScripts> get-process     Handles  NPM(K)    PM(K)      WS(K) VS(M)   CPU(s)     Id ProcessName     -------  ------    -----      ----- -----   ------     -- -----------         123       5     1008       2500    32     1.24   1844  alg         799      14    14188      16480    71   189.09   1656  CcmExec          19       1     1444       1516    13     1.61   1052  cmd         426       5     1796       3148    24   184.88    464  csrss         361      11     9420      13312    58 2,206.90    212  explorer     ...

Some of the columns in this output, such as ProcessName and Id, are simple properties of the Process data structure. Others, including the non-paged memory size, paged memory size, and working set, are calculated columns . For each of these columns, the default formatter is running a small fragment of script on each Process object it sees, in this case, to convert a number in bytes to kilobytes for display.

We'll come back to the default formatter's behavior shortly. Meanwhile, let's say we're just interested in displaying a subset of the properties of the msh process. The format-list cmdlet is one of the simplest formatters. When provided with a list of property names, it will display each in sequence, along with its corresponding value. For now, let's just use a few properties that are common to all Process types; we'll see where these property names come from later when we meet the get-member cmdlet in Chapter 3:

     MSH D:\MshScripts> get-process msh | format-list     ProcessName,PriorityClass,Id,VirtualMemorySize,Handles,StartTime,WorkingSet,Modules     ProcessName       : msh     PriorityClass     : Normal     Id                : 3088     VirtualMemorySize : 186503168     Handles           : 451     StartTime         : 1/22/2005 5:20:51 PM     WorkingSet        : 37068800     Modules           : {msh.exe, ntdll.dll, mscoree.dll, KERNEL32.dll,                         ADVAPI32.dll, RPCRT4.dll, SHLWAPI.dll, GDI32.dll,                         USER32.dll, msvcrt.dll, mscorwks.dll, MSVCR80.dll,                          mscorlib.ni.dll, ole32.dll, shell32.dll, comctl32.dll,                         comctl32.dll, rsaenh.dll, mscorsec.dll, WINTRUST.dll,                         CRYPT32.dll, MSASN1.dll, IMAGEHLP.dll, SOFTPUB.DLL,                         xpsp2res.dll, userenv.dll, VERSION.dll, secur32.dll,                         netapi32.dll, cryptnet.dll, WLDAP32.dll, WINHTTP.dll,                         SensApi.dll, Cabinet.dll, System.Management.Automation.     ...

format-table is one of the more versatile formatters. In simple usage it can be provided with a comma-separated list of properties and will automatically tabulate the corresponding values for each object it sees. In many cases, a simple format-table pass will be sufficient for data presentation:

     MSH D:\MshScripts> get-process | format-table Id,ProcessName,StartTime                        Id ProcessName                StartTime                        -- -----------                ---------                      1844 alg                        1/22/2005 5:17:58 PM                      1656 CcmExec                    1/22/2005 5:17:56 PM                      1052 cmd                        1/29/2005 5:32:20 PM                       464 csrss                      1/22/2005 5:17:34 PM                       212 explorer                   1/22/2005 5:19:06 PM                         0 Idle                       544 lsass                      1/22/2005 5:17:36 PM                      3088 msh                        1/22/2005 5:20:51 PM     ...

As with most formatting cmdlets, format-table will accept a GroupBy parameter. When displaying results, this is used to separate objects based on some property value. For cleanliness of presentation, it's common to first sort the input before presentation so that each grouped category appears just once. For example, let's create a tabulated process listing grouped by process priority:

     MSH D:\MshScripts> get-process | sort-object PriorityClass,ProcessName     | format-table -GroupBy PriorityClass ProcessName,Id,VirtualMemorySize,PriorityClass         PriorityClass: Normal     ProcessName                                   Id         VirtualMemorySize     -----------                                   --         -----------------     svchost                                      896                  29769728     svchost                                      756                  35753984     svchost                                      824                 110878720     svchost                                      720                  59514880     smss                                         308                   3911680     spoolsv                                     1088                  27459584     svchost                                      940                  39124992     wmiprvse                                     320                  23642112     wmiprvse                                    1920                  26124288     wuauclt                                     1708                  68648960     System                                         4                   1941504     csrss                                        464                  25485312     explorer                                     212                  60772352     alg                                         1844                  33259520     CcmExec                                     1656                  73891840     cmd                                         1052                  13979648     notepad                                     1792                  25735168     services                                     532                  25305088     msh                                         3088                 186503168     lsass                                        544                  43470848         PriorityClass: High     ProcessName                                   Id         VirtualMemorySize     -----------                                   --         -----------------     winlogon                                     488                  53092352     Idle                                           0                         0 

We've only scratched the surface of format-table here. It's possible to be far more expressive in terms of formatting (width and alignment), as well as content (through the use of calculated columns). In the following example, the syntax may seem somewhat obtuse to begin with, but it's very regular and can be used to create almost any imaginable table output:

     MSH D:\MshScripts> get-process | format-table @{expression="ProcessName";     width=50; label="Name"}, @{expression="Id"; width=5}, @{expression={$_     .VirtualMemorySize/1024}; width=30; label="Virtual memory (kb)"}     Name                                             Id    Virtual memory (kb)     ----                                             --    -------------------     alg                                            1844                  32480     CcmExec                                        1656                  72008     cmd                                            1052                  13652     csrss                                           464                  24888     explorer                                        212                  59348     Idle                                              0                      0     lsass                                           544                  42452     msh                                            3088                 182132     notepad                                        1792                  25132     ...

1.5.2. What Just Happened?

We started by looking at how the default formatter operates on known types. It's important to realize that the formatting process is applied to any object when it has nowhere further to go (i.e., it has reached the end of the pipeline, and the next stop is the console output). The shell does not discriminate between a single command (a pipeline of length 1, if you will) and a complex series of processes all piped togetherultimately, both cases have an end point.

format-list is a simple case, and we've already seen the bulk of its functionality here. One thing to remember is that because it generates the same listing for each element, its output can tend to get very large when it's used for any more than a small number of objects. It has a couple of other interesting usages. For types known to MSH, format-list with no parameter will display the object's most relevant properties, whereas format-list with a wildcard parameter (*) will display all of them. If the default formatter does not recognize a type it encounters, it always falls back to the list formatter that shows all properties and values of the object.

The complex format-table case uses a construct known as a hashtable, which is a data type we haven't discussed yet. When we look at hashtables and other data types in Chapter 3, we'll be able to revisit this aspect of format-table to create some more interesting reports.

1.5.3. What About...

...Are there any other formatters? The format-wide cmdlet can be used to list output in a horizontal order. Its formatting is similar to the effect of the /w switch on the DIR command where items are listed left to right and wrap when a line is complete.

...Combining grouping and the default formatter? It certainly is possible. If a formatting cmdlet is used without parameters and the objects are of a known type, the default formatting rules will be applied. In other words, applying format-table to the output of get-process will result in the familiar tabulated style offered by the default formatter. A pipeline such as get-process | sort-object PriorityClass | format-table -GroupBy PriorityClass can be used to group processes by priority while maintaining the standard column format.

1.5.4. Where Can I Learn More?

You can learn more about how the default formatter works by looking at the *.mshxml file distributed with MSH. This file references a series of similar files, each of which contains configuration that is used by the default formatter.

The get-command cmdlet, as well as the help system, can also be used to find more information about the available formatters and their usage:

     MSH D:\MshScripts> get-command format-*




Monad Jumpstart
Monad Jumpstart
ISBN: N/A
EAN: N/A
Year: 2005
Pages: 117

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net