Getting the DNS Servers associated with an ESXi Host | PowerCLI | One-Liner

We recently had to check for discrepancies in configurations of ESXi hosts in a datacenter. While they should be identical, we have had issues with DNS working on some hosts while some don’t. So I developed a script that outputs the DNS servers configured on every host of the entire vCenter to a CSV file. (Note: This outputs the IPs of the DNS servers)

Its a one-liner so its not difficult to execute, check it out :

$vcenter = "vcenter_name"

Connect-VIServer $vcenter 

Get-VMHost | Select Name, @{N='DNS Server(s)';E={$_.Extensiondata.Config.Network.DnsConfig.Address -join ' , '}} | Export-Csv 'esx_dns_info.csv' 

Code breakdown:

Basically what we are doing is getting the data that is hidden inside the data that is pulled by the Get-VMHost module -in this case it’s under extension data/config/Network/DNSConfig/Address – which fetches the IP’s of these servers.

Why I used the -join ‘,’ is that a single ESXi host may have multiple DNS servers configured for redundancy, but this will not be outputted properly with CSV. So what I’m doing is joining the list of IPs to a single line separated by a comma.

Then finally pipe all that data in to the Export-CSV module that will export it to a CSV file I’ve named “esx_dns_info.csv”

And that is it – simple as that. Hope that was a easy and clear guide to getting the DNS servers associated with an ESX host.

If you liked it, please share the news! Happy Scripting!

Changing the vCenter Alarm reporting frequency | PowerCLI

Recently we noticed that in vCenters while we receive SNMP or Email (SMTP) red alerts, we did not receive the green alerts that changed immediately.

For example if an ESX host had a memory utilization of 95%, it would trigger a red state alarm and would send out an email or SNMP trap notifying the admins “HELP SOMETHING IS WRONG“, but should that alarm flap immediately and return to green (below that 95% or 90% whichever is set) – the vCenter doesn’t send out an email or SNMP saying “okay false alarm calm down“. This would waste a vigilant system administrator’s time checking an alarm that was a fluke.

According to this VMware KB article the alarm actions like Email alerts/SNMP traps are not triggered for state changes within 5 minutes from initial alarm trigger. So it’s official. And there is no GUI way to change this, it’s all PowerCLI to the rescue.

We didn’t notice this until we built an application that shows real time vCenter alarms which was sensitive to flapping state changes. So we had to take action to set the alarming frequency from 5 minutes to 0 to get immediate alarms. Fortunately you can do this for individual alarms, which means its not a global setting that changes the alarm frequency of all alarms in the vCenter.

Enough chit chat – down to scripting! I will do a breakdown of the full script to explain what I’m doing and have the full script down below, if you’re lazy you can just copy the script and run it

#Credentials 
$user = "vcenter_username"
$pwd = "vcenter_password"

#the vcenter name goes here
$server = "vcenter_1"
	
Connect-VIServer $server -User $user -Password $pwd

#variable with the name of the alarm that you want to change the alarming frequency of
$alarm_check = "vCenter host alarm"
write-host "checking alarm $alarm_check"
	
$alarm_id = (Get-AlarmDefinition | where name -eq $alarm_check ).id
$alarm_view = Get-View -id $alarm_id

echo $alarm_view.info.setting

#create a spec variable that holds a copy of data to update
$spec_to_update = $alarm_view.info
$spec_to_update.Setting.ReportingFrequency = 0

Write-Host "Reconfiguring $alarm_check"
$alarm_view.ReconfigureAlarm($spec_to_update)

Write-Host "New Reporting frequency of $alarm_check"

$new_alarm_id = (Get-AlarmDefinition | where name -eq $alarm_check ).id
$new_alarm_view = Get-View -id $new_alarm_id

echo $new_alarm_view.info.setting

For those of you who want to know what just happened with this script here is a breakdown of the script:
First up we need to connect to the vCenter via Connect-VIServer

#Credentials 
$user = "vcenter_username"
$pwd = "vcenter_password"

#the vcenter name goes here
$server = "vcenter_1"
	
Connect-VIServer $server -User $user -Password $pwd

Next up we create a variable that has the name of the alarm which you want to change the reporting frequency of, we’re calling that $alarm_check. (I’m taking the vcenter host alarm example I took above for this too and assuming the alarm name is “vCenter host alarm”)

$alarm_check = "vCenter host alarm"
write-host "checking alarm $alarm_check"

Then we take the ID of the alarm (vCenter has a separate ID for every alarm to identify every alarm uniquely), then we get-view that alarm ID which shows all the settings of that alarm. We then echo the settings to see whether the reporting frequency is actually 5 minutes

$alarm_id = (Get-AlarmDefinition | where name -eq $alarm_check ).id
$alarm_view = Get-View -id $alarm_id

echo $alarm_view.info.setting

Here’s where things might get a liiiiiittle bit confusing. We create a copy of that alarm-view data, and then create a proxy copy of data that need to be there with the new alarm reporting frequency of 0. Basically we have created a variable with the setting that we want to be there..

#create a spec variable that holds a copy of data to update
$spec_to_update = $alarm_view.info
$spec_to_update.Setting.ReportingFrequency = 0

Then we take the original alarm-view and reconfigure the original alarm with the proxy copy of data that we created with the data that we need to be there

Write-Host "Reconfiguring $alarm_check"
$alarm_view.ReconfigureAlarm($spec_to_update)

Like the good Sys Admins that we are – then we double check whether the change did take place

$new_alarm_id = (Get-AlarmDefinition | where name -eq $alarm_check ).id
$new_alarm_view = Get-View -id $new_alarm_id

echo $new_alarm_view.info.setting
The output should look a little something like this

And that’s it! The vCenter should send alarm state changes immediately now!

The main issue is there is no GUI way of doing this, you have to rely on PowerCLI to do that for you. But if you do find a better, lazier way to do this please do let me know – I mean that’s why we script right? because we laaaaazy 😉

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