The Trouble with Format-* Commands in PowerShell


There are a handful of Format commands that can really help make your data easier to look at.

  • Format-List (FL)
  • Format-Custom (FC)
  • Format-Table (FT)
  • Format-Wide (FW)

I’ll commonly use either Format-List or Format-Table to display the data of an object in the console to see whats in there but I often times see people put this in their scripts or even worse, in the middle of a pipe.

Side Note: Another common mistake is for people to use write-host in a script, see this.

The problem with using the Format commands is that it is for displaying info and when it does this it converts your object to a special internal type object. Lets play with an IPAddress and see what we have.


$ip = [ipaddress] '192.168.1.1'

$ip

$ip | ft

$ip | gm

$ip | ft | gm

So if you take a look at the output you’ll see a couple of things,

  1. The default view of an IP object is a List view. Some objects have default definitions for views and are stored in format files here C:\Windows\System32\WindowsPowerShell\v1.0 (NEVER EDIT THIS FILE), if you want to know more about these format files comment on this post and I’ll do a write up. If a default view isnt defined (which most arent) the rule is, more than 4 properties make it a list, 4 or less make it a table.)
  2. If we ask for it as a table it will squeeze it in, which in some cases that’s great. (Dont forget ft -auto)
  3. Running Get-Member (GM) on this we see that as it goes down the pipe its left in tact (Shows us we have an IPAddress object)
  4. The important part, if we pass an object down the pipe and then format it and then check the type, we see several items spit back, all of which are Internal.Format types.

The problem here is that what we’ve started with in the pipe (an IPAddress) has been dropped and changed for Format objects, which dont have the properties of the original object.

Basically we’ve gone from an Object to formatted text which is no fun in PowerShell.

There are some cases where you want to slim down your result set or combine things in which case the cmdlet you are looking for is Select-Object (Select) which I’ve now started to use over the format cmdlets for displaying data in the console.


$ip | select address
$ip | select address | gm

You’ll notice the object type is only slightly different. the type name has been prefixed with Selected. The thing to keep in mind is if we try to use this IPAddress in a method that expects this object in its full state, for example.

$ip = [ipaddress] "..." #use a valid IP here
$limitedIP = $ip | select addressfamily
$ip | gm
$limitedIP | gm
[net.dns]::GetHostEntry
[net.dns]::GetHostEntry($limitedIP)
[net.dns]::GetHostEntry($ip)

You’ll notice the first call caused an error saying there is no overload that has a single argument which is rather misleading because both signatures require only one argument (IPAddress or String). It should probably say invalid type or something like that.

The second call works just fine.

Now, back to the format cmdlets. Normally I would have stopped right here but the PowerShell.com Tip of the Day had a pretty neat use of Format-Table in a function


$Input | Format-Table -AutoSize | Out-File $Path -Width 10000

This is actually a pretty neat use since it can be used to generate a report. I havent played with this enough to see if there is a great advantage of this method over the Export-CSV cmdlet, but still, it’s a use of the format commands in the pipe (never say never).

I hope this has helped clear things up for you more than making it worse. I will say I think one of the primary take aways from this post is that with all power that PowerShell provides its VERY easy to get yourself in trouble.

BONUS TIP: You can create custom objects quickly with Select like so.


$customobj = "" | select fname,lname
$customobj.fname = 'Justin'
$customobj.lname = 'Rich'

Enjoy!

 

P.S. Thanks to Thomas Lee for the corrections.

Advertisements

About jrich

I am the Solutions Architect for Apex Learning in Seattle WA. I've been working with computers since I was 13. Started programming when I was 14. Had my first IT job as tech support at an ISP at the age of 15 and became a network admin at the age of 17. Since then I've worked at a variety of small to mid size companies supporting, maintaining and developing all aspects of IT. Mostly working with Windows based networks but have recently been working with Solaris system as well. I created this blog mostly as a place for me to take my own notes, but also share things that I had a hard time finding the info for.

Posted on November 25, 2011, in WMF (Powershell/WinRM) and tagged , , , , . Bookmark the permalink. 2 Comments.

  1. A small correction to the above which says: “all objects have default definitions for views”. This is not correct, most objects do NOT have a view, but PowerShell can format them anyway by simply displaying all the properties.

    Also, in the discussion of using Select-Object with an IP Address. The article says that is you do this: $ip | select address | gm, “You’ll notice the object type is still the same” This is not correct. When hyou do the select. the type name changed from .System.Net.IPAddress to Selected.System.Net.IPAddress. This is why you get errors calling the DNS methods. They are expecting an object of type System.Net.IPAddress not Selected.System.Net.IPAddress.

    Thomas Lee
    http://tfl09.blogspot.com

    • Thanks, I’ll be updating that. Just past that I stated ” If a default view isn’t defined the rule is, more than 4 properties make it a list, 4 or less make it a table.” It did make me think twice and you are right I should change that.

      As far as the second item, I completely missed that. I don’t suppose you know what that’s doing or could provide details in to the internals of that? For example, why it does that and not just convert it in to a system.object or psobject.

      I’m glad to see someone as notable as yourself is coming across my blog, I’m very pleased to get input from someone like yourself.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: