Weekend Scripter: Use PowerShell to Calculate and Display Percentages


Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to calculate and display percentages.

Microsoft Scripting Guy, Ed Wilson, is here. This morning, I am sipping a cup of red berry tea. It is tangy and refreshing. I will admit that I cheated. I used our machine. Boom! 90 seconds later it was done. I guess I could actually do that in my sleep.

Of course, I do not make tea in my sleep, but I do sometimes write Windows PowerShell script while I am dozing. When this happens, I need to get to work quickly—before I forget what I was thinking about.

In Windows 8.1, Windows 8, Windows Server 2012 R2, and Windows Server 2012, there is a function named Get-Volume. It provides a decent default output, and I use it quite a lot actually.

Note  This function requires that the Windows PowerShell console or the Windows PowerShell ISE is opened with Administrator rights (or it generates an error message). But the message does not say that you do not have permission or rights. Instead it says, “Access to a CIM resource was not available to the client.” To figure out that it is a permission denied scenario, I need to look a bit further in the error message, where I will see the following: “+ CategoryInfo  : PermissionDenied:”

Here is the standard output from the Get-Volume function:

PS C:\> get-volume

DriveLetter  FileSystemLabel  FileSystem DriveType  HealthStatus  SizeRemaining  Size

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

     C             SSD                     NTFS        Fixed       Healthy        72.65 GB    148.53 GB

     E            HybridTer...          NTFS         Fixed      Healthy        560.81 GB   931.39 GB

                    Recovery             NTFS        Fixed       Healthy        22.96 MB      300 MB

I like the drive letter, label, size, and size remaining.  I already know the drives are fixed, and I am glad that they do not have any social diseases and are therefore healthy. But what I want to know is the percentage of utilization. I really cannot do a whole lot with the statistic "150 GB," but if I see that it is 85% utilized, I know that maybe I am starting to have an issue.

I can obtain this same information by using Windows PowerShell 2.0 (or even Windows PowerShell 4.0 on Windows 7) by directly querying the WMI class. Here is an example:

Get-CimInstance win32_volume | Select DriveLetter, Label, FileSystem, DriveTYpe, FreeSpace, Capacity

Following is the output from this command. I would need to do a bit more work to display the output in gigabytes and in megabytes. I wrote a function a long time ago that I would use to display the output in the appropriately sized units.

DriveLetter : C:

Label       : SSD

FileSystem  : NTFS

DriveTYpe   : 3

FreeSpace   : 78011699200

Capacity    : 159486308352

 

DriveLetter : E:

Label       : HybridTerrabyte

FileSystem  : NTFS

DriveTYpe   : 3

FreeSpace   : 602152972288

Capacity    : 1000068870144

 

DriveLetter :

Label       : Recovery

FileSystem  : NTFS

DriveTYpe   : 3

FreeSpace   : 24080384

Capacity    : 314568704

Getting the percentage volume utilization

In the past, I would always make the calculation, and then format the output. Following, is an example of doing that. (This is a one-line command that I broke at the pipe character.)

PS C:\> get-volume |

select driveletter, FilesystemLabel, @{L='pct used';E={"{0:N2}" -f (($_.sizeremaining/$_.size)*100)}}

 

                  driveletter FilesystemLabel      pct used

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

                            C SSD                           48.91

                            E HybridTerrabyte               60.23

                              Recovery                      7.66

That works, but it is actually quite a bit of work, and it is not all that easy to understand. I am using conditional formatting, and I am specifying that I want a number with two decimal places. It is pretty easy to get this wrong.

I was thinking about this last night, and I realized there is a much easier way to accomplish the same task. It also gives me quite a bit of control over the process. I am going to create a new instance of the System.Globalization.CultureInfo class, and specify en-us culture. I store the returned object in the $nfi variable. Here is that line:

$nfi = New-Object System.Globalization.CultureInfo -ArgumentList "en-us",$false

Now I decide that I want to define the number of digits used for percentages to be four decimal places. (For more information, see NumberFormatInfo.PercentDecimalDigits Property.) This is a straightforward value assignment, as shown here:

$nfi.NumberFormat.PercentDecimalDigits = 4

Now that I have done that, I am going to use the ToString method from the numbers and specify that I want percentage number formatting (see The Percent ("P") Format Specifier). I also specify my customized CultureInfo object with the custom number format for decimal places for percentages. Here is the command (again, it is a single line that is broken at the pipe character):

get-volume |

select driveletter, FilesystemLabel, @{L='pct used';E={($_.sizeremaining/$_.size).ToString("P", $nfi)}}

The command the associated output are shown here:

Image of command output

This is actually easier than it looks. For example, if I do not want to customize the way my percentages display, I can use the default. There is already an instance the CultureInfo class at work in the Windows PowerShell console. I can examine it by using the Get-Culture cmdlet, as shown here:

PS C:\> $c = Get-Culture

PS C:\> $c.NumberFormat.PercentDecimalDigits

2

By not specifying a custom number format, I can use these defaults. This is shown here:

PS C:\> get-volume |

select driveletter, FilesystemLabel, @{L='pct used';E={($_.sizeremaining/$_.size).ToString("P")}}

 

                  driveletter FilesystemLabel      pct used

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

                            C SSD                           48.91 %

                            E HybridTerrabyte               60.23 %

                              Recovery                      7.66 %

If I want to change the default behavor, for example, for the number of percentage decimal places, I simply write a new value, as shown here:

PS C:\> $c = Get-Culture

PS C:\> $c.NumberFormat.PercentDecimalDigits = 4

PS C:\> get-volume | select driveletter, FilesystemLabel, @{L='pct used';E={($_.sizeremain

ing/$_.size).ToString("P")}}

 

                  driveletter FilesystemLabel       pct used

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

                            C SSD                           48.9057 %

                            E HybridTerrabyte               60.2304 %

                              Recovery                      7.6550 %

This behavior will exist until I close the Windows PowerShell console. If I want a permanent solution, I add the command to my Windows PowerShell profile.

I hope you have an awesome day, and I will see you tomorrow.

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 

Comments (6)

  1. I used a similar concept in one of my scripts. Very useful

  2. nag says:

    Am I missing something? isn’t it calculating percentage remaining rather than percent used?
    Btw, nice articles – I like these (some food for thought every day :)).
    Regards.

  3. Steve says:

    I think you’re right, the calculation should be:
    @{L=’pct used’;E={($_.size – $_.sizeremaining)/$_.size).ToString("P")}}

  4. Theo says:

    For those of us stuck with PS 3.0 I had this solution. Not quite as elegant, but it does seem to work.
    get-psdrive|%{
    If ($_.Used){
    $_|select Name, @{name=’Used’;Expression={"{0:N2}" -f ( $_.Used/1024/1024/1024)}}, @{name=’Free’;Expression={ "{0:N2}" -f ($_.Free/1024/1024/1024)}}, @{name=’Pct Used’;Expression={"{0:N2}" -f ($_.Used / ($_.Used + $_.Free) * 100 )}}
    }
    }

  5. Daniel says:

    Why not use {0:P2} instead to let powershell handle the percentage??

  6. Stephen Zhou says:

    Thanks Ed for the percentage tips, a little difference with ur way but same result

    $disksObj = Get-WmiObject Win32_LogicalDisk
    # Weekend Scripter: Use PowerShell to Calculate and Display Percentages
    # Ref:
    http://blogs.technet.com/b/heyscriptingguy/archive/2014/10/11/weekend-scripter-use-powershell-to-calculate-and-display-percentages.aspx
    $nfi = New-Object System.Globalization.CultureInfo -ArgumentList "en-us",$false
    $nfi.NumberFormat.PercentDecimalDigits = 2
    Foreach ($diskObj in $disksObj) {
    #$diskObj
    #$diskObj.Size
    # Powershell: check variable for null
    # Ref:
    http://www.thomasmaurer.ch/2010/07/powershell-check-variable-for-null/
    # Show the disks which is exist really
    If ($diskObj.Size) {
    $diskID = $diskObj.DeviceID
    $diskFreeSpace = $diskObj.FreeSpace
    $diskSize = $diskObj.Size
    $diskUsagePerc = ($diskSize-$diskFreeSpace)/$diskSize
    Write-Host $diskID,$diskUsagePerc.ToString("P", $nfi)
    }
    }

    Result:
    C: 34.65 %
    D: 0.15 %

Skip to main content