Get-InventoryPlus – Inventory of all vSphere objects

Often I have to get a complete list of all the objects in a vSphere environment. From the PowerCLI cmdlets, the Get-Inventory cmdlets looks like the obvious candidate to tackle such a request. But the cmdlet seems to have some shortcomings. It definitely does not return all vSphere objects.

Hence I set out to write this Get-InventoryPlus function.

The function was demonstrated for the first time during the 24th VMUGBe in Mechelen.

The Issues

A quick demonstration of the problem. When you do a Get-Inventory, a list of vSphere objects is produced.

inventory-0

But some vSphere objects are definitely not in the list. To make this more visible, I grouped the returned objects by objecttype.

inventory-1

There are no network, nor storage related objects in the list returned by Get-Inventory !

With my Get-InventoryPlus function you do get a complete inventory. Notice how we now get network and storage related objects returned.

inventory-2

And there is in fact a 2nd issue !

Have a look at these two views of the entry named Folder2. Are we looking at one object or two objects ?

folder-10

To take the suspense away, an object of the type Folder can in fact appear twice in your inventory, and they are not the same object ! These are the so-called “Yellow” and “Blue” folders. They can have the same name, and appear to be in the same location. But in fact they are not in the same location. It’s an optical illusion, that is caused by the hidden folders ! In this case the hidden folders named ‘host’ and ‘vm’

folder-12

The view in old C# client makes this more visible.

folder-11

So I had to make sure that the function could make the distinction between the two !

The script

Annotations

Line 29: By default the function gets the inventory of the vSphere server that is in $Global:DefaultVIServer, but you can ask for the inventory of another vSphere server with this Server parameter. Notice the Type used for the Server parameter, it is the “portable” way of specifying a Type, as described in PowerCLI Best Practice: Correct Use of Strong Typing.

Line 33, 81: The Get-InventoryPlus function uses two inline, helper functions, Get-ViBlueFolderPath and Get-ObjectInfo.

Line 36: Since the helper function can be called with different types of vSphere objects, the $Itemp parameter is defined as an object of the base ManagedEntity type. All derived Types will be accepted.

Line 42,46,58,63,102,113: Depending on the type of object, the path upwards needs to use different properties. That is where the UpdateViewData method comes in handy, to just add the required property.

Line 73: The function traverse the path bottom up, as a consequence the elements in the $path array needs to be reversed, before the path string can be created.

Line 89: The script uses an array to hold the names of all hidden folders

Line 135-138: if an object has a “yellow” and a “blue” path that are the same, the BluePath property is retained, and the Path property is set to the NoValue string

Line 139-141: a Template object, by definition only has a BluePath

Line 147-152: All vSphere information can be retrieved starting from the ServiceInstance object

Line 155: The ContainerView is the simplest method to find all vSphere objects

Sample Usage

The usage is rather straight-forward.

Will produce something similar to this

inventoryplus-1

A call of the Get-InventoryPlus function will produce a number of objects. Each object has sufficient properties to uniquely distinguish it in the vSphere environment.

I tested the function in my lab against many possible configurations, but it is always possible I missed a “special” case. If you should encounter such an issue, please let me know.

 

Enjoy!

6 Comments

    djianto

    hi Luc,
    I was wondering how we could also list the IP address and Guest OS types with this function. I am just starting to learn powerCLI. Thank you and keep up the good work!

      LucD

      Hi,
      Sure that is possible.
      But note that this will only work for VMs that have the VMware Tools running in their Guest OS.
      Try with this small change to the function.

      function Get-InventoryPlus
      {
      < # .SYNOPSIS Retrieve the objects available on a vSphere Server. .DESCRIPTION This function will retrieve all objects available on a vSphere Server, including all storage and network objects. .NOTES Author: Luc Dekens .PARAMETER Server The vSphere Server (vCenter or ESXi) from which to retrieve the objects. The default is $Global:DefaultVIServer .PARAMETER NoValue Properties that are not set are returned as an empty string. The value on this parameter will be used instead of the empty string. .EXAMPLE PS> Get-InventoryPlus
      .EXAMPLE
      PS> Get-InventoryPlus -Server $vCenter
      .EXAMPLE
      PS> Get-InventoryPlus -NoValue 'na'
      #>

      [cmdletbinding()]
      param(
      [VMware.VimAutomation.ViCore.Types.V1.VIServer]$Server = $Global:DefaultVIServer,
      [String]$NoValue = ''
      )

      function Get-ViBlueFolderPath{
      [cmdletbinding()]
      param(
      [VMware.Vim.ManagedEntity]$Item
      )

      $hidden = 'Datacenters','vm'

      if($Item -is [VMware.Vim.VirtualMachine]){
      $Item.UpdateViewData('Parent')
      $parent = $Item.Parent
      }
      elseif($Item -is [VMware.Vim.VirtualApp]){
      $Item.UpdateViewData('ParentFolder')
      $parent = $Item.ParentFolder
      }

      if($parent){
      $path = @($Item.Name)
      while($parent){
      $object = Get-View -Id $parent -Property Name,Parent
      if($hidden -notcontains $object.Name){
      $path += $object.Name
      }
      if($object -is [VMware.Vim.VirtualApp]){
      $object.UpdateViewData('ParentFolder')
      if($object.ParentFolder){
      $parent = $object.ParentFolder
      }
      else{
      $object.UpdateViewData('ParentVapp')
      if($object.ParentVapp){
      $parent = $object.ParentVapp
      }
      }
      }
      else{
      $parent = $object.Parent
      }
      }
      [array]::Reverse($path)
      return "/$($path -join '/')"
      }
      else{
      return $NoValue
      }
      }

      function Get-ObjectInfo{
      [cmdletbinding()]
      param(
      [parameter(ValueFromPipeline)]
      [VMware.Vim.ManagedEntity]$Object
      )

      Begin{
      $hidden = 'Datacenters','vm','host','network','datastore','Resources'
      }

      Process{
      if($hidden -notcontains $Object.Name){
      $props = [ordered]@{
      Name = $Object.Name
      Type = $Object.GetType().Name
      BluePath = $NoValue
      GuestOS = ''
      IP = ''
      }
      $blueFolder = $false
      $isTemplate = $false
      if($object -is [VMware.Vim.Folder]){
      $object.UpdateViewData('ChildType')
      if($Object.ChildType -contains 'VirtualMachine'){
      $blueFolder = $true
      }
      }
      $path = @($Object.Name)
      $parent = $Object.Parent

      if($object -is [VMware.Vim.VirtualMachine] -or $object -is [VMware.Vim.VirtualApp]){
      $props['BluePath'] = Get-VIBlueFolderPath -Item $Object
      if($Object -is [VMware.Vim.VirtualMachine]){
      $Object.UpdateViewData('ResourcePool','Config.Template')
      if($Object.Config.Template){
      $parent = $Object.Parent
      $props['Type'] = 'Template'
      $isTemplate = $true
      }
      else{
      $Object.UpdateViewData('Guest.IpAddress','Guest.GuestFullName')
      $props['GuestOS'] = $Object.Guest.GuestFullName
      $props['IP'] = $Object.Guest.IpAddress
      $parent = $Object.ResourcePool
      }
      }
      }
      while($parent){
      $Object = Get-View -Id $Parent -Property Name,Parent
      $parent = $Object.Parent
      if($hidden -notcontains $Object.Name){
      $path += $Object.Name
      }
      }
      [array]::Reverse($path)
      $path = "/$($path -join '/')"
      $props.Add('Path',$path)

      if($blueFolder){
      $props['BluePath'] = $props['Path']
      $props['Path'] = $NoValue
      }
      if($isTemplate){
      $props['Path'] = $NoValue
      }
      New-Object PSObject -Property $props
      }
      }
      }

      $sView = @{
      Id = 'ServiceInstance'
      Server = $Server
      Property = 'Content.ViewManager','Content.RootFolder'
      }
      $si = Get-view @sView
      $viewMgr = Get-View -Id $si.Content.ViewManager

      $contView = $viewMgr.CreateContainerView($si.Content.RootFolder,$null,$true)
      $contViewObj = Get-View -Id $contView

      Get-View -Id $contViewObj.View -Property Name,Parent |
      where{$hidden -notcontains $_.Name} |
      Get-ObjectInfo
      }

        Jeffrey

        Hi, sorry to bother you, but would you mind explaining how to modify your script to add a column for the VM id? I was using your script along with the following where clause to filter only VMs.

        Get-InventoryPlus | where{$_.Type -eq ‘VirtualMachine’}

        However, since a VM name might not be unique, I’d like an ID column as well that is specific to each VM. Any help would be appreciated!

    Raphael

    You’re the genius !! Worked for me !!! Many thx

    Jeffrey

    Hi Luc,

    I had a quick question about modifying / using your function. My objective is to export a list of all VMs, their blue and yellow paths, and certain VM properties such as power state and host name.

    I am able to export the typical VM properties using “Get-VM | Select Name, PowerState, VMHost, VMHostId | Export-Csv -Path $csv -NoTypeInformation -UseCulture”. I am also able to export your function’s paths using “Get-InventoryPlus | where{$_.Type -eq ‘VirtualMachine’} | Export-Csv -Path C:\Temp\Task1.csv -NoTypeInformation -UseCulture”.

    However, I am unsure how to combine these. If it’s not too much trouble, it’d be awesome if you could explain how to export a single csv file with columns for Name, Host, PowerState, BluePath, and YellowPath.

    P.S.: I’m relatively new to PowerShell and PowerCLI, so apologies if this is question is trivial. I came across this function the other day and really appreciate it! I also noticed you are the lead author of the PowerCLI Reference book, which is awesome!

    hulk

    Please update on how to execute this code tried from cli ..when i execute it just goes back to the prompt dont get any output..

    ./inventoryplus.ps1 ,
    Get-InventoryPlus

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*

Buy the Book