9 Replies Latest reply on Jan 15, 2019 11:47 PM by LucD

    VM Provisioned space per each connected Datastore

    VM_Us3r Lurker

        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:

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

        • 1. Re: VM Provisioned space per each connected Datastore
          LucD Guru
          User ModeratorsvExpertCommunity Warriors

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

          • 2. Re: VM Provisioned space per each connected Datastore
            VM_Us3r Lurker
             
            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 
             
             
            • 3. Re: VM Provisioned space per each connected Datastore
              LucD Guru
              vExpertUser ModeratorsCommunity Warriors

              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.

              • 4. Re: VM Provisioned space per each connected Datastore
                VM_Us3r Lurker

                 

                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

                 

                 

                 

                 

                 

                 

                 

                 

                 

                 

                • 5. Re: VM Provisioned space per each connected Datastore
                  LucD Guru
                  Community WarriorsvExpertUser Moderators

                  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

                  • 6. Re: VM Provisioned space per each connected Datastore
                    VM_Us3r Lurker

                     

                      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.

                    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)

                     

                    • 7. Re: VM Provisioned space per each connected Datastore
                      LucD Guru
                      User ModeratorsvExpertCommunity Warriors

                      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.

                      • 8. Re: VM Provisioned space per each connected Datastore
                        VM_Us3r Lurker

                        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!

                        • 9. Re: VM Provisioned space per each connected Datastore
                          LucD Guru
                          User ModeratorsvExpertCommunity Warriors

                          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