PowerCli to get all VMs on certain Datastores?

From time to time, I get tasked with generating a report of production VMs with specs. This normally wouldn’t be an issue, but we have changed our server naming standard a few times, so we have machines with all sorts of names. The one thing in out environment that hasn’t changed is the datastore naming. We have our datastores split up between non-production and production, and each department has their own. So to get the production VMs, I can do a filter on the name of the datastores to get only the production one.

	Get-datastore | Where {$_.name -like '*PROD*' -or $_.name -like '*REPL*'} | Get-VM
Output of script to get VMs on certain datastores
Output of script to get VMs on certain datastores

The script results are good, but I don’t need to know if the servers are powered on for the report that I’ve been tasked with. There are also several other options that I need to collect on the VMs before I can call my report finished. I need to get the folder that the VM is in along with the VM cluster, and network adapter

	Get-datastore | Where {$_.name -like '*PROD*' -or $_.name -like '*REPL*'} | Get-VM | Select Name, @{N="vCPU";E={($_).NumCpu}}, @{N="Memory (GB)";E={($_).MemoryGB}}, @{N="Cluster";E={Get-Cluster -VM $_}}, @{N="Folder";E={$_.folder}}, @{N="Network";E={$_.Networkadapters.NetworkName}} | Format-Table

Now this is more like what I was tasked with collecting from vSphere. Now that I have the neccessary information, I need to export it to an CSV.

$report = @()
$VMs = Get-datastore | Where {$_.name -like '*PROD*' -or $_.name -like '*REPL*'} | Get-VM 
Foreach ($VM in $VMs){
	$line = $VM | Select Name, @{N="vCPU";E={($_).NumCpu}}, @{N="Memory (GB)";E={($_).MemoryGB}}, @{N="Cluster";E={Get-Cluster -VM $_}}, @{N="Folder";E={$_.folder}}, @{N="Network";E={$_.Networkadapters.NetworkName}}
	$report += $line
	}
	$report | Export-csv C:\scripts\logs\ProductionVMs.csv -NoTypeInformation -UseCulture
PowerCLI to get VMs based on Datastore report
Example report from the results of the Script to get VMs based on datastores

There are many different specs that can be collected with this script.  I also have a version that states whether or not the systems has RDMs attached. This is very helpful when needing to move the VM between cluster, as I would need to have the storage team to attach the RDMs to the new destination cluster.

$report = @()

$VMs = (Get-Datastore | Where {$_.Name -like '*REPL*' -or $_.Name -like '*PROD*'} | Get-VM).Name | sort

Foreach ($VM in $VMs){
    $line = Get-VM $VM | Select Name, @{N="vCPU";E={($_).NumCpu}}, @{N="Memory (GB)";E={($_).MemoryGB}}, @{N="Cluster";E={Get-Cluster -VM $_}}, @{N="Folder";E={$_.folder}}, @{N="Network";E={(Get-NetworkAdapter -VM $_).NetworkName}}, @{Expression={if (($_ | Get-HardDisk | Where {$_.DiskType -eq "RawPhysical"}) -eq $Null) {"No"} Else {"Yes"}}; Label="RDMs" }
    $report += $line
}
$report | Export-Csv C:\scripts\logs\ProductionVMs.csv -NoTypeInformation -UseCulture 

– Stuart

Find this script on Github

8 thoughts on “PowerCli to get all VMs on certain Datastores?”

    1. Joy,
      I have modified the script to capture the data that i believe that you are looking for.

      $report = @()
      $datastores = Get-datastore | Where {$_.name -like '*PROD*' -or $_.name -like '*REPL*'}
          Foreach ($Datastore in $datastores){
              $VMs = $datastore | Get-VM
                  Foreach ($VM in $VMs){
                      $Line = "" | Select Name, vCPU, 'Memory(GB)', TotalHDD, Cluster, Folder, Datastore, 'Datastore Capacity'
                      $line.Name                 = $VM.name
                      $line.vCPU                 = $vm.NumCpu
                      $line.'Memory(GB)'         = $vm.MemoryGB
                      $line.TotalHDD             = ($VM | Get-HardDisk | Measure capacityGB -sum).sum
                      $line.Cluster              = Get-Cluster -VM $VM.name
                      $line.Folder               = $VM.Folder
                      $line.Datastore            = $datastore.name
                      $line.'Datastore Capacity' = $Datastore.CapacityGB
                      $report                   += $line
                  }
          }
      $report | ft -AutoSize
      

      I hope this helps.

      -Stuart

  1. Awesome script! I was wondering if this can be modified to list the datastore name and tell me how many VMs are on that datastore and the free space left? I am trying to create a spreadsheet that can easily tell someone which datastore to use when building a VM. We like to put 15 VMs per datastore and keep the free space above 500G out of the 2T provisioned for each datastore. We have a lot of FC datastores and it can take some time to click on each one in vCenter to see how many VMs are on it and what the free space is. Thanks!

    1. Patrick,
      I believe that this is what you are looking for.

      $DatastoreReport = @()
      $Datastores = Get-datastore
      Foreach ($Datastore in $datastores){
          $DSLine             = "" | Select Name, NumofVMs, FreeSpaceGB
          $DSView             = $Datastore | Get-View
          $DSLine.Name        =  $DSView.Name
          $DSLine.NumofVMs    = ($DSView.vm).count
          $DSLine.FreeSpaceGB = [math]::Round(($DSView.Info.FreeSpace / 1024GB),2)
          $DatastoreReport   += $DSLine
      }
      $date = get-date -Format MM"-"dd"-"yyyy
      $DatastoreReport | Sort -Property FreeSpaceGB -Descending | Export-CSV C:\scripts\Logs\DataStore_Report_$date.csv -NoTypeInformation -UseCulture
      

      -Stuart

      1. Stuart,
        I was not expecting a reply so soon. You are a gentleman and a scholar!!! This is exactly what I have been needing for a very long time!!!
        I modified the script a tad and copied a line from another script I found online to look for a specific name. We have other datastores in vCenter but I only care about the FC ones for this spreadsheet. Not sure if I need the -or part but it works.

        Thanks again!!!

        $DatastoreReport = @()
        $Datastores = Get-datastore | Where {$_.name -like ‘*D1C01*’ -or $_.name -like ‘*REPL*’}
        Foreach ($Datastore in $datastores){
            $DSLine             = "" | Select Name, NumofVMs, FreeSpaceGB
            $DSView             = $Datastore | Get-View
            $DSLine.Name        =  $DSView.Name
            $DSLine.NumofVMs    = ($DSView.vm).count
            $DSLine.FreeSpaceGB = [math]::Round(($DSView.Info.FreeSpace / 1024GB),2)
            $DatastoreReport   += $DSLine
        }
        $date = get-date -Format MM"-"dd"-"yyyy
        $DatastoreReport | Sort -Property FreeSpaceGB -Descending | Export-CSV C:\Scripts\Logs\DataStore_Report_$date.csv -NoTypeInformation -UseCulture
        

        -Patrick

        1. Patrick,
          Thanks for the kind words. The ‘-or’ part of the script does additional sorting based on the names of the datastores. Its not necessary if your datastores don’t include *REPL* in the name.

          -Stuart

    1. Bill,
      This should be what you are looking for. Basically you would need to add the following to the $line row to also gather the Datastore name that the VM is on.
      @{N=”Datastore”;E={($_ | Get-datastore).Name}}

      Below is the script that has the line already inserted for reference.

      $report = @()
      $VMs = Get-datastore | Where {$_.name -like '*PROD*' -or $_.name -like '*REPL*'} | Get-VM 
      Foreach ($VM in $VMs){
      	$line = $VM | Select Name, @{N="vCPU";E={($_).NumCpu}}, @{N="Memory (GB)";E={($_).MemoryGB}}, @{N="Datastore";E={($_ | Get-datastore).Name}}, @{N="Cluster";E={Get-Cluster -VM $_}}, @{N="Folder";E={$_.folder}}, @{N="Network";E={$_.Networkadapters.NetworkName}}
      	$report += $line
      	}
      	$report | Export-csv C:\scripts\logs\ProductionVMs.csv -NoTypeInformation -UseCulture
      

      -Stuart

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.