VMware Cloud Community
Ramkrish
Contributor
Contributor
Jump to solution

get-vmhost doesn't reflect the correct Host Count on few scenarios

Hello Community Members,

When I try to use get-vmhost cmdlet against a cluster which has one or no hosts in it, I don't get the correct host count. Below are few lines to get this information.

foreach ($objDataCenter in $objColDataCenters)
{
  $objColClusters = Get-Cluster -Location $objDataCenter

  foreach ($objcluster in $objColClusters)
  {
   $Details = $Null
   $objClusterBaseRP = $objHosts = $objDataStores = $objVMs = $Null
   $intNUmDatastores = $intNumHostCPUs = $intTotCPUMhz = $intTotUsageCPUMhz = 0
   $intTotMemMB = $intTotUsageMemMB = 0
   $CPUStat = $CPUStatMax = $MemoryStat = $MemoryStatMax = 0
   $intTotMemGB = $intUsageGB = $intMemResGB = $intMemLmtGB = 0
   $inttOTDiskCapacityMB = $intTotDiskFreeMB = $intTotDSCapacityGB = $intTotDSFreeGB = 0
   $intTotVMMemGB = $intTotVMCPUMhz = $intNumVMCpus = $intTotVMMemMB = 0
   $intTotVMProvisionedSpaceGB = $intTotVMUsedSpaceGB = 0

 

   $objHosts = get-vmHost -LOcation $objcluster

    $objHosts.Count

  }

}

above code produce Blank for clusters which has single Host, for all other clusters which has  2 or more hosts results are correct. I know there is no point of having a cluster with single or no nodes but the result doesn't reflect correct stats.

In the same way below lines also produce incorrect information for the cluster which has no HOSTS or has a single HOST which is in maintanence mode and has no VMs in it

$objVMs = get-VM -Location $objCluster

   $objVMs | %{
    $intNumVMCpus += $_.NumCpu
    $intTotVMMemMB += $_.MemoryMB
    $intTotVMProvisionedSpaceGB += $_.ProvisionedSpaceGB
    $intTotVMUsedSpaceGB += $_.usedSpaceGB
  
    }

When I print the values in any of the above variables, it should report 0  instead I get to see some figures. Please note I explicitly assign $null values to all objects and assign 0 to all other variables at the beginning of loop for clusters.

Any help in resolving this is greatly appreciated - Thanks

Regards, Ramki

0 Kudos
1 Solution

Accepted Solutions
mattboren
Expert
Expert
Jump to solution

Hello, Ramkrish-

Welcome to the communities.

For the first part, the host count for a cluster with zero (0) or one (1) host -- there are a couple of things happening there.

When the Get-VMHost call returns only one host, and you then try to access the .Count property of $objHosts, you are trying to access that property on a VMHost object, not an array of length 1 with one VMHost in it.  And, since the VMHost object has no property ".Count" you get a "blank" or null return.

And, when Get-VMHost returns no hosts, and you try to access .Count on $objHosts, you are effectively typing "$null.Count", since $objHosts -eq $null at that point.

A couple of ways to handle those cases would be to either use the Measure-Object cmdlet or to explicitly make an array, even if zero or one VMHosts are returned.  Like:

## using Measure-Object
$objHosts = Get-VMHost -Location $objcluster
(
$objHosts | Measure-Object).Count    ## correctly returns 0 or 1 (or greater)
...
## or
#
# forcing an array, even if 0 or 1 items returned
$objHosts = @(Get-VMHost -Location $objcluster)
$objHosts.Count        ## correctly returns 0 or 1 (or greater)
...

As for the behavior that you are seeing with the Foreach-Object statement with $objVMs, I suspect that the behavior of the Foreach-Object statement when you pipe an empyt/null value to it is at play here.  That is, while you might expect "$arrEmptyArray | %{'hello'}" to produce nothing, it actually does go through one interation of the loop (really -- try it).  So, to avoid that, you could remove the unnecessary part that stores the output of Get-VM in the "$objVMs" variable, and just combine the lines to pipe the output of Get-VM directly to the Foreach-Object statement, like:

Get-VM -Location $objCluster | %{
   
$intNumVMCpus += $_.NumCpu
   
$intTotVMMemMB += $_.MemoryMB
   
$intTotVMProvisionedSpaceGB += $_.ProvisionedSpaceGB
   
$intTotVMUsedSpaceGB += $_.usedSpaceGB
}

An aside:  while we're updating that code a bit, another way that you could get those totals is to again use the Measure-Object cmdlet, this time with the -Sum parameter, like:

Get-VM -Location $objCluster | Measure-Object -Sum -Property NumCpu, MemoryMB, ProvisionedSpaceGB, usedSpaceGB

Much more compact, and it just lets PowerShell do the work.  Granted, you then handle the return from Measure-Object, but depending on the situation, it is quite handy.

How about that?

View solution in original post

0 Kudos
2 Replies
mattboren
Expert
Expert
Jump to solution

Hello, Ramkrish-

Welcome to the communities.

For the first part, the host count for a cluster with zero (0) or one (1) host -- there are a couple of things happening there.

When the Get-VMHost call returns only one host, and you then try to access the .Count property of $objHosts, you are trying to access that property on a VMHost object, not an array of length 1 with one VMHost in it.  And, since the VMHost object has no property ".Count" you get a "blank" or null return.

And, when Get-VMHost returns no hosts, and you try to access .Count on $objHosts, you are effectively typing "$null.Count", since $objHosts -eq $null at that point.

A couple of ways to handle those cases would be to either use the Measure-Object cmdlet or to explicitly make an array, even if zero or one VMHosts are returned.  Like:

## using Measure-Object
$objHosts = Get-VMHost -Location $objcluster
(
$objHosts | Measure-Object).Count    ## correctly returns 0 or 1 (or greater)
...
## or
#
# forcing an array, even if 0 or 1 items returned
$objHosts = @(Get-VMHost -Location $objcluster)
$objHosts.Count        ## correctly returns 0 or 1 (or greater)
...

As for the behavior that you are seeing with the Foreach-Object statement with $objVMs, I suspect that the behavior of the Foreach-Object statement when you pipe an empyt/null value to it is at play here.  That is, while you might expect "$arrEmptyArray | %{'hello'}" to produce nothing, it actually does go through one interation of the loop (really -- try it).  So, to avoid that, you could remove the unnecessary part that stores the output of Get-VM in the "$objVMs" variable, and just combine the lines to pipe the output of Get-VM directly to the Foreach-Object statement, like:

Get-VM -Location $objCluster | %{
   
$intNumVMCpus += $_.NumCpu
   
$intTotVMMemMB += $_.MemoryMB
   
$intTotVMProvisionedSpaceGB += $_.ProvisionedSpaceGB
   
$intTotVMUsedSpaceGB += $_.usedSpaceGB
}

An aside:  while we're updating that code a bit, another way that you could get those totals is to again use the Measure-Object cmdlet, this time with the -Sum parameter, like:

Get-VM -Location $objCluster | Measure-Object -Sum -Property NumCpu, MemoryMB, ProvisionedSpaceGB, usedSpaceGB

Much more compact, and it just lets PowerShell do the work.  Granted, you then handle the return from Measure-Object, but depending on the situation, it is quite handy.

How about that?

0 Kudos
Ramkrish
Contributor
Contributor
Jump to solution

Hello mattboren,

Thanks for your such a detailed response. it works perfectly now. Your explanation helped me understand what goes inside when i try to execute those statements. I got quite few useful information to deal with these sorts of situation.

Thank you very much,

ramki

0 Kudos