Click to Rate and Give Feedback
Tips
Find out how you can use Windows Boot Performance Diagnostics to identify the source of startup performance problems and automatically fix issues. ...

Read more!

Learn how you can use this command-line tool to perform Group Policy–related troubleshooting. ...

Read more!

One way to disable a policy is to disable an unused part of the GPO. By disabling part of a policy that isn’t used, the application of GPOs and security will be faster. ...

Read more!

In six easy steps, you can configure message delivery options for your organization’s transport servers so that they don’t apply filters to IP addresses from internal servers and your perimeter network ...

Read more!

Here are seven best practices that will help you get the most out of your servers hosting the Hyper-V role. ...

Read more!

Related Articles

This installment clears up some confusion over Active Directory Browser, ADSI Scriptomatic, and browsing Active Directory. And in doing so, the Scripting Guy creates a Windows PowerShell script that will allow you to browse the Active Directory schema.

The Microsoft Scripting Guys

TechNet Magazine February 2009

...

Read more!

You need to calculate server downtime in order to report on server uptime. The Scripting Guys have a Windows PowerShell script that can do this for you.

The Microsoft Scripting Guys

TechNet Magazine December 2008

...

Read more!

The Microsoft Scripting Guys create a Windows PowerShell script that provides an easy way to back up, archive, and clear your event log files.

The Microsoft Scripting Guys

TechNet Magazine July 2009

...

Read more!

Don Jones kicks off a four part series that will look at how you can use Windows PowerShell to create a real-world user provisioning script.

Don Jones

TechNet Magazine March 2009

...

Read more!

Automating data entry is more important than ever, and today’s automation language is Windows PowerShell. This article uses Windows PowerShell to collect some data about the local computer and write it to an Office Access database.

The Microsoft Scripting Guys

TechNet Magazine May 2009

...

Read more!

Also by this Author

Don Jones concludes his four-part series on automating user provision with Windows PowerShell. In this final edition, Don discusses adding users to domain groups and modifying directory attributes.

Don Jones

TechNet Magazine June 2009

...

Read more!

Don Jones demonstrates a Windows PowerShell-based inventory tool and guides you through the process that goes into building such a solution.

Don Jones

TechNet Magazine November 2008

...

Read more!

For your users with attention span issues—and even those without—providing status feedback in your scripts is a good idea. Here's all you need to know to provide status in Windows PowerShell.

Don Jones

TechNet Magazine March 2008

...

Read more!

Today, the likelihood of a homogeneous network has become increasingly remote. It’s in your interest not to limit yourself to a single platform. Instead, you can be known as the IT guy who can do whatever needs to be done—whether it be supporting Mac or Windows. Don Jones teaches what you need to know to set up a Mac on your Windows network, troubleshoot network problems, share files and folders among Macs and Windows-based systems, and configure Macs to use your network printers.

Don Jones

TechNet ...

Read more!

Following up on the November installment of his Windows PowerShell column, Don Jones demonstrates an even better inventorying tool and demonstrates a sound process for building your own custom Windows PowerShell functions.

Don Jones

TechNet Magazine December 2008

...

Read more!

Popular Articles

Without too much effort, you can deploy a terminal server to host the applications you need in your environment. But there are some important decisions you’ll need to make to ensure your implementation meets user expectations. Greg Shields discusses the various options you have and explains how they will affect you.

Greg Shields

TechNet Magazine January 2009

...

Read more!

Learn how you can implement error-handling in Windows PowerShell.

Don Jones

TechNet Magazine January 2009

...

Read more!

Why do attachment sizes increase when sending and receiving e-mail messages? How can you ensure databases on a passive node in a CCR cluster are defragmented during online maintenance? Can you use an external trust between forests? We answer these questions and more.

Henrik Walther

TechNet Magazine January 2009

...

Read more!

Drivers fail, files get corrupted, disks crash--there are numerous uncontrollable reasons why Windows might fail. But all is not lost. Wes Miller explores the kinds of things that can go wrong in a Windows system, and explains how you can troubleshoot them to get your system working again.

Wes Miller

TechNet Magazine January 2009

...

Read more!

Discover how to use the Excel.Application automation model for a more powerful way to process data from your servers and take advantage of the analysis and charting tools built into Excel.

The Microsoft Scripting Guys

TechNet Magazine January 2009

...

Read more!

Our Blog

NAP monitors the health of specified computers when they attempt to connect to a network and includes a number of mechanisms to enforce health requirements. In this article, Geek of All Trades Greg Shields gives readers an overview of these enforcement mechanisms and, as an example, takes a closer look at setting ...

Read more!

Use Windows PowerShell to Manage Virtual Machines Here are a few examples of how you can use Windows PowerShell scripts to manage virtual machines running on a Server Core installation. Note that these scripts are presented as samples and may need to be customized to work in your environment.

Create a New ...

Read more!

Disabling an Unused Part of Group Policy Objects One way to disable a policy is to disable an unused part of the GPO. By disabling part of a policy that isn’t used, the application of GPOs and security will be faster.

Administer Windows Server 2008 Server Core from the Command Prompt ...

Read more!

In the August 2008 issue of TechNet Magazine, Paul Randal wrote an article Top Tips for Effective Database Maintenance.  It was geared toward "involuntary  DBAs" (IT pros who inadvertently wind up responsible for a SQL Server instance).  The article had a great response from our readers so Paul has written another ...

Read more!

Microsoft Forefront is designed to deliver an integrated security solution that makes it much easier to deploy and manage security across an organization’s IT infrastructure. In this, our annual security issue, we feature two articles that describe how Forefront Security protects instant messaging and e-mail.

Protect ...

Read more!

Windows PowerShell Looking Good
Don Jones


It's not uncommon to want your scripts to produce nice-looking output, and I'm often asked about the best way to produce things like tables. There are really a couple of ways to go about doing this. The first step is to write a script that puts the data—that is, whatever data it is that I want to display in a formatted fashion—into variables named
$data1, $data2, and $data3. Now I can get down to formatting the data.

The Text Way
The most common way folks tend to approach this task is the same way they'd handle it if they were working in a language such as VBScript, Perl, KiXtart, or another text-oriented language. I might start by writing out a set of column headers to the screen:
Write-Host "ColumnA'tColumnB'tColumnC"
Note that the `t is a special escape sequence in Windows PowerShellTM that inserts a tab character. To write out each line of my table—remembering that my data is in $data1, $data2, and $data3—I have a few choices. One is to simply write the variables, relying on the shell's ability to replace variables with their contents inside double quotation marks:
Write-Host "$data1't$data2't$data3"
Another slightly more attractive way to achieve this uses the –f operator. This technique separates the formatting from the data and makes what I think is an easier-to-read and more easily maintained line of code:
Write-Host "{0}'t{1}'t{3}" –f $data1,$data2,$data3
This entire approach has significant problems, though. First, by relying on the fixed tab stops in the console window, I am setting myself up for some odd formatting. For example, if a particular table row has a 20-character value in the first column, I throw the entire formatting for that row out of whack. Also, since I'm outputting this text by using Write-Host, I'm pretty much limited to a console display.
There's no easy way to send that output to a file or to put it in other formats, should I ever want to do so. Most importantly, this text-based approach completely ignores the inherently object-based shell that I'm working in, failing to take advantage of all the incredible techniques and capabilities that Windows PowerShell offers.
Video
Watch Don Jones demonstrate how you can easily add formatting to your Windows PowerShell output.


The Windows PowerShell Way
Windows PowerShell is an object-oriented shell. That means, ideally, everything you work with should be in objects, allowing the shell to turn things into text displays when needed. But how do you create objects for arbitrary pieces of data?
Continuing my example, I start by creating a blank custom object and storing it in a variable:
 $obj = New-Object PSObject
This gives me a fresh, empty object to work with. I then add my data to the object in the form of properties. To do this, I simply pipe my object to the Add-Member cmdlet. I add something called a NoteProperty, give the property a name (a good idea is to use the column headers as property names), and then insert the data as the values for the properties:
 $obj | Add-Member NotePropertyColumnA $data1
$obj | Add-Member NotePropertyColumnB $data2
$obj | Add-Member NotePropertyColumnC $data3
Now I simply output this object—not to the console, but to the pipeline:
Write-Output $obj
I can then repeat these steps for each table row that I need to output. The following is a short function that accepts a string and outputs an uppercase and lowercase version, along with the original string:
functionStringVersions {
param([string]$inputString)
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty Original($inputString)
  $obj | Add-Member NoteProperty Uppercase($inputString.ToUpper())
  $obj | Add-Member NoteProperty Lowercase($inputString.ToLower())
  Write-Output $obj
}  
$strings = @("one","two","three")
foreach ($item in $strings) {
StringVersions $item
}
I start with an array of string variables, going through each of them one at a time and sending them to the function. And the function's output is written to the pipeline.
You should note that there are shorter ways to write this code, but I chose this technique because it clearly illustrates the point I want to make. The result, as shown in Figure 1, is a perfectly formatted table. That's because the shell already knows how to format objects in a table.
Figure 1 Windows PowerShell output displayed in a table (Click the image for a larger view)
Whenever an object has four or fewer properties, Windows PowerShell chooses a table automatically. So with no work whatsoever on my part, I now have a great-looking table.

But Wait, There's More!
Cmdlet of the Month: Get-Command
I'm sure you've used Get-Command, or its handy alias (gcm), once or twice to review the list of available Windows PowerShell cmdlets. But you may not know how flexible gcm really is. For instance, if you want to see everything Windows PowerShell can do with a service, run gcm -noun service. Or, if you want to see all of the Windows PowerShell export options, try gcm -verb export. If you just need to see what cmdlets were added by a particular snap-in, such as the PowerShell Community Extensions, try gcm -pssnapin pscx. (You can replace "pscx" with any snap-in name to see that snap-in's cmdlets.)
As you can see, Get-Command is a key player in the discoverability of Windows PowerShell. It allows you to learn what functionality is available without even having to pick up a manual. And note that gcm is a more accurate way of discovering functionality than using a command such as Help *. The Help function only lists available help topics. Any cmdlets that didn't ship with help don't show up in the help listing—even though the cmdlets are there if you need them.

The benefit of this technique goes far beyond tables. When you're working with objects, Windows PowerShell knows how to do a huge range of things. Want your data in a CSV file? Use Export-CSV. Prefer an HTML table? Pipe your objects to ConvertTo-HTML. Need a list format? Pipe them to Format-List. By using objects, you can make use of all the things the shell already knows how to do. Here's a revised example:
functionStringVersions {
  PROCESS {
   $obj = New-Object PSObject
   $obj | Add-Member NoteProperty Original($_)
   $obj | Add-Member NoteProperty Uppercase($_.ToUpper())
   $obj | Add-Member NoteProperty Lowercase($_.ToLower())
   Write-Output $obj
}
}
This time around, I've modified the function to accept pipeline input—this is always a better idea when you're working with objects—and to output to the pipeline.
This function now has its code inside of a PROCESS scriptblock. This means that function will accept pipeline input and will execute the PROCESS scriptblock once for each object that is piped in.
Within the PROCESS scriptblock, the special $_ variable refers to the current pipeline object that's being processed. The practical result of this is that now I can simply pipe in an array of strings:
@("one","two","three") | StringVersions
I get a table because the function is putting its output into the pipeline. At the end of the pipeline, the shell knows to call on its formatting subsystem, which makes the decision to use a table because the objects in the pipeline have fewer than five properties (for more properties, the shell will use a list by default).
But I don't have to rely on the default behavior. I can simply pipe those objects to another cmdlet to have something else done with them:
@("one","two","three") | StringVersions | Format-List
@("one","two","three") | StringVersions | ConvertTo-HTML | Out-File "strings.html"
@("one","two","three") | StringVersions | Export-CSV "strings.csv"
@("one","two","three") | StringVersions | Select Uppercase,Lowercase -unique
Figure 2 shows the resulting HTML from the second example displayed in a Web browser. By simply representing my output data in objects, rather than representing it as simple text, I suddenly now have complete access to a wealth of functionality that is built into the shell—a variety of formatting layouts; HTML conversion; export options; the ability to sort, filter, and group; and more.
Figure 2 Windows PowerShell data output in HTML format (Click the image for a larger view)
This is very powerful stuff. In fact, I will go so far as to suggest that every script you write should produce an object as its output so you can use that output in as many different ways as possible—all without writing a single additional line of code.

Don Jones is an expert in Windows administrative automation and has authored such books as Windows PowerShell: TFM and VBScript, WMI, and ADSI Unleashed. You can reach him through the forums on ScriptingAnswers.com.
© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.
Page view tracker