## Wednesday, March 7, 2012

### Using PowerCLI to find total space consumed by a VM

Say you have a VM named burger and you want to know the total disk space used by a VM in PowerCLI.

Get-VM burger | Get-HardDisk | Measure-Object -Property CapacityKB -Sum

Count    : 2
Average  :
Sum      : 157286400
Maximum  :
Minimum  :
Property : CapacityKB

The Sum value contains the total amount of kilobytes consumed by all disks connected to the VM. But what if you just want the value of Sum?

Get-VM burger | Get-HardDisk | Measure-Object -Property CapacityKB -Sum | Select-Object Sum
Sum
---
157286400
Still good, but what if you want just the number?

(Get-VM burger | Get-HardDisk | Measure-Object -Property CapacityKB -Sum).sum
157286400

That's the correct amount of kilobytes, but how can I convert that into gigabytes? Easy! Divide it by 1048576 (1024 multiplied by 1024)

(Get-VM burger | Get-HardDisk | Measure-Object -Property CapacityKB -Sum).sum/(1024*1024)
150

What if you want to add some text after the string?
((Get-VM burger | Get-HardDisk | Measure-Object -Property CapacityKB -Sum).sum/(1024*1024)).ToString() + " gigabytes consumed"
150 gigabytes consumed

That was easy! Now, let's see all the errors you could have made along the way.

((Get-VM burger | Get-HardDisk | Measure-Object -Property
CapacityKB -Sum).sum/(1024*1024)) + " gigabytes consumed"
Cannot convert value "gigabytes consumed" to type "System.Double". Error: "Input string was not in a correct format."
At line:1 char:102
+ ((Get-VM burger | Get-HardDisk | Measure-Object -Property CapacityKB
-Sum).sum/(1024*1024)) + <<<<  "gigabytes consumed"
+ CategoryInfo          : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException

This error is caused by trying to add two incompatible values. Let's separate this command into a blue and green segments.

((Get-VM burger | Get-HardDisk | Measure-Object -Property
CapacityKB -Sum).sum/(1024*1024)) + " gigabytes consumed"

This blue code produces a number of type System.Double. We can verify this by using the Get-Members cmdlet.

((Get-VM burger | Get-HardDisk | Measure-Object -Property CapacityKB -Sum).sum/(1024*1024)) | Get-Member

TypeName: System.Double

Name        MemberType Definition
----        ---------- ----------
CompareTo   Method     int CompareTo(System.Object value), int CompareTo(dou...
Equals      Method     bool Equals(System.Object obj), bool Equals(double obj)
GetHashCode Method     int GetHashCode()
GetType     Method     type GetType()
GetTypeCode Method     System.TypeCode GetTypeCode()
ToString    Method     string ToString(), string ToString(string format), st...

Now let's evaluate the second part of the command. +"gigabytes consumed" is a System.String object. This is obvious (it's in inverted commas), but you can pipe it into the Get-Member cmdlet if you want to check.

The reason why you received the error message Cannot convert value "gigabytes consumed" to type "System.Double is because PowerShell tries to cast (convert) the second operand (a string) in to the type of the first operand (a double). You can't convert the string "gigabytes consumed" into a bunch of numbers, but you can do the reverse! Let's pick up the +"gigabytes consumed: " bit of code and drop it at the beginning.

"gigabytes consumed: " + ((Get-VM burger | Get-HardDisk | Measure-Object -Property CapacityKB -Sum).sum/(1024*1024))
gigabytes consumed: 150

Awesome, it works! PowerShell casted the results of the double into a string. But what if we don't want the string before the value? We can use the .ToString() function to cast the double into a string.

(Get-VM burger | Get-HardDisk | Measure-Object -Property C
apacityKB -Sum).sum/(1024*1024).ToString() + " gigabytes consumed"
Cannot convert value "gigabytes consumed" to type "System.Double". Error: "Input string was not in a correct format."
At line:1 char:111
+ (Get-VM burger | Get-HardDisk | Measure-Object -Property CapacityKB -Sum).sum/(1024*1024).ToString() + <<<<  "gigabytes consumed"
+ CategoryInfo          : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException

WHAT?! We used ToString()! Why did it throw a casting error? Oh, wait, I only casted the (1024*1024) part. I need to evaluate the entire blue code block then cast to a string.

((Get-VM burger | Get-HardDisk | Measure-Object -Property
CapacityKB -Sum).sum/(1024*1024)).ToString() + " gigabytes consumed"
150 gigabytes consumed

That's better. And that's it!