VMware Cloud Community
markus81
Contributor
Contributor
Jump to solution

Get List of VMs, Datastores and VMDK / path per Cluster

Hi Folks,

as I´m new to this stuff, I´m wondering if anybody has already done some scripting work to gather a list of all virtual machines, its corresponding datastore(s) and the path to the VMDK-Files (or at least the name of it) - I know this part is already solved - found a couple of them 😉

But my problem is, I need this script drilled down per Cluster or Datacenter. As I said I´m completly new to this CLI-Stuff and don´t have a clue about how to solve this..

Cheers

Markus

54 Replies
LucD
Leadership
Leadership
Jump to solution

Strange, the CapacityGB property was introduced on the Harddisk object in PowerCLI 5.1.

It works for me.

Can you do

Get-VM -Name <whateverVM> | Get-Harddisk | Get-Member

to check if the CapacityGB property is there ?


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

0 Kudos
MD4SV
Contributor
Contributor
Jump to solution

Robert,

Great script though I would like to expand on it to include the snapshot size.  I've tried a number of ways to get the info - the only one that I can get to work still gives me a bit of garbage - the field name on the data line (I believe because I am asking for a select-object within a select-object).

Any suggestions for making this work within the code you have or do I need to plug it in through a secondary array?

0 Kudos
RvdNieuwendijk
Leadership
Leadership
Jump to solution

The following PowerCLI code will give you the sum of the sizes of all snapshots of a VM:

(Get-Snapshot -VM $VM | Measure-Object -Property SizeGB -Sum).Sum


If you want to get a list of all the individual snapshot sizes then you can use:

[string]::Join(' ',(Get-Snapshot -VM $VM | Sort-Object -Property Created | ForEach-Object {$_.SizeGB}))

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
0 Kudos
MD4SV
Contributor
Contributor
Jump to solution

Ahh, now I see where I went wrong with the approach I was trying (using the string entry) - thanks.  I ended up moving the get-snapshot info to a spot right after the last ForEach to insert it into a variable within the array.  This does the job nicely since it captures it at the execution level instead of the select-object level though I won't have the advantage of being able to see the total size of all snapshots so I modified mine entry and it provided the desired result.

BTW - why is a Join required to get the IP info? I thought it was used for manipuation of string contents.   I noticed that for the IP address issue as well - it seemed to me the Guest IP should be obtainable by a reference to Guest.IPAddress but for some reason it comes up NULL.  I'm still learning the powercli so I have a lot of things I'm missing that seem to be crucial to the process.

How are you able to post your code directly into the your blog entries here?  I can post the raw text from a text document or post it as an image - but cannot get it posted directly from PowerGUI script editor.

0 Kudos
RvdNieuwendijk
Leadership
Leadership
Jump to solution

If the property is an array then you can use the [string]::Join() method to convert the array to a single string. This is needed when you want to export the objects to a .csv file using the Export-CSV cmdlet because that does not work with array properties.

Guest.IPAddress is also an array. So you can use the [string]::Join() method here also.

To insert a script in a post with the PowerGUI colors, use the PowerGUI Edit - Copy As - Html option. While editing the post select HTML in the upper right corner to insert the code. To prevent Internet Explorer from not showing the last line of the script insert:

<!--[if IE]>

<![endif]-->


between the last:

</span></pre>

of the script.

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
0 Kudos
MD4SV
Contributor
Contributor
Jump to solution

The following script executes and provides what was desired - though there are a few tweeks I would like to impose -

1. One key tweek is how to get the output csv file to include the source path and file name of the executed script

2. In the situations where I am looking at a snapshot existing I would also like to get the base file size for the vmdks.  For some reason - the report kills the file size on the base vmdk's when discovering snapshots almost like it is pulling the information from the config file instead of raw off the disk.  JUST ADDING A FOOTNOTE:  I noted that when there is a snapshot on the system, the VMDK size is reported as zero - which of course is incorrect.  So, I'm asking Luke or anyone who can, to tell me what is wrong.  I suspect it is because the extensiondata.name is changed when a snapshot is ran, and the config file is no longer pointed to the Flat file - but my knowledge of the extensiondata is weaker that it should be and I don't really know all the SDK content that lets me drill down to the specifics without a lot more coding.  I have included a copy of the output and the latest version of my PS1.  Anyone who can point me to better guidance on the extensiondata and how to pull the fine details from it will be very much appreciated.

$VmInfo = ForEach ($Datacenter in (Get-Datacenter | Sort-Object -Property Name)) {   ForEach ($Cluster in ($Datacenter | Get-Cluster | Sort-Object -Property Name)) {     ForEach ($VM in ($Cluster | Get-VM | Sort-Object -Property Name)) {       ForEach ($HardDisk in ($VM | Get-HardDisk | Sort-Object -Property Name )) {         $SnapSize=Get-Snapshot -VM $VM | Measure-Object -Property SizeGB -Sum                  "" | Select-Object -Property @{N="VM";E={$VM.Name}},               @{N="Datacenter";E={$Datacenter.name}},               @{N="Folder";E={$VM.Folder}},               @{N="Host";E={$VM.VMHost}},               @{N="Cluster";E={$Cluster.Name}},                 @{N="# CPU";E={$VM.NumCpu}},               @{N="RAM";E={$VM.MemoryGB}},               @{N="IP";E={$VM.Guest.IPAddress}},               @{N="Hard Disk";E={$HardDisk.Name}},               @{N="HD Size";E={$HardDisk.CapacityGB}},               @{N="HD Type";E={$HardDisk.StorageFormat}},               @{N="Snap Size";E={$SnapSize.Sum}},               @{N="VMDK Size";E={($vm.extensiondata.layoutex.file|?{$_.name -contains $harddisk.filename.replace(".","-flat.")}).size/1GB}},               @{N="Datastore";E={$HardDisk.FileName.Split("]")[0].TrimStart("[")}},               @{N="VMDKpath";E={$HardDisk.FileName.Split("]")[1]}}        }     }   } }$VmInfo | Export-Csv -NoTypeInformation -UseCulture -Path $path 

Message was edited by: MD4SV

0 Kudos
SLGizmo
Contributor
Contributor
Jump to solution

Worked out of the box for me.  I needed to get a list of our VM's in order to setup a script and this helped me tremendously.  Thanks.

0 Kudos
oke_obire
Contributor
Contributor
Jump to solution

What do I need to do in order to add GET-WWPN names to this script?

#################################################

$VmInfo = ForEach ($Datacenter in (Get-Datacenter | Sort-Object -Property Name)) {
  ForEach ($Cluster in ($Datacenter | Get-Cluster | Sort-Object -Property Name)) {
    ForEach ($VM in ($Cluster | Get-VM | Sort-Object -Property Name)) {
      ForEach ($HardDisk in ($VM | Get-HardDisk | Sort-Object -Property Name)) {
        "" | Select-Object -Property @{N="VM";E={$VM.Name}},        @{N="Datacenter";E={$Datacenter.name}},        @{N="Cluster";E={$Cluster.Name}},        @{N="Hard Disk";E={$HardDisk.Name}},        @{N="Datastore";E={$HardDisk.FileName.Split("]")[0].TrimStart("[")}},        @{N="VMConfigFile";E={$VM.ExtensionData.Config.Files.VmPathName}},        @{N="VMDKpath";E={$HardDisk.FileName}},        @{N="VMDK Size";E={($vm.extensiondata.layoutex.file|?{$_.name -contains $harddisk.filename.replace(".","-flat.")}).size/1GB}},        @{N="Drive Size";E={$HardDisk.CapacityGB}}
      }
    }
  }
}
$VmInfo | Export-Csv -NoTypeInformation -UseCulture -Path "C:\scripts\xxxxx.csv"

0 Kudos
MD4SV
Contributor
Contributor
Jump to solution

I believe this will help you with your request though I cannot take credit for the script.

http://communities.vmware.com/thread/389982

One way that you should be able to get HostSystems' HBA WWN info is like:

## get all HostSystems' .NET View object
Get-View -ViewType HostSystem -Property name, Config.StorageDevice.HostBusAdapter | %{
   
$viewHost = $_
   
## for each HBA that is a HostFibreChannelHba, get some info
    $viewHost.Config.StorageDevice.HostBusAdapter | ?{$_ -is [VMware.Vim.HostFibreChannelHba]} | %{
       
New-Object -TypeName PSObject -Property @{
            VMHostName
= $viewHost.Name
           
## the HBA Port WWN in hexadecimal, with each octet split by ":"
            HBAPortWWN = (("{0:x}" -f $_.PortWorldWideName) -split "(\w{2})" | ?{$_ -ne ""}) -join ":"
           
## the HBA Node WWN in hexadecimal, with each octet split by ":"
            HBANodeWWN = (("{0:x}" -f $_.NodeWorldWideName) -split "(\w{2})" | ?{$_ -ne ""}) -join ":"
           
## the HBA status ("online", for example)
            HBAStatus = $_.Status
        }
## end new-object
    } ## end foreach-object
} | Select VMHostName, HBAPortWWN, HBANodeWWN, HBAStatus | Sort VMHostName

This gets each host, and for each fiber channel HBA in the host, lists the Node- and Port- WWN in hex.  The output would be something like:

VMHostName             HBAPortWWN                  HBANodeWWN                  HBAStatus
----------             ----------                  ----------                  ---------
myhost0.domain.com     10:00:00:00:00:00:00:e0     20:00:00:00:00:00:00:e0     online
myhost0.domain.com     10:00:00:00:00:00:00:5b     20:00:00:00:00:00:00:5b     online
myhost1.domain.com     10:00:00:00:00:00:00:77     20:00:00:00:00:00:00:77     online
myhost1.domain.com     10:00:00:00:00:00:00:58     20:00:00:00:00:00:00:58     online
...
shaka411
Contributor
Contributor
Jump to solution

Is there anyway to add to the script getting the LUN ID of the datstore that the VMDK is on?

0 Kudos
EKutsko
Contributor
Contributor
Jump to solution

I know this is really old, but does anyone know how to add the annotations into this?   We would like to have the owners of the VM's listed in the output and they are in the Annotations section.

0 Kudos
EKutsko
Contributor
Contributor
Jump to solution

I figured it out...here is what I did.

Connect-VIServer dabwinpvmvc01

$VmInfo = ForEach ($Datacenter in (Get-Datacenter | Sort-Object -Property Name)) {

  ForEach ($Cluster in ($Datacenter | Get-Cluster | Sort-Object -Property Name)) {

    ForEach ($VM in ($Cluster | Get-VM | Sort-Object -Property Name)) {

      ForEach ($HardDisk in ($VM | Get-HardDisk | Sort-Object -Property Name)) {

      ForEach ($Contact1 in ($VM | Get-Annotation -CustomAttribute "1st Contact" | Sort-Object -Property Name)) {

  ForEach ($Contact2 in ($VM | Get-Annotation -CustomAttribute "2nd Contact" | Sort-Object -Property Name)) {

        "" | Select-Object -Property @{N="VM";E={$VM.Name}},

          @{N="Datacenter";E={$Datacenter.name}},

          @{N="Cluster";E={$Cluster.Name}},

          @{N="Hard Disk";E={$HardDisk.Name}},

          @{N="Datastore";E={$HardDisk.FileName.Split("]")[0].TrimStart("[")}},

          @{N="VMDKpath";E={$HardDisk.FileName}},

          @{N="VMDK Size in GB";E={($vm.extensiondata.layoutex.file|?{$_.name -contains $harddisk.filename.replace(".","-flat.")}).size/1GB}},

   @{N="1st Contact";E={$Contact1.value}},

   @{N="2nd Contact";E={$Contact2.value}}

  } 

      }

   }

    }

  }

}

$VmInfo | Export-Csv -NoTypeInformation -UseCulture -Path "VmInfo.csv"

nscenter
Enthusiast
Enthusiast
Jump to solution

it worked like a charm for our needs, thanks for sharing.

0 Kudos
mypcgeek
Contributor
Contributor
Jump to solution

If you don't want to bother with Scripts just download RVTools. Should provide you with all of this information and more with this information.

0 Kudos
dubium
Contributor
Contributor
Jump to solution

Code becomes concise and elegant using the -pipelinevariable parameter, 

$report = Get-Datacenter -pv datacenter | Get-Cluster -pv cluster | Get-VM -pv vm | Get-HardDisk -pv harddisk | ForEach-Object {
     [psCustomObject] @{
        VM = $vm.name
        Datacenter = $datacenter.Name
        Cluster = $cluster.Name
        HardDisk = $harddisk.Name
        Datastore = $HardDisk.FileName.Split("]")[0].TrimStart("[")
        SizeGB = $harddisk.CapacityGB
        DiskFormat = $harddisk.StorageFormat
        DiskType = $harddisk.DiskType
        VMDKpath = $harddisk.FileName
     }
}
$report | Out-GridView


Cheers
Xavi

0 Kudos