“Format-{0}”–f ‘List’

Today I would like to write few words about why you shouldn’t work too hard with creating output when PowerShell can do the work for you.

Scripting, as I see it, is a way of taking stuff that “is there” and force it to do my job in a way I want it to be done. If there is something that will do job for me – I will use it. If not – I will create it. So my role is just to build the bridges, not whole road next to the old one.

Obviously, at times you do not know that road already exists. That’s where stuff like Scripting Games help a lot. I for one learned few neat tricks already. But if you fail to see highway and claim to be advanced scripter – be warned, I won’t praise your rocky road that you’ve created next to it. To the point.

Old habits die hard

In VBScript days (but also in cmd days) we, scripters, had to work hard to create decent output. Create tabs, newlines and pray for string in variables to be short/ long enough to get what we expected. One exception to what we seen in tests and we were doomed. OK, maybe not doomed, but not happy with end result either.

We also had to use some fancy techniques to merge output with variables. No way to easily “inject” variable into pre-formatted string. Nightmare.

So it probably should not be a surprise to see the same patterns in PowerShell scripts. I’ve seen that a lot during last few days when reading script both from beginner and advanced category. Luckily – most people know already, that PowerShell is not only powerful in getting data – it’s pretty strong in formatting it. But I’ve seen enough of VBScript-style work to feel that some broader comment on this topic may be needed/ helpful. First – lets talk a little bit about data injection.

Magic of –f operator

PowerShell is based on .NET. What it means? It means we can format data pretty easily. It can be DateTime, integer, regular string – not important. We can move things around, fix width, align left of right – you name it. So if you creating some output message like that:

"Foo is: " + $foo + " and bar is " + $bar            

… you are – in my opinion – doing it wrong. Even if you use put variables in the middle of the string (including subexpression syntax for accessing variable properties), you still not taking full advantage of what PowerShell has to offer.

OK, critics are valuable only if they are constructive. So what alternative do I have for you? Take a look at this line:

"{0:G}.$.$.{1:P2}.'.'|{2,-10}|{3,10}|" -f (Get-Date), (1/3), 'Alfa','Beta'

Would it be hard to guess output? Well, things we have in {} are anchors, they will position things in our output string. Number inside anchor – is index in parameter list. After colon we choose format (‘G’, ‘P2’) and after comma – position (‘10’, ‘-10’) of data. And where is data? Well, it’s outside our string. So if you ever decide to change it – great – just apply new variable! It’s even cooler than that: you can save this template and apply it as many times as you wish. Well… maybe not this particular, but something like that:

# Somewhere at the start of script/ function we define template...            
$AddColumn = "ALTER Table TableName Add Column {0} {1}"            
            
# And in the middle of process block/ foreach statement:            
Invoke-SqlCommand ($AddColumn -f $Name, $Type)

Easy! Smile  And as you can see you can have whole expressions there. Things like $variable.property just work, commands require extra step. Still: I think this separation makes message like that easier to create, read and maintain.

Format-* to make your objects shine

OK, so we are done with creating single message. But single message is not always what we are after. Most often you have more data to show, and you would like to format it nicely. Obviously, you can use what I mentioned above, or just move your data around to get proper number of spaces here… or [tab][tab][tab] there… Stop!

Really, PowerShell is there to help. But it understands objects. So, what you have to do? Create one. I know at least four ways of creating objects out of the blue, pick one that suits you most. I may comment on it, or don’t like it. But that’s just a matter of taste. End result is the same: you build object, PowerShell will format it for you. One object looks perfect when listed. Dozen – in a table. It’s up to you which you should choose. But don’t rewrite PowerShell formatter. And remember: if you create objects and decide that you want to do something useful with them before formatting (like sort, or select) – you can. If you just generate some strings – you end up with something you will use once. So how would I create object? My favourite technique is to use hashtable:

New-Object -TypeName PSObject -Property @{            
    Alfa = 1            
    Beta = 2            
    Gamma = 'Some data here'            
    Delta = Get-Date            
}

It got even better in v3:

[PSCustomObject]@{            
    Alfa = 1            
    Beta = 2            
    Gamma = 'Some data here'            
    Delta = Get-Date            
    Five = 'So I get a list'            
}            

It has advantage over v2 method: hashtables do not keep order, so objects in v2 are kind of random. As you can see default display changes depending on number of properties, but that just default, you can change end result with Format-* whenever you want. You don’t have to worry too much about lining things correctly: all that will be done by PowerShell in background. You can even take it to the next level with formatting files. Still: first step is to create object. And because there are so many ways to skin the cat – you are not forced to use mine. Smile And if you ever decide you’d rather have table instead of list – you do not have to rewrite whole block of code. Just replace –List with –Table, or other way around. Remember: bridges, not new roads.

About these ads

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