get-list-of-vms-in-esx-host

Get the list of Virtual Machines on a ESXi Host with Get-VMHost | PowerCLI

Recently I needed to create a script to get a list of all virtual machines in a specific ESXi host. Surprisingly I had to search high and low on the internet to figure this out.

This is perplexing I mean its very straightforward to get the VMs in a datastore with

Get-VM -Datastore <datastore_name>

you would think getting all the virtual machines on a ESXi host would be more important than that! Work on this VMware – give us a Get-VM -VMHost!

But I digress – this is how you get the list of virtual machines on a ESXi host… I mean I was ranting up there but it’s really not that difficult, just that there’s no proper documentation on it

Get-VMHost -Name <Host_name> | Get-VM

And that’s all there is to it. But it’s not that intuitive, you wouldn’t think piping through the host name to Get-VM would do anything right? Anyways this one-liner saved my bacon, and I hope it would be useful to you as well!

Till the next time – happy scripting!

Expanding an existing disk on a Virtual Machine with PowerCLI | Get-HardDisk & Set-HardDisk cmdlets

We recently had a sudden requirement to increase the C: drives of a set of VMs to assist with an Operating system patching process – its not practical to to manually do that one by one – so PowerCLI to the rescue. So if you get a scenario where you need to expand an existing disk of a virtual machine by a specified amount of GB (especially a bulk of VMs), the following script will make life much easier.

Get the current size of the required disk

Use the code below to get the size (in GB) of the harddisk in question (here I’m getting the size of “hard disk 1”)

$vm_info_dsk = (Get-HardDisk -VM $vm_name | Where-Object {$_.Name -eq "Hard Disk 1"}).CapacityGB

You can make this a more expandable/usable code by making the Hard disk number a variable as well. With this you can change the name of the Hard disk easily without having to replace all the instances where the name was used.

$hard_disk_number = "Hard Disk 1"

$vm_info_dsk = (Get-HardDisk -VM $vm_name | Where-Object {$_.Name -eq $hard_disk_number}).CapacityGB

Setting the hard disk to the new size

You can change the size of the disk using the Set-HardDisk command. Here I’m going to assume the size of the disk needs to be increased by 10GB

$space_to_increase = 10
$new_capacity = $vm_info_dsk + $space_to_increase

Get-HardDisk -VM $vm_name | Where-Object {$_.Name -eq "Hard Disk 1"} | Set-HardDisk -capacityGB $new_capacity -confirm:$false

How it all comes together (the complete script)

Lets see how to put this all in to a robust expandable script.

The script will read a list of vms from the vm_list.txt text file (vms should be separated by a new line) which would be useful for bulk list of VMs – for more clarity on Get-Content read that post here. To change any parameter (different disk size, different harddisk) simply change the relevant variable.

#Read list from a text file vm_list.txt - separated by a new line
$vm_list = Get-Content "vm_list.txt"

$vcenter = "vCenter1"
$space_to_increase = 20
$hard_disk_number = "Hard Disk 1"

Connect-VIServer $vcenter 


foreach($vm_name in $vm_list){
	write-host "Fetching information of $vm_name"
	$vm = Get-VM $vm_name

	$vm_info_dsk = (Get-HardDisk -VM $vm_name | Where-Object {$_.Name -eq $hard_disk_number}).CapacityGB

	Write-Host "$vm $hard_disk_number is $vm_info_dsk"

	$new_capacity = $vm_info_dsk + $space_to_increase

	Write-Host "new hard disk capacity $new_capacity"

	Get-HardDisk -VM $vm_name | Where-Object {$_.Name -eq $hard_disk_number} | Set-HardDisk -capacityGB $new_capacity -confirm:$false

#Check if it is successfully set and display the new size
	$vm_info_dsk = (Get-HardDisk -VM $vm_name | Where-Object {$_.Name -eq $hard_disk_number}).CapacityGB

	Write-Host "$vm new hard disk 1 is $vm_info_dsk"
}
	
Disconnect-VIServer -Confirm:$false

Listing all networks visible to an ESX host via PowerCLI

I had worked on an automation project to ease up virtual machine provisioning – for that it was necessary to create a script that would list out all the networks that is visible to an ESXi host (so that the correct one could be added to the new virtual machine). Turns this was quite easy with the Get-VirtualPortGroup cmdlet – here’s how to do it (its so simple that its going to be a smaller than normal post)

$host_info = Get-VMHost -VM $vmname
	
Get-VirtualPortGroup -VMHost $host_info.name

And that’s it! no magic to it at all!

Checking for and Setting Maintenance mode on an ESXi Host via PowerCLI

Say you have to do a configuration change on an ESXi host – you know you can script that stuff out and put your feet up while it does it’s thang… Buuut you’re unsure about whether the host is in maintenance mode… what if its not on maintenance mode? What if it screws it up! Well in this post I’ll cover how you can check for as well as set maintenance mode effectively via PowerCLI.

Checking whether ESXi host is in Maintenance mode

The Get-VMHost cmdlet get the connection state of the ESXi host as well whether its connected, disconnected or in maintenance mode.

$host = "esx_host1" 
#Use the fqdn of the host

if($host.ConnectionState -eq "Maintenance"){
	write-host "The host is in maintenance mode"
	#Your configuration change code can go here
}

Setting ESXi host to Maintenance mode

$host = "esx_host1" 
#Use the fqdn of the host

#Set host to maintenance mode
Get-VMHost -Name $hosts | set-vmhost -State Maintenance

do{
	$host_info = Get-VMHost $hosts
	$count = $count + 1
	#check if 5 minutes had passed, if so exit 
	if ($count -gt 15){
		$failed = 1
		$msg = "Waiting for maintenance mode timed out. Please check the status from the vCenter"
		break
	}
		
	else{
		sleep 20
	}		
	
}until($host_info.ConnectionState -eq "Maintenance" )

This script issues the command to set the host to maintenance mode. Then checks every 20 seconds for 5 minutes whether the host is in maintenance mode. If not it will get a timeout error (say if one stubborn Virtual machine refuses to leave the host).

Error handling in Powershell : Try / Catch blocks in Powershell

Recently I had a project to develop a web portal that would trigger a powerCLI script. The problem was that if anything except the required JSON output popped up, especially any errors, the whole thing would crash. The only work around was to error handle the sh#t out of the code!!!

The best and easiest way to error handle / catch exceptions is to use try / catch blocks – if you’re familiar with Java (or any kind of) programming, powershell try catch blocks work exactly the same way. If you’re not – don’t worry I got your back.

What is a try catch block?

Try catch block is a way to structure your code to handle errors and catch any exceptions that your code might throw. There is also a “Finally” block that is also a part of the whole thing.

Try block – This is where you place the code which you need to check for exceptions
Catch block – This is where you specify what you need the code to do IF an exception is caught
Finally block – This is where you specify the code that you need to run regardless of whether an exception was caught or not

try{

	//The code that needs checking for exceptions
}

catch{

	//What should happen if an exception is caught
}

Finally{

	//What should run regardless of what happens above
}

Code Example

try{

	Connect-VIServer $vcenter -Credential $credentials -ErrorAction Stop
	Write-host "This will not run if an exception is caught"
}

catch{

	Write-host "Oops something is wrong with the credentials"
}

Finally{

	Write-host "This runs regardless of what happens above"
}

The above code is a PowerCLI script which will try to connect to a vCenter with the given credentials and if an exception is caught it will display the text in the catch block.

IMPORTANT: DONT FORGET THE -ERRORACTION The -ErrorAction stop is extremely important for the code to function as expected. This is will stop powershell from executing the next lines and divert the code to the catch block. If ErrorAction was not there it will continue executing everything regardless of an exception.