How can I write a PowerShell function that outputs a table?

This is a REALLY common question, and if you have any experience with VBScript, or Perl, or some similar scripting language, you’ll go down completely the wrong path. The thing to remember is that PowerShell already knows how to format tables! You just have to give it your data in a way it understands, so it can make a table out of it. So what does PowerShell’s Format-Table cmdlet know how to work with?


So the trick is to format whatever data you’re working with as an object. In other words, let’s say you have four variables that contain your data: $data1, $data2, $data3, and $data4. You might be tempted to create a table by doing this:

Write-Host $data1 $data2 $data3 $data4

And so forth. You might start your script with a statement that writes out column headers, even. But that’s not the "PowerShell way" of doing things. Here’s what is:

$out = new-object psobject
$out | add-member noteproperty ColumnA $data1
$out | add-member noteproperty ColumnB $data2
$out | add-member noteproperty ColumnC $data3
$out | add-member noteproperty ColumnD $data4

This gives you an object, stored in $out, containing four properties: ColumnA, ColumnB, ColumnC, and ColumnD. Simply output that by using Write-Output $out and you’re done: PowerShell will happily format it as a table. Since it only has four properties, you don’t even have to use the Format-Table cmdlet – PowerShell will choose a table layout automatically.

A bonus of this technique is that you can also use other cmdlets, like Export-CSV, ConvertTo-HTML, and more. By having your output data contained within an object, all of PowerShell’s various exporting and formatting options become possible, with no extra work on your part.

Think of an "object" as a row in a table; each property of the object becomes a column of the table. Here’s an example function that accepts a computer name, makes up some data as output, and outputs the object. I’m reading in a bunch of computer names from a file, and sending each one to the function. The result is a single output table.

function MakeData($name) {
 $data1 = $name.ToLower()
 $data2 = $name.ToUpper()
 $data3 = $name
 $out = new-object psobject
 $out | add-member noteproperty LowerCase $data1
 $out | add-member noteproperty UpperCase $data2
 $out | add-member noteproperty Original $data3
 write-output $out
$computers = get-content c:\names.txt
foreach ($computer in $computers) {
 makedata $computer

I could actually have written the function to accept pipeline input directly, making this possible:

gc c:\names.txt | makedata

But I didn’t, simply because the way I used is a bit easier to follow as a learning example. So, the moral: Don’t output text. Output objects.

Thanks to Jon for sending this one in.