VMware Cloud Community
VM_Us3r
Contributor
Contributor
Jump to solution

VM Provisioned space per each connected Datastore

  I have been having issues trying to pull the provisioned space per connected datastore of each VM.  I can get the total provisioned space of the VM via 'ProvisionedGB' but this total is across all of the VM's connected datastores.  What I need is a .CSV that contains a breakdown of all datastores connected to each VM and the provisioned space that VM is using on each connected datastore.  I have modified several scripts but I am uncertain on how to get this information.  Most scripts I have worked with look something like the line below where it only pulls one of the connected datastores.

"where {$_.ID -match (($vmview.Datastore | Select -First 1) | Select Value).Value}"

Currently, I am pulling the below details and I realize there will be redundant info this way if we add additional rows for each disk and/or datastore.  I am open to other suggestions you may have. 

(Current Column Layout)

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

| VMName | Powerstate | OS | IPAddress | ToolsStatus | NumCPU | MemGB | Datastore | DiskType | DiskGb | DiskFree | DiskUsed | ProvisionedSpace |

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

Perhaps adding each datastore name to the columns would help prevent redundant data and simply add the VM's provisioned space of that specific datastore to these columns? 

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

Example:  | VMName | etc. | Datastore_1 | Datastore_2 | Datastore_3 |

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

.

..

...

  Anyway, below is the current script I have been modifying.  As you can see it will only pull one connected datastore per VM although the VM's have multiple datastores attached.  The "Guest.Disks" and "ProvisionedSpaceGB" properties will measure all VM guest disks and provisioned space regardless of what datastore.  I need to figure out how to break these fields down to a per datastore equation for each VM guest. 

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

START SCRIPT:

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

filter Get-FolderPath {

    $_ | Get-View | % {

        $row = "" | select Name, Path

        $row.Name = $_.Name

        $current = Get-View $_.Parent

        $path = ""

        do {

            $parent = $current

            if($parent.Name -ne "vm"){$path = $parent.Name + "\" + $path}

            $current = Get-View $current.Parent

        } while ($current.Parent -ne $null)

        $row.Path = $path

        $row

    }

}

$VCServerName = "vsphere.com"

$VC = Connect-VIServer $VCServerName

$ExportFilePath = "C:\TEST.csv"

$Report = @()

$VMs = Get-VM | Where-Object { $_.Name -like 'Client*' }

$Datastores = Get-Datastore | select Name, Id

$VMHosts = Get-VMHost | select Name, Parent

ForEach ($VM in $VMs) {

      $VMView = $VM | Get-View

      $VMInfo = {} | Select VMName, Powerstate, OS, IPAddress, ToolsStatus, NumCPU, MemGB, Datastore, DiskType, DiskGb, DiskFree, DiskUsed, ProvisionedSpace

      $VMInfo.VMName = $vm.name

      $VMInfo.Powerstate = $vm.Powerstate

      $VMInfo.OS = $vm.Guest.OSFullName

      $VMInfo.IPAddress = $vm.Guest.IPAddress[0]

      $VMInfo.ToolsStatus = $VMView.Guest.ToolsStatus

      $VMInfo.NumCPU = $vm.NumCPU

      $VMInfo.MemGB = [Math]::Round(($vm.MemoryGB),2)

      $VMInfo.Datastore = ($Datastores | where {$_.ID -match (($vmview.Datastore | Select -First 1) | Select Value).Value} | Select Name).Name

      $VMInfo.DiskType = $DiskTypes[$VMInfo.Datastore]

      $VMInfo.DiskGb = [Math]::Round((($vm.Guest.Disks | Measure-Object -Property CapacityGB -Sum).Sum),2)

      $VMInfo.DiskFree = [Math]::Round((($vm.Guest.Disks | Measure-Object -Property FreeSpaceGB -Sum).Sum),2)

      $VMInfo.DiskUsed = $VMInfo.DiskGb - $VMInfo.DiskFree

      $VMInfo.ProvisionedSpace = [math]::round(($vm.ProvisionedSpaceGB), 2)

      $Report += $VMInfo

}

$Report = $Report | Sort-Object VMName

IF ($Report -ne "") {

    $report | Export-Csv $ExportFilePath -NoTypeInformation

}

$VC = Disconnect-VIServer -Confirm:$False

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

END SCRIPT:

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

Reply
0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

Try like this

$dcName = 'MyDC'

$vmMask = 'MyRegEx'


$dc = Get-View -ViewType Datacenter -Property Name -Filter @{Name = "^$($dcName)$"}


# Get the harddisk info for each VM

$hdInfo = Get-View -ViewType VirtualMachine -SearchRoot $dc.MoRef -Filter @{Name = "$($vmMask)"} -PipelineVariable vm |

   ForEach-Object -Process {

   $vm.Config.Hardware.Device | where {$_.DeviceInfo.Label -like "Hard disk *"} |

   ForEach-Object -Process {

   $hd = $_

   $vm.LayoutEx.Disk | where {$_.Key -eq $hd.Key} | % {

   $diskFiles = $_.Chain | % {$_.FileKey} | % {$_}

   }

   $diskAllocated = 0

   $vmdkName = $vm.LayoutEx.File | where {$_.Key -eq $diskFiles[0]} | select -ExpandProperty Name

   $vm.LayoutEx.File | where {$diskFiles -contains $_.Key} | % {

   $diskAllocated += $_.Size

   }

   $obj = New-Object PSObject -Property @{

   VMname = $vm.Name

   PowerState = $vm.Runtime.PowerState

   OS = $vm.Guest.GuestFullName

   IP = & {

   if ($vm.Guest.IpAddress) {

   @($vm.Guest.IPAddress)[0]

   }

   }

   ToolsStatus = $vm.Guest.ToolsStatus

   NumCpu = $vm.Config.Hardware.NumCPU

   MemGB = $vm.Config.Hardware.MemoryMB / 1KB

   Label = $hd.DeviceInfo.Label

   Path = $vmdkName

   Provisioned_GB = ("{0:N1}" -f ($hd.CapacityInKB / 1MB))

   }

   $obj

   }

}


# Get all datastores

$dsNames = $hdInfo | Group-Object -Property {$_.Path.Split(' ')[0].Trim('[]')} |

   ForEach-Object -Process {

   $_.Name

} | Sort-Object


# Summarise harddisk per datastore per VM

$report = @()

$hdInfo | Sort-Object -Property VMName |

   Group-Object -Property VMname |

   ForEach-Object -Process {

   $vm = Get-View -ViewType VirtualMachine -Filter @{Name = "^$($_.Name)$"}

   $obj = [ordered]@{

   VMname = $vm.Name

   PowerState = $vm.Runtime.PowerState

   OS = $vm.Guest.GuestFullName

   IP = & {

   if ($vm.Guest.IpAddress) {

   @($vm.Guest.IPAddress)[0]

   }

   }

   ToolsStatus = $vm.Guest.ToolsStatus

   NumCpu = $vm.Config.Hardware.NumCPU

   MemGB = $vm.Config.Hardware.MemoryMB / 1KB

   }


   # Add a column for each datastore

   $dsNames | ForEach-Object -Process {

   $obj.Add($_, '')

   }


   # Get the total size per datastore

   $_.Group | Group-Object -Property {$_.Path.Split(' ')[0].Trim('[]')} |

   ForEach-Object -Process {

   $totalGB = ($_.Group | Measure-Object -Property Provisioned_GB -Sum).Sum

   $obj.Item($_.Name) = $totalGB

   }

   $report += New-Object psobject -Property $obj

}

$obj = [ordered]@{

   VMname = 'Total'

   PowerState = ''

   OS = ''

   IP = ''

   ToolsStatus = ''

   NumCpu = ''

   MemGB = ''

}

$dsNames | ForEach-Object -Process {

   $dsName = $_

   $sum = $report | Measure-Object -Property $dsName -Sum | select -ExpandProperty Sum

   $obj.Add($dsName, $sum)

}

$report += (New-Object PSObject -Property $obj)

$report | Export-Csv -Path .\report.csv -NoTypeInformation -UseCulture


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

27 Replies
LucD
Leadership
Leadership
Jump to solution

Do you mean something like this one Re: VM Guest HDD percentage ?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
VM_Us3r
Contributor
Contributor
Jump to solution

 
No, that is closer to what I need but still not quite what I am looking for.  I did try working with this script you suggested but it does not report VM provisioned space per datastore when the VM has disks connected on multiple datastores. 
 
EXAMPLE:  (VM_Guest)  Disk 1 = 100GB on Datastore 4, Disk 2 = 300GB on Datastore 4, Disk 3 = 50GB  on Datastore 1
 
The initial script in the suggested thread will report the below details which is correct for the overall VM but it is not correct for the actual provisioned space on the datastore.  Regardless if I run the script against datastore_1 or datastore_4 I will get the same results below.
 
Name            : (VM_Guest)
GuestUsageGB    : 101.9
GuestCapacityGB : 449.26
FreeSpaceGB     : 347.4
GuestUsage(%)   : 22.67
 
I also modified and ran the larger combined script (Attached) in that thread as well against both datastore_1 and datastore_4 and also recieved the same results for both datastores.  That larger script however would only see 2 of the 3 disks for some reason as it did not not report the OS disk for Disk1.  
 
What I need to report is the provisioned space per datastore for each VM.  So for the example above I would need Disk 3 reported as 50GB provisioned for Datastore_1 and then Disk 1 and 2 combined for 400GB provisioned on datastore_4.  Doesn't even really have to be combined as long as it reports provisioned space properly for each VM per datastore.
 
------------------------------------------------------- 
 | Name | Datastore_1 | Datastore_4 |  
------------------------------------------------------- 
 | VM_Guest |  50GB   |  400GB
-------------------------------------------------------
 
I hope this makes more sense now.  Thanks 
 
 
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Ok, got it.
That would mean that we have to summarise the space used by each VDMK on a specific datastore.

But a VMDK might be Thin provisioned, meaning it might actually use less than it was configured for.

In my Yadr – A Vdisk Reporter post, I take this into account.
Starting from that result, and by using the Path property, we can extract the datastore.

If we then group the result per VM and per datastore, we should be close to your goal.

The only thing that this will not cover, is the storage space taken by the VM for other files besides VMDK.

These include logs, swap space, BIOS settings...

Do you have all the info you are looking for in the yadr report.
We can always rearrange the layout of the report.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
VM_Us3r
Contributor
Contributor
Jump to solution

Great, this is very helpful!

I have cut down the yadr to remove all snapshot related lines as they are not used in my environment.  I have attached the modified script that results in the output below.

VMname

Label

Path

Provisioned_GB

VM_Name01

Hard disk 1

[DS_SSD_1] VM_Name01/VM_Name01.vmdk

70

VM_Name01

Hard disk 2

[DS_SSD_1] VM_Name01/VM_Name01_1.vmdk

120

VM_Name02

Hard disk 1

[DS_SATA_2] VM_Name02/VM_Name02.vmdk

70

VM_Name02

Hard disk 2

[DS_SAS_4] VM_Name02/VM_Name02_1.vmdk

100

I am not able to add the initial VMInfo data into this loop however.  Not sure what is needed to combine this script with the original.

What I would like to do is combine the Disk "Provisioned_GB" above into each datastore per VM as laid out below.   Please assist in this if possible.  Thanks!

VMName

Powerstate

OS

IPAddress

ToolsStatus

NumCPU

MemGB

DS_SSD_1

DS_SATA_2

DS_SAS_4

VM_Name01

poweredOn

Win

0.0.0.0

Ok

2

8

190

                 0

                                   0         

VM_Name02

poweredOn

Linux

0.0.0.0

Ok

4

16

               0

70

100

LucD
Leadership
Leadership
Jump to solution

Try like this.

The funny Sort-Object at the end is to avoid an issue with Export-Csv.
Normally it uses the number of properties on the 1st object to determine how many columns there will be in the CSV.

Note that the vmName is a RegEx expression, not a meta-character -like mask.

For example, setting $vmName to 'Test', will return all VMs that have the string 'Test' in their DisplayName

$dcName = 'YourDatacenter'

$vmMask = 'VM-Name-RegEx'


$dc = Get-View -ViewType Datacenter -Property Name -Filter @{Name = "^$($dcName)$"}

Get-View -ViewType VirtualMachine -SearchRoot $dc.MoRef -Filter @{Name = "$($vmMask)"} -PipelineVariable vm |

   ForEach-Object -Process {

   $vm.Config.Hardware.Device | where {$_.DeviceInfo.Label -like "Hard disk *"} |

   ForEach-Object -Process {

   $hd = $_

   $vm.LayoutEx.Disk | where {$_.Key -eq $hd.Key} | % {

   $diskFiles = $_.Chain | % {$_.FileKey} | % {$_}

   }

   $diskAllocated = 0

   $vmdkName = $vm.LayoutEx.File | where {$_.Key -eq $diskFiles[0]} | select -ExpandProperty Name

   $vm.LayoutEx.File | where {$diskFiles -contains $_.Key} | % {

   $diskAllocated += $_.Size

   }

   $obj = New-Object PSObject -Property @{

   VMname = $vm.Name

   PowerState = $vm.Runtime.PowerState

   OS = $vm.Guest.GuestFullName

   IP = & {

   if ($vm.Guest.IpAddress) {

   $vm.Guest.IPAddress[0]

   }

   }

   ToolsStatus = $vm.Guest.ToolsStatus

   NumCpu = $vm.Config.Hardware.NumCPU

   MemGB = $vm.Config.Hardware.MemoryMB / 1KB

   Label = $hd.DeviceInfo.Label

   Path = $vmdkName

   Provisioned_GB = ("{0:N1}" -f ($hd.CapacityInKB / 1MB))

   }

   $obj

   }

} |

   Group-Object -Property VMname |

   ForEach-Object -Process {

   $vm = Get-View -ViewType VirtualMachine -Filter @{Name = "^$($_.Name)$"}

   $obj = [ordered]@{

   VMname = $vm.Name

   PowerState = $vm.Runtime.PowerState

   OS = $vm.Guest.GuestFullName

   IP = & {

   if ($vm.Guest.IpAddress) {

   $vm.Guest.IPAddress[0]

   }

   }

   ToolsStatus = $vm.Guest.ToolsStatus

   NumCpu = $vm.Config.Hardware.NumCPU

   MemGB = $vm.Config.Hardware.MemoryMB / 1KB

   }

   $_.Group | ForEach-Object -Process {

   $dsName = $_.Path.Split(' ')[0].Trim('[]')

   $obj.Add($dsName, $_.Provisioned_GB)

   }

   New-Object psobject -Property $obj

} |

   Sort-Object -Property {($_ | Get-Member -MemberType NoteProperty).Count} -Descending |

   Export-Csv -Path .\report.csv -NoTypeInformation -UseCulture


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

VM_Us3r
Contributor
Contributor
Jump to solution

  This is great!  It is really close but a few things are not working.  The IP reports as “1” for all VMs.  Prior it was sorted by name but I was not able to make it sort alphabetically on this script. It appears to be starting with the VM that has the largest number of disks with the “-Descending” in the sort. It does start with the VM that has the most disks but appears to be quite random thereafter.  More importantly, it is only pulling the datastores for the first VM and it is not summing the disks per datastore either.  Below you will see the script results for the first few VMs. It appears that it will only add the Provisioned_GB for the first disk of the VM on each datastore instead of summing the disks total per datastore.   Thanks!

VMname

PowerState

OS

IP

ToolsStatus

NumCpu

MemGB

SAS_5

SSD_1

SSD_2

VMName_1

poweredOn

Microsoft Windows Server 2008 R2 (64-bit)

1

toolsOld

16

32

100

300

50

VMName_2

poweredOn

Microsoft Windows Server 2016 (64-bit)

1

toolsOk

2

4

100

VMName_3

poweredOn

Microsoft Windows Server 2016 (64-bit)

1

toolsOk

6

12

Screenshot of “VMName_1” Disks.

pastedImage_16.png

Script ERROR:

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

Exception calling "Add" with "2" argument(s): "Item has already been added. Key in dictionary: 'sata_2'  Key being added: 'sata_2'"

At line:111 char:4

+    $obj.Add($dsName, $_.Provisioned_GB)

+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : ArgumentException

Exception calling "Add" with "2" argument(s): "Item has already been added. Key in dictionary: 'sata_2'  Key being added: 'sata_2'"

At line:111 char:4

+    $obj.Add($dsName, $_.Provisioned_GB)

+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : ArgumentException

Exception calling "Add" with "2" argument(s): "Item has already been added. Key in dictionary: 'sas_4'  Key being added: 'sas_4'"

At line:111 char:4

+    $obj.Add($dsName, $_.Provisioned_GB)

+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : ArgumentException

 

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

Line 111:     $obj.Add($dsName, $_.Provisioned_GB)

LucD
Leadership
Leadership
Jump to solution

Is sata_2 the name of a datastore?
And is that a local datastore?


I'll have a look at the other issues you mention.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
VM_Us3r
Contributor
Contributor
Jump to solution

Yes, that is another datastore name but it is not adding a column for all other datastores that are not connected to the first VM. 

Datastores are NFS mounted storage, not local.  

Thanks!

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Oops, I lost track of this thread.
In any case, the below should provide a better solution.
All datastores are now present in each row, when a VM has no harddisk on a datastore, the value is left empty.

$dcName = 'YourDatacenter'

$vmMask = 'YourRegEx'


$dc = Get-View -ViewType Datacenter -Property Name -Filter @{Name = "^$($dcName)$"}


# Get the harddisk info for each VM

$hdInfo = Get-View -ViewType VirtualMachine -SearchRoot $dc.MoRef -Filter @{Name = "$($vmMask)"} -PipelineVariable vm |

   ForEach-Object -Process {

   $vm.Config.Hardware.Device | where {$_.DeviceInfo.Label -like "Hard disk *"} |

   ForEach-Object -Process {

   $hd = $_

   $vm.LayoutEx.Disk | where {$_.Key -eq $hd.Key} | % {

   $diskFiles = $_.Chain | % {$_.FileKey} | % {$_}

   }

   $diskAllocated = 0

   $vmdkName = $vm.LayoutEx.File | where {$_.Key -eq $diskFiles[0]} | select -ExpandProperty Name

   $vm.LayoutEx.File | where {$diskFiles -contains $_.Key} | % {

   $diskAllocated += $_.Size

   }

   $obj = New-Object PSObject -Property @{

   VMname = $vm.Name

   PowerState = $vm.Runtime.PowerState

   OS = $vm.Guest.GuestFullName

   IP = & {

   if ($vm.Guest.IpAddress) {

   $vm.Guest.IPAddress[0]

   }

   }

   ToolsStatus = $vm.Guest.ToolsStatus

   NumCpu = $vm.Config.Hardware.NumCPU

   MemGB = $vm.Config.Hardware.MemoryMB / 1KB

   Label = $hd.DeviceInfo.Label

   Path = $vmdkName

   Provisioned_GB = ("{0:N1}" -f ($hd.CapacityInKB / 1MB))

   }

   $obj

   }

}


# Get all datastores

$dsNames = $hdInfo | Group-Object -Property {$_.Path.Split(' ')[0].Trim('[]')} |

   ForEach-Object -Process {

   $_.Name

} | Sort-Object


# Summarise harddisk per datastore per VM

$hdInfo |

   Group-Object -Property VMname |

   ForEach-Object -Process {

   $vm = Get-View -ViewType VirtualMachine -Filter @{Name = "^$($_.Name)$"}

   $obj = [ordered]@{

   VMname = $vm.Name

   PowerState = $vm.Runtime.PowerState

   OS = $vm.Guest.GuestFullName

   IP = & {

   if ($vm.Guest.IpAddress) {

   $vm.Guest.IPAddress[0]

   }

   }

   ToolsStatus = $vm.Guest.ToolsStatus

   NumCpu = $vm.Config.Hardware.NumCPU

   MemGB = $vm.Config.Hardware.MemoryMB / 1KB

   }


   # Add a column for each datastore

   $dsNames | ForEach-Object -Process {

   $obj.Add($_, '')

   }


   # Get the total size per datastore

   $_.Group | Group-Object -Property {$_.Path.Split(' ')[0].Trim('[]')} |

   ForEach-Object -Process {

   $totalGB = ($_.Group | Measure-Object -Property Provisioned_GB -Sum).Sum

   $obj.Item($_.Name) = $totalGB

   }

   New-Object psobject -Property $obj

} |

   Sort-Object -Property VMName |

   Export-Csv -Path .\report.csv -NoTypeInformation -UseCulture


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
VM_Us3r
Contributor
Contributor
Jump to solution

Thanks so much for your help!  The datastores are all reporting properly now.  The IP is still reporting as "1" for all servers however.  I don't fully understand why the IP requires the "if" statement in both locations of the script.  I tried removing the if statements and I tried also using "$vm.ExtensionData.guest.ipAddress" as well but it is still not reporting the IP. 

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

The reason for the If is that on VMs where the VMware Tools are not installed, the IPAddress array will be $null, and that causes an error when you try to index the array.


Do you have the VMware Tools installed on these VMs?

If yes, is there more than one vNIC on these VMs?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
VM_Us3r
Contributor
Contributor
Jump to solution

Understood, that makes sense now, Thanks.  VMware tools is installed on nearly all of the VM guests except maybe a handful.  A few posts prior I listed the report spreadsheet example showing the "1" for IP column.  I do believe all VM guests only have a single vNIC.  In my original script at the top of the forum the IP was pulling fine via: "$VMInfo.IPAddress = $vm.Guest.IPAddress[0]"

So I am uncertain why the IP is not working now.  Thanks  

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

I think I found it, try replacing this line

$vm.Guest.IPAddress[0]

with this line (twice)

@($vm.Guest.IPAddress)[0]

If there is only 1 IP address, the property IPAddress is not an array, so we force it to be an array this way.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
VM_Us3r
Contributor
Contributor
Jump to solution

That was it!  Thank you so much!  The script is working great now. 

I do have one more question for you that I did not ask previously as I didn't think about it prior.  Can the datastore columns each be auto-summed with an additional bottom row called "Total"?  Something like the below example.  Thanks

VMname

PowerState

OS

IP

ToolsStatus

NumCpu

MemGB

SAS_5

SSD_1

SSD_2

VMName_1

poweredOn

Microsoft Windows Server 2008 R2 (64-bit)

1

toolsOld

16

32

100

300

50

VMName_2

poweredOn

Microsoft Windows Server 2016 (64-bit)

1

toolsOk

2

4

90

0

150

VMName_3

poweredOn

Microsoft Windows Server 2016 (64-bit)

1

toolsOk

6

12

0

50

40

Total190350240

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Try like this

$dcName = 'MyDC'

$vmMask = 'MyRegEx'


$dc = Get-View -ViewType Datacenter -Property Name -Filter @{Name = "^$($dcName)$"}


# Get the harddisk info for each VM

$hdInfo = Get-View -ViewType VirtualMachine -SearchRoot $dc.MoRef -Filter @{Name = "$($vmMask)"} -PipelineVariable vm |

   ForEach-Object -Process {

   $vm.Config.Hardware.Device | where {$_.DeviceInfo.Label -like "Hard disk *"} |

   ForEach-Object -Process {

   $hd = $_

   $vm.LayoutEx.Disk | where {$_.Key -eq $hd.Key} | % {

   $diskFiles = $_.Chain | % {$_.FileKey} | % {$_}

   }

   $diskAllocated = 0

   $vmdkName = $vm.LayoutEx.File | where {$_.Key -eq $diskFiles[0]} | select -ExpandProperty Name

   $vm.LayoutEx.File | where {$diskFiles -contains $_.Key} | % {

   $diskAllocated += $_.Size

   }

   $obj = New-Object PSObject -Property @{

   VMname = $vm.Name

   PowerState = $vm.Runtime.PowerState

   OS = $vm.Guest.GuestFullName

   IP = & {

   if ($vm.Guest.IpAddress) {

   @($vm.Guest.IPAddress)[0]

   }

   }

   ToolsStatus = $vm.Guest.ToolsStatus

   NumCpu = $vm.Config.Hardware.NumCPU

   MemGB = $vm.Config.Hardware.MemoryMB / 1KB

   Label = $hd.DeviceInfo.Label

   Path = $vmdkName

   Provisioned_GB = ("{0:N1}" -f ($hd.CapacityInKB / 1MB))

   }

   $obj

   }

}


# Get all datastores

$dsNames = $hdInfo | Group-Object -Property {$_.Path.Split(' ')[0].Trim('[]')} |

   ForEach-Object -Process {

   $_.Name

} | Sort-Object


# Summarise harddisk per datastore per VM

$report = @()

$hdInfo | Sort-Object -Property VMName |

   Group-Object -Property VMname |

   ForEach-Object -Process {

   $vm = Get-View -ViewType VirtualMachine -Filter @{Name = "^$($_.Name)$"}

   $obj = [ordered]@{

   VMname = $vm.Name

   PowerState = $vm.Runtime.PowerState

   OS = $vm.Guest.GuestFullName

   IP = & {

   if ($vm.Guest.IpAddress) {

   @($vm.Guest.IPAddress)[0]

   }

   }

   ToolsStatus = $vm.Guest.ToolsStatus

   NumCpu = $vm.Config.Hardware.NumCPU

   MemGB = $vm.Config.Hardware.MemoryMB / 1KB

   }


   # Add a column for each datastore

   $dsNames | ForEach-Object -Process {

   $obj.Add($_, '')

   }


   # Get the total size per datastore

   $_.Group | Group-Object -Property {$_.Path.Split(' ')[0].Trim('[]')} |

   ForEach-Object -Process {

   $totalGB = ($_.Group | Measure-Object -Property Provisioned_GB -Sum).Sum

   $obj.Item($_.Name) = $totalGB

   }

   $report += New-Object psobject -Property $obj

}

$obj = [ordered]@{

   VMname = 'Total'

   PowerState = ''

   OS = ''

   IP = ''

   ToolsStatus = ''

   NumCpu = ''

   MemGB = ''

}

$dsNames | ForEach-Object -Process {

   $dsName = $_

   $sum = $report | Measure-Object -Property $dsName -Sum | select -ExpandProperty Sum

   $obj.Add($dsName, $sum)

}

$report += (New-Object PSObject -Property $obj)

$report | Export-Csv -Path .\report.csv -NoTypeInformation -UseCulture


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

VM_Us3r
Contributor
Contributor
Jump to solution

This is fantastic.  Thank You very much!

Reply
0 Kudos
VM_Us3r
Contributor
Contributor
Jump to solution

  I am having issues with the RegEx pulling the VM templates as well as the VM guests skewing the .csv results.  I have been trying to add an If statement to the loop for skipping the template names but I have not been successful in this.  Any suggestions on this?  Thanks

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

$Temp = 'VMTemplate1' ,'VMTemplate2','VMTemplate3'

   While ($vm.Name.Movenext())

   if($vm.Name.Current.name -match $Temp){Continue}

   $vm.Name.current

#Also tried something like this:

   if ($vm.Name -eq $Temp) {continue}

   VMname = $vm.Name

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

To skip the templates, change the Filter.
Like this

Get-View -ViewType VirtualMachine -SearchRoot $dc.MoRef -Filter @{Name = "$($vmMask)"; 'Config.Template'='False' } -PipelineVariable vm |


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

VM_Us3r
Contributor
Contributor
Jump to solution

Perfect, Thank You! 

Reply
0 Kudos