Hey, Scripting Guy! Question

Hey, Scripting Guy! I just read your “using calculated properties” PowerShell Tip of the Week, and it addresses a problem I recently had. However, when I got to the last step in your article, I realized the file sizes – and my displayed values – are now left-justified. I’d like to use leading zeroes to align the numbers on the decimal point, but I haven’t figured out how to do that. Any suggestions?
-- GD

SpacerHey, Scripting Guy! AnswerScript Center

Hey, GD. You know, any time we answer a Windows PowerShell question we usually end up getting a flurry of PowerShell-related questions, all of them pretty much like this one:

Hey, Scripting Guy! I saw your column about Windows PowerShell. That’s something I’d really like to learn; do you have any suggestions on a good starting place for someone brand-new to Windows PowerShell?

Well, as a matter of fact we do – now. Next week (next Tuesday – June 10, 2008, in fact) the Scripting Guys will be delivering a pair of instructor-led labs at TechEd 2008 in Orlando. We’ll be presenting Windows PowerShell for VBScripters at 10:00 AM on Tuesday, then we’ll present the same lab again at 1:00 PM, although this late show will be for adults only.

Although, now that we think about it, kids aren’t allowed to attend TechEd. Which means that the early show will be for adults only, too.

At any rate, this lab is designed for people – adult people – who are new to Windows PowerShell. (Despite the name, no VBScript experience is required.) What will we do during the lab? Well, we have only an hour and 15 minutes for each session, which means we’re going to try and cram as much PowerShell knowledge into your heads as we can. And if we can’t get to something? Hey, no problem: we also have some useful handouts for you, including a printed – and greatly expanded – VBScript to Windows PowerShell Conversion Guide, as well as a printed – and slightly expanded – version of the Windows PowerShell Owners Manual. Are you going to get copies of these two booklets at any other session in TechEd? Are you going to get copies of these two booklets at Universal Studios or Disney World? In a word: no.

Note. Will you get copies of these two booklets at Sea World? Hmmm; good question. We’ll have to get back to you on that. They seem like the sort of thing you’d get at Sea World, but we can’t be sure.

Oh, and even that’s not all. At the end of each lab we’ll also have a special guest appearance by Hal Rottenberg, co-host of the ever-fascinating PowerShell Podcast, and Community Director for the Web site PowerShellCommunity.org. Hal’s going to talk about the Windows PowerShell community, something which will definitely be of interest to those of you just getting started with Windows PowerShell.

Note. And what if you’re an old hand at Windows PowerShell? Well, you could lend newcomers a hand by suggesting resources we could add to our Windows PowerShell Toolbox and the Windows PowerShell Holiday Gift Guide. If you know of a good PowerShell utility, Web site, book, or other resource that we haven’t listed, please drop us a line at scripter@microsoft.com (in English, if possible) and let us know. We thank you, Hal Rottenberg thanks you, and the newcomers to Windows PowerShell thank you.

Well, except for that grouchy guy from Wisconsin, who never thanks anybody for anything. But all the other PowerShell newcomers thank you.

Of course, the one problem with all this is the fact that we don’t present our instructor-led lab until next Tuesday. (Well, OK, another problem is the fact that this lab is only going to be presented at TechEd 2008, which means you’re going to have to figure out a way to get into the conference and get yourself to Orlando before next Tuesday. But how hard could that be?) That means that you’ve still got a week – over a week – to wait before the world premiere of Windows PowerShell for VBScripters. How are you supposed to get your Windows PowerShell fix between now and then? Here’s a hint: just keep reading. We have all sorts of good PowerShell information for you in today’s column.

And no, this isn’t the first time that a Hey, Scripting Guy! column has been filled with good information. After all, there was … that one time. And then that other time after that.

Although, come to think of it, there really wasn’t much information in that one, was there?

At any rate, let’s take a peek at a simple example and then – after we’ve illustrated the basic concept – we’ll show you how to use this same approach using a calculated property. (But no, we won’t discuss calculated properties or how they are used, at least not in today’s column. After all, that’s what the PowerShell Tip of the Week that GD referred to is for.)

The problem GD has is that he’s getting output that looks like this:

37.222378
5421.1991
3.2

As you can see, that output is a bit difficult to decipher, especially at first glance. What GD would like to get is output that looks like this, with leading zeroes that ensure that the decimal places line up nice and neat:

00037.222378
05421.1991
00003.2

How’s he supposed to do that? Well, here’s one suggestion:

$a = 37.222378
$a.ToString("00000.00")
$b = 5421.1991
$b.ToString("00000.00")
$c = 3.2
$c.ToString("00000.00")

Good question: what are we doing here? Well, the first line should be fairly straightforward; all we’re doing there is assigning the value 37.222378 to the variable $a. And the second line really isn’t all that difficult, either: in that line we’re using the ToString method to display the value of $a as a string. When we do that (display a number as a string), we can apply some standard formatting characters to the string as well. For this sample script, we want to do two things: 1) we want to display a maximum of 6 leading zeroes; and, 2) we want to display two decimal places. That’s why we used the format string 000000.00: the 000000 gives us six leading zeros (or, to be a little more precise, as many leading zeroes as we need in order to fill six digit spots) and the .00 gives us two decimal places.

We then do the same thing for the values assigned to $b and $c. And what’s our output going to look? It’s going to look an awful lot like this:

00037.22
05421.20
00003.20

Of course, PowerShell being PowerShell, we also could have carried out this same task using a single command:

($a = 37.222378, 5421.1991, 3.2) | ForEach-Object {$_.ToString("000000.00")}

In this example we’re simply assigning all three of our numeric values to an array named $a. We then pipe the value of $a to the ForEach-Object cmdlet, asking ForEach-Object to use the ToString method to display the value of each item in the array, and to display these values using the 000000.00 format.

And yes, that is awfully nice of ForEach-Object to do that for us, isn’t it?

While we’re on the subject, what if you wanted a fixed number of decimal places but didn’t care about leading zeroes? Well, in that case you could always use a format string like this one:

$a.ToString("#.000000")

Here we’re using the # sign to represent one or more digits, then using .000000 to represent six decimal places. What’s $a going to look like when we run this command? It’s going to look like this:

37.222378

Here’s another formatting string you might find useful:

$a.ToString("#,###.00")

Notice the syntax here: #,###.00. The #,### is going to use a comma as the thousands separator; in other words the value 1,000 is going to be displayed like this:

1,000.00

And it doesn’t matter how many thousands (or tens of thousands or hundreds of thousands or thousands of thousands) you might have; PowerShell will put in as many commas as needed. For example, take this little block of code:

$a = 11366777.222378
$a.ToString("#,###.00")

As you can see, the value 11366777.222378 needs all sorts of commas in order to separate the thousands. That’s fine; PowerShell will take care of that for you:

11,366,777.22

Now, what about using this approach in a calculated property? Well, as it turns out, that’s no big deal:

Get-ChildItem C:\Scripts | Where-Object {$_.PsISContainer -eq $False } | 
Select-Object Name, @{Name="Kbytes";Expression={ ($_.Length / 1KB).ToString("00000.0") } }

Again we’re too lazy – um, too pressed for time to discuss calculated properties in any depth today. But take a look at our calculated property for displaying file sizes in kilobytes:

@{Name="Kbytes";Expression={ ($_.Length / 1KB).ToString("00000.0") }

In this case we’re taking the Length (size, in bytes) of each file and dividing it by the numeric constant 1KB; that gives us the size of each file in bytes. We then take that value and display it using the ToString method, this time using 5 leading zeroes and a single decimal place:

ToString("00000.0")

And what will that result in? This:

Name                                                        Kbytes
----                                                        ------
Average.txt                                                 00001.8
bcdscripts.zip                                              00006.6
bootmgr.vbs                                                 00001.9
ctp2.txt                                                    00035.1
ctp2_cmdlets.txt                                            00111.5
hey0501.doc                                                 00115.0
mimic_bcdedit.vbs                                           00017.5
MORPHEUS.TTF                                                00066.4
os_info.vbs                                                 00017.5
output.txt                                                  00032.9
pool.mdb                                                    00224.0
PowerShellScriptOMaticCompiledRelease.exe                   00430.6

Pretty nice, huh?

But wait; there’s more. Leading zeroes are nice, but it might be even nicer – at least in some cases – to have output that looks like this:

   37.22
 5421.20
    3.20

In other words, we’d like to use “leading blank spaces” rather than leading zeroes. But is that even possible using out .NET formatting characters?

To tell you the truth, we aren’t sure; however, after a brief search we weren’t able to come up with anything. But that’s OK; instead, we came up with this:

$a = 37.222378
($a.ToString("#.00")).PadLeft(10)
$b = 5421.1991
($b.ToString("#.00")).PadLeft(10)
$c = 3.2
($c.ToString("#.00")).PadLeft(10)

This time around we’re doing “two-step” formatting. In step 1, we use the ToString method to convert the value of each variable to a formatted string, in this case a number (or set of numbers) followed by two decimal places:

($a.ToString("#.00"))

Note that we placed this command in parentheses to ensure that PowerShell carried this out before doing anything else.

Step 1 converts the value 37.222378 to this: 37.22. In step 2, we’re going to use the PadLeft method to insert enough blank spaces at the beginning of the string to ensure that the string fills up 10 character spaces. That makes $a equal to this:

     37.22

And when we apply the same process to $b and $c we end up getting the “leading blank spaces” we were after:

   37.22
 5421.20
    3.20

Pretty slick, huh?

That should do it, GD. If you have any other questions about Windows PowerShell, just stop by TechEd 2008 next week and we’ll be happy to help you. As we noted, we’ll be delivering a pair of instructor-led labs on Tuesday; we’ll also be available after each session to answer questions and to chat about scripting. (Well, as far as we know we’ll be available.) In addition, we’ll be hanging out at the TechNet Magazine booth on Wednesday morning; if you get the chance, drop by and say hi.

Oh, and don’t forget about those new resources for the PowerShell Toolbox. You say that, as much as you enjoy helping people, you need more motivation that just that? OK, how about this: we have a handful of Dr. Scripto bobbleheads lying around. Send us a suggestion by Friday morning at 8:00 AM, and we’ll toss your name into a hat. When we get back from Orlando we’ll draw names and award bobbleheads to 5 lucky souls. But you have to send us a suggestion for the PowerShell Toolbox by Friday morning to be eligible.

Deal? Deal.