Converting to size units – our solution and the winner

The task was to convert a number to the size units without using the built-in multipliers. Thank you all for taking the time to participate in this teaser.

Now, let’s present the solution we had in mind. Starting with PowerShell 3.0, we now have two new bitwise arithmetic operators: shift-left (shl) and shift-right (shr). You can read more about them in the about_Comparison_Operators help topic.

The solution to this teaser is using the shift-right operator to convert the value of given number (representing a value in bytes).

Generally speaking, shifting right a number divides it by 2 and rounds the number down. Each division takes the result of the last operation and divides it again by 2.

PS> 100 -shr 1

PS> 100 -shr 2

PS> 100 -shr 3

Now, let’s take the value of 1KB: 1024. To get to 1024 we need to raise 2 in the power of 10. For 1MB (1048576), we need to raise it in the power of 20. 30 for 1GB, 40 for 1PB and so on and so forth.

PS> [math]::Pow(2,10)

PS> [math]::Pow(2,20)

PS> [math]::Pow(2,30)

We can use the values 10, 20, 30… and shift-right by them to get the corresponding unit sizes in KB, MB, GB…. We will use the value of 13947906293.76 (that’s 12.99GB, actually).

$value = 13947906293.76

# get the value in KB
PS> $value -shr 10

# get the value in MB
PS> $value -shr 20

# get the value in GB
PS> $value -shr 30

If you happen to manage Exchange 2007/2010 you are probably familiar with the size formatting ToKB/ToMB/ToGB/ToTB methods. Actually I owe the idea for this teaser to the Exchange team–they calculate the requested size by shifting right the value.

The formatting methods are available on ByteQuantifiedSize objects ([Microsoft.Exchange.Data.ByteQuantifiedSize]).

Here’s a list of ByteQuantifiedSize properties of a Mailbox object:

(Get-Mailbox shay).PSObject.Properties |
Where-Object {$_.TypeNameOfValue -like "*ByteQuantifiedSize*"} |
Format-Table name


To format the size of ByteQuantifiedSize property, you refer to its Value property and then to one of the above methods:

PS> $mbx.ArchiveQuota
IsUnlimited Value
----------- -----
  False 50 GB (53,687,091,200 bytes)

PS> $mbx.ArchiveQuota.Value | Get-Member
   TypeName: Microsoft.Exchange.Data.ByteQuantifiedSize
Name          MemberType Definition
----          ---------- ----------
CompareTo     Method     int CompareTo(Microsoft.Exchange.Data.ByteQuantifiedSize other), int IComparable.CompareTo(...
Equals        Method     bool Equals(System.Object obj), bool Equals(Microsoft.Exchange.Data.ByteQuantifiedSize other)
GetHashCode   Method     int GetHashCode()
GetType       Method     type GetType()
RoundUpToUnit Method     uint64 RoundUpToUnit(Microsoft.Exchange.Data.ByteQuantifiedSize+Quantifier quantifier)
ToBytes       Method     uint64 ToBytes()
ToGB          Method     uint64 ToGB()
ToKB          Method     uint64 ToKB()
ToMB          Method     uint64 ToMB()
ToString      Method     string ToString(), string ToString(string format), string ToString(string format, System.IF...
ToTB          Method     uint64 ToTB()

PS> $mbx.ArchiveQuota.Value.ToGB()

Now to the prize. Congratulations Jaap Brasser and Rob Campbell, you get to take with you a copy of the Windows Server 2012 Automation with PowerShell Cookbook eBook. We would like to thank again Packt Publishing for the eBooks.

Jaap and Rob, in the best commmunity spirit, came up with the solution that was the shortest one that returns the right results for all five supported unit sizes:

PS> $s = 12345678964561111
PS> 1..5|%{[long](($s/=1024)-.5)}

Let’s rewrite our solution in the same manner:

PS> 1..5|%{$s -shr 10*$_}

Amazingly, we can even remove all spaces, and it’ll still work:

PS> 1..5|%{$s-shr10*$_}

See you in the next brainteaser. 🙂

Share on:
comments powered by Disqus