Windows PowerShell Tip of the Week

Here’s a quick tip on working with Windows PowerShell. These are published every week for as long as we can come up with new tips. If you have a tip you’d like us to share or a question about how to do something, let us know.

Byte Conversion

WMI is one of the most useful management technologies available to system administrators; as you well know, you can use WMI to retrieve all sorts of cool information about your computers. The only problem is that WMI and system administrators don’t always speak the same language. For example, consider the following Windows PowerShell command, a command that uses WMI to return the amount of free disk space for all the drives on a computer. This is, admittedly, a somewhat odd-looking command, but there’s a reason why we did things this way, as you’ll see in a minute:

Get-WMIObject Win32_LogicalDisk | ForEach-Object {$_.freespace}

So, other than the odd syntax (typically you would use Select-Object to isolate a single property) what’s the problem with this command? Nothing, really; the command does go out and retrieve the amount of free disk space for all the drives on a computer. No, the problem isn’t so much with the command as it is with the way WMI reports back free disk space; as it so often does, WMI reports information as bytes rather than, say, gigabytes. That means we get back a report similar to this:

7385841664
19392094208

Quick: how many gigabytes in 19392094208 bytes? Don’t feel bad; we don’t have the slightest idea either.

Historically, scripters have always worked around this problem by doing a little math: they divide 19392094208 bytes by 1024, yielding 18937592 kilobytes. They then divide the kilobytes by 1024, resulting in 18493.7421875 megabytes. Finally, they divide that value by 1024, leaving a final answer of 18.06029510498046875 gigabytes. Whew!

Now, there’s nothing wrong with that, either; it’s just that it’s very easy to get mixed up and, say, divide by 1024 one too many or one too few times. In turn, that means the answer generated by your script is going to dramatically over-report (or under-report) free disk space on the computer. It would be far better and far more foolproof if you could just divide the number of bytes by a gigabyte. But you can’t.

Well, not unless you use Windows PowerShell, that is:

Get-WMIObject Win32_LogicalDisk | ForEach-Object {$_.freespace / 1GB}

Notice what we’re doing this time around. Once again we use Get-WMIObject to return information from the Win32_LogicalDisk class. And once again we pipe that information to the ForEach-Object cmdlet. This time, however, we don’t just display the value of the FreeSpace property. Instead, we divide that value by 1GB (1 gigabyte):

$_.freespace / 1GB

That’s right, Windows PowerShell has a built-in constant (GB) for converting values to gigabytes; it has similar constants for megabytes (MB) and kilobytes (KB). To convert bytes to gigabytes we don’t have to divide by 1024, then divide by 1024, then divide by 1024. Instead, we just divide by 1GB. (Note that there’s no space between the value and the constant.)

Does that really work? Of course it works:

6.8775634765625
18.0602951049805 

Pretty cool, huh? Would you rather see the amount of free megabytes on each drive? No problem; just divide the free space by 1MB:

Get-WMIObject Win32_LogicalDisk | ForEach-Object {$_.freespace / 1MB}

And here’s what we get back:

7043.0703125
18493.7421875

Here’s another use for these numeric constants. Suppose you have a file that uses 137 kilobytes of disk space. How many bytes is that? Well, let’s see. First, let’s run the following command:

137KB

Then let’s take a peek at what we get back:

140288

Nice. Ever wonder how many bytes 1 byte plus 1 kilobyte plus 1 megabyte plus 1 gigabyte adds up to? Well, to tell you the truth, we haven’t either. But if we ever did need to know that we could determine the answer by using this command:

1 + 1KB + 1MB + 1GB

And here is that answer that we’ve all been waiting for:

1074791425

What if you want this value in kilobytes? You already know the answer to that:

1074791425 / 1KB

Which turns out to be this:

1049601.00097656

Etc., etc. The numeric constants GB, MB, and KB. Why didn’t someone think of these a long time ago?

Special bonus tip. You make a good point: reporting back a value like 1049601.00097656 is kind of silly, isn’t it? (Typically we don’t need to measure free disk space to 8 decimal points.) With that in mind here’s a bonus command that strips off the decimal points:

Get-WMIObject Win32_LogicalDisk | ForEach-Object {[math]::truncate($_.freespace / 1GB)}

What we’re doing here is using the .NET Framework’s System.Math class ([math]) and the Truncate method to remove the decimal points and report free disk space as a whole number. You know, like this:

6
18

That’s more like it. For more information about the Truncate method, take a peek at our VBScript to Windows PowerShell Conversion Guide.