Ever tried to run a command like this?
Get-Process | Format-Table | Export-CSV processes.csv
Pretty horrible output. Do you know why? It all has to do with the way PowerShell's formatting system works. What actually happens under the hood can be a lot more complicated that you might have realized. Here's what's going on
First, understand that the PowerShell pipeline always ends in a special cmdlet called out-Default. It's always there, whether you see it or not. When you run this:
You're actually running this:
Get-Process | Out-Default
In the consoles provided by Microsoft, Out-Default simply forwards to Out-Host, which is responsible for turning whatever's in the pipeline into some form of text display. So REALLY, you're running this:
Get-Process | Out-Default | Out-Host
The trick is that most of the Out cmdlets (-Host, -Printer, and -File, specifically) don't actually know what to do with objects like processes, services, users, or anything else. These Out cmdlets only understand special "formatting objects" that tell them how to construct tables, lists, and so forth. The formatting subsystem is responsible for turning those process objects into a table, and here's how it works.
First, the formatting system looks at the type of object it needs to display. Run this:
Get-Process | Get-Member
See the "Type Name" at the top? System.Diagnostics.Process is the type name of a process object. PowerShell then scans through the formatting instructions that have been loaded into memory. By default, several sets of instructions are loaded. You'll find them in the PowerShell installation folder (run "cd $pshome"), in files with a ".format.ps1xml" filename extension. For processes, I found "System.Diagnostics.Process" in the "dotnettypes.format.ps1xml" file.
RULE #1: If a pre-defined layout can be found, PowerShell will use it.
In the case of Process objects, there IS a pre-defined layout. Specifically, it's a seven-column table. With that information, PowerShell knows how to create the table you're used to seeing when you run Get-Process, and so it creates that table from whatever process objects are in the pipeline.
HINT: All of this magic only works well if the pipeline contains ONE kind of object. It'll select a formatting view based on the type of the first object it sees. Load the pipeline with different kinds of objects (which a script can easily do), and your results might not be as attractive.
Try searching those .format.ps1xml files for "Win32_OperatingSystem," which is produced by Get-WmiObject -class Win32_OperatingSystem. You won't find it. There's no pre-defined layout for that object. So what does PowerShell do with it?
RULE #2: If a DefaultDisplayPropertySet is defined, use those properties to display. Otherwise, attempt to display ALL properties.
If you look in PowerShell's default Extensible Type System (ETS) instructions (types.ps1xml), you'll find Win32_OperatingSystem, and a section called "DefaultDisplayPropertySet." It lists the six properties displayed, by default, for this kind of object.
RULE #3: Given the properties we will display, how many are there? If it's 4 or less, make a table; if it's 5 or more, make a list. The theory is that 4 columns will fit on most screens.
Once PowerShell knows what layout it will use (either from a pre-defined layout, or from Rule #3), it calls a formatting cmdlet. That cmdlet generates formatting instructions, and then passes them back to whatever Out cmdlet is in use. So, really, when you run this:
You're running something like this:
Get-Process | Out-Default | Out-Host | Format-Table | Out-Host
That's not the exact under-the-hood sequence, but it illustrates the logic that's in play.
Here's the BIG TRICK: **ONLY OUT CMDLETS**, for the most part, can understand what a Format cmdlet produces. Try this:
Get-Process | Format-Table | ConvertTo-HTML | Out-File c:\test.html
View that in a Web browser and you'll see that you have HTML that was created FROM THE FORMATTING INSTRUCTIONS. Not what you wanted! Here's a simple rule to remember to keep from getting confused:
In other words, your Format command should be the LAST thing on the command line (all the way to the right), unless the LAST thing on the command line is Out-File, Out-Printer, or Out-Host. Don't pipe a Format command's output to anything but one of those three Out cmdlets, and you're fine.
So there's the formatting system in a nutshell. Any questions?