Use PowerShell and Conditional Formatting to Format Numbers

Use PowerShell and Conditional Formatting to Format Numbers

  • Comments 7
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell and conditional formatting to format numbers.

Hey, Scripting Guy! Question Hey, Scripting Guy! One of the big problems I have when it comes to using Windows PowerShell is figuring out how to properly format numbers. I mean, I can easily use [int] to get rid of hundreds of decimal places, but it is the other things that cause me fits. Help!

—MI

Hey, Scripting Guy! Answer Hello MI,

Microsoft Scripting Guy, Ed Wilson, is here. I just got off of the phone with the TechEd group. We were discussing plans for the Scripting Guys booth at TechEd in New Orleans, LA. Yes, that is right. If you have not heard, TechEd 2013 is in New Orleans this year. It runs from June 3 – June 6, 2013, and right now, there is a $300.00 discount on the price.

Image of TechEd logo 

Note   This is the third blog post in a series of five that talk about using format methods and operators in Windows PowerShell. The first blog, Understanding PowerShell and Basic String Formatting, provided a great overview to the basics of using the Format method from the String class and the Format operator from Windows PowerShell for composite formatting. The second blog, Use PowerShell to Format Strings with Composite Formatting, dove deeply into the use of composite formatting and using various format specifiers.

Understanding number format specifiers

There are many times when I need to format numbers in various ways. Luckily, I do not have to reinvent the wheel when it comes to consistent number formatting. I can use the standard numeric format specifiers, which are documented on MSDN. By using these format specifiers, I can easily display a number as one of the following.

  Currency “C”

  Decimal “D”

  Exponential “E” 

  Fixed-Point “F”

  General “G”

  Number “N”

  Percent “P”

  Hexadecimal “H”

Note  For reference information about this technique, see Composite Formatting on MSDN. For detailed information about standard format specifiers, see Standard Numeric Format Strings.

Formatting percentages by using a format specifier

When converting a number into a percentage the process usually involves multiplying the number by 100 and displaying a percentage sign.

Note   For a good example of this, using the standard number “N” format specifier, see Weekend Scripter: The Scripting Wife Talks about the First Warm-Up Event in the Winter Scripting Games.

Suppose in my calculations I arrive at the number 5/21, and I want to express it as a percentage. If I use normal formatting, I would need to use a formula such as the following.

PS C:\> (5/21)*100

23.8095238095238

The problem is that I have a LOT of decimal places. I can use the Scripting Wife’s technique to get down to two places by using the “F” format specifier as shown here:

PS C:\> "{0:N2}" -f ((5/21)*100)

23.81

This technique works great, but by using the “P” Percent standard numeric format specifier, I can shorten the amount of work a bit.

Example 1: Write percentage to console

In this example, I store the result of 5/21 into a variable I call $percent. If I look at the value stored in the $percent variable, I see the following:

PS C:\> $Percent

0.238095238095238

To display the value as a percentage, I do not need to multiple by 100 and use techniques to return two decimal places. Instead, all I need to do is use composite formatting. In the format item, I first specify an index number for the object substitution, and then I use a format string to specify that I want to display the output as a percentage. When I do this, the “P” format specifier multiplies the output by 100 and by default displays two decimal places. This is a REAL time saver! The following code illustrates this technique.

PS C:\> $Percent = 5/21

PS C:\> [console]::WriteLine("{0:P}",$percent)

23.81 %

Example 2: Using an overload for the ToString method

In Windows PowerShell, everything is an object—even numbers. This means that an ordinary integer still has methods and properties. One of the more useful (at least for me) methods is the ToString method. In fact, I use this method from time-to-time when I want to do things such as write numeric values to the registry. One of the really cool features of the ToString method is that is has an overload that permits me to use a format specifier.

Example 2A: Store value in a variable and call a method

In Example 2A, I perform my calculation and store the results in the $percent variable. I use that variable inside the WriteLine method, and I call the ToString method and specify that I want to use format specifier “P.” The advantage of this methodology is that it permits you to avoid using conditional formatting by calling the overload of the ToString method.

PS C:\> $Percent = 5/21

PS C:\> [console]::WriteLine(($percent).ToString("P"))

23.81 %

Example 2B: Compute a value inside a method call

In Example 2B, I perform the computation directly inside the method call. The advantage is that this creates a one-line command that is not dependent on an external variable.

PS C:\> [console]::WriteLine((5/21).ToString("P"))

23.81 %

Example 3: Use the Windows PowerShell Format operator

The most concise methodology of using the “P” format specifier to display your output as a percentage is to use the Windows PowerShell Format operator (-f). As I said yesterday, when you get the hang of reading it, it is the shortest way to do your formatting. Following are two examples of using the Windows PowerShell format operator.

Example 3A: Store results in a variable and call with the operator

In Example 3A, I store the results of my computation in a variable that I call $percent. I then use conditional formatting, and in my format item, I specify the first index value (0) to display as a percentage. The “P” format specifier goes in the second half of the format item. On the other side of the –f Windows PowerShell format operator, I use the $percent variable to pass my object to the format item. Here is the script.

PS C:\> $Percent = 5/21

PS C:\> "{0:P}" -f $Percent

23.81 %

Example 3B: Use the computation directly

In Example 3B, I do not need to use an intermediate variable. I can use conditional formatting directly as shown here.

PS C:\> "{0:P}" -f (5/21)

23.81 %

Example 4: Specify more than (or less than) two decimal places

In my format item (the “{0:P}” part of the conditional formatting string), I can specify precision on the right side of the “P” format specifier. In this way, I can display a percentage as three decimal places, one decimal place, or whatever value is appropriate. This technique is shown here.

PS C:\> "{0:P3}" -f (5/21)

23.810 %

Example 5: Compute percentages with admin constants

The admin constants (KB, MB, GB) make it easy to work with data that is returned from my computer. For example, the following command returns basic process information about the Explorer process on my computer.

PS C:\> Get-Process explorer

 

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

-------  ------    -----      ----- -----   ------     -- -----------

   1818      96    47684     113708   623    18.21   1328 explorer

OK, so the process is using 623 megabytes of virtual memory. Is this good or bad? I need to compare it to total system memory, which on my new laptop is 16 gigabytes. Dude, I do not want to mess with all that math. No problem. The “P” format specifier can handle it. Here are the results.

PS C:\> "{0:P}" -f (623MB/16GB)

3.80 %

Revisiting the Scripting Wife’s solution

The real power of using conditional formatting, format specifiers, format items, and the like is that I can incorporate it with my other Windows PowerShell “tricks” to arrive at really powerful and useful solutions.

The Scripting Wife came up with a great one-liner to show the percentage of disk utilization on her system. In her solution, she used a number of great Windows PowerShell tricks including conditional formatting. (I do not think she knew that is what she was doing, but she did find a great example to adapt to her needs).

She also used a great trick with the Select-Object cmdlet where she created a custom property on the outputted object. This is powerful stuff. So the only thing I am going to do is steal her code, and modify it to use the “P” format specifier instead of using the “N” format specifier.

gwmi win32_volume |

ft DriveLetter, FreeSpace, Capacity,

@{Label="PercentFree";Expression= {"{0:P}" -f ($_.freespace / $_.capacity)}}

MI, that is all there is to using Windows PowerShell to format numbers by using conditional formatting. Formatting Week will continue tomorrow when I will talk about formatting dates. It is fun. It is powerful. And you really, really do not want to miss it. See you then.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • In Example 5, the process "explorer" does not refer to Internet Explorer as mentioned. The process name would be "iexplore".

  • @Someone you are correct. I have updated the example to fix that. Thanks for catching it.

  • conditional formatting? You must have meant composite formatting.

  • One aspect about formatting numbers in PowerShell I find very annoying is rounding. The commands

    [int] 1.5

    "{0:N0}" -f 1.5

    give answers of 2, which clearly are not the integer part of 1.5. If I wanted to round it, then I would use

    [math]::round(1.5)

    Because of this "bug" I have to use

    [math]::floor(1.5)

    Could someone explain why the PowerShell development team decided to use rounding instead of simply returning the integer? The first time this "feature" bit me was a rather painful experience.

  • @Paul

    This works fine for me:

    PS > [int]2.5

    2

    PS > [int]4.5

    4

    PS > [int]6.5

    6

    Everyone truncates the integer.  Perhaps some of your numbers are busted.

  • Another tip I use, when looking at Disk drives, is to filter out anything that isn't a local disk

    e.g. in your final example I would change the first line to this

    gwmi win32_volume -filter drivetype=3  |

  • One question I have is, when I use

        $_.freespace/1mb

    I get  an answer of 356372.5703125

    If I try to format that with

        "Free: " + "{0:N0}" -f $_.freespace/1mb + "MB"

    I get the error

        Cannot convert value "373,683,826,688" to type "System.Int32". Error: "Input string was not in a correct format."

    However if I store the result in a variable, e.g. $freespace it works

        $freespace = $_.freespace/1mb

        "Free: " + "{0:N0}" -f $freespace + "MB"

    Gives a result of

        Free: 356,372MB

    Why does this work but the previous way doesn't?