This code will aid in the automation of deleting Host Affinity rules via PowerCLI.

Currently the Get-DRSRule and Remove-DRSRule command does not allow the removal of VM-Host Affinity rules.
This code block will get a “VMHost Affinity” rule based on a string filter then delete it along with the VM group + Host group attached to it.
If you don’t want to delete the VM and host group, just remove the sub group specs below.

Add-PSSnapin VMware.VimAutomation.Core
Connect-VIServer “” -User “XX” -password “XX”

$Mycluster = get-cluster “MyCluster”
$therules = get-drsrule -cluster $mycluster -type vmhostaffinity | where {$ -match “RuleNameHere”}

foreach($rule in $therules){
$spec = New-Object VMware.Vim.ClusterConfigSpecEx
$spec.rulesSpec = New-Object VMware.Vim.ClusterRuleSpec[](1)
$spec.rulesSpec[0] = New-Object VMware.Vim.ClusterRuleSpec
$spec.rulesSpec[0].operation = “remove”
$spec.rulesSpec[0].removeKey = $rule.key
$spec.rulesSpec[0].info = New-Object VMware.Vim.ClusterVmHostRuleInfo
$spec.rulesSpec[0] = $
$spec.rulesSpec[0].info.vmGroupName = $rule.extensiondata.vmgroupname
$spec.rulesSpec[0].info.affineHostGroupName = $rule.extensiondata.AffineHostgroupname
$spec.groupSpec = New-Object VMware.Vim.ClusterGroupSpec[](2)
$spec.groupSpec[0] = New-Object VMware.Vim.ClusterGroupSpec
$spec.groupSpec[0].operation = “remove”
$spec.groupSpec[0].removeKey = $rule.extensiondata.vmgroupname
$spec.groupSpec[0].info = New-Object VMware.Vim.ClusterVmGroup
$spec.groupSpec[0] = $rule.extensiondata.vmgroupname
$spec.groupSpec[1] = New-Object VMware.Vim.ClusterGroupSpec
$spec.groupSpec[1].operation = “remove”
$spec.groupSpec[1].removeKey = $rule.extensiondata.AffineHostgroupname
$spec.groupSpec[1].info = New-Object VMware.Vim.ClusterHostGroup
$spec.groupSpec[1] = $rule.extensiondata.AffineHostgroupname
$_this = Get-View (get-cluster $Mycluster)
$_this.ReconfigureComputeResource_Task($spec, $true)

Here are some extra vars if you want to make a report from each rule”
#The name of the Rule

#name of the VM group and host group assigned to the Rule
$vmgroupname = $rule.extensiondata.vmgroupname
$hostgroupname = $rule.extensiondata.AffineHostgroupname

#list of VMs by name in the VM Group
$vmlist = get-vm -id $rule.vmids | %{$}

#list of hosts by name in the Host group
$hostlist = get-vmhost -id $rule.AffineHostIds | %{$}

VMware Links:

This code will grab the vmotion count that you see on the summary page of your cluster object. This counter is total vmotions to include system and manual migrations. If you want the manual ones you will need to parse out your vievents.

Get-Cluster | Select Name,@{N=”vMotion”;E={$_.ExtensionData.Summary.NumVmotions}}


This code will give you a list of all VM names and the OS configured for it. This code does not tell you what OS is running within your VM. You need vmware tools running within the guest to pull that info. You could you this script combined with the guest OS check to make sure they match.
**note – I added an if statement to filter if you only want Windows OS. Edit as needed.

connect-viserver “myvCenter”
$vmlist = @()
$GuestOSCheck = Get-VM | Get-View | Select name, @{N=”OS”;E={$_.Summary.Config.GuestFullName}}
foreach($single in $guestOSCHeck){
if($single.os -match “Windows”){
$vmlist += $single
Disconnect-viserver -confirm:$False

This will enable lockdown mode for your host.
Be careful with this because it will disable your ability to use the root account when you SSH to your host.

(get-vmhost “” | get-view).EnterLockdownMode()

To disable use:
(get-vmhost “” | get-view).ExitLockdownMode()

This code will upgrade your VMs virtual hardware level to the highest available value for the host its running on.
I’ve also added some checks and limits that you can remove, change, or add as needed.
**Note, you must power off the VM to upgrade the virtual hardware so be sure you want to do that before running this script.

The code will do the following:
– check if the tools are updated/current.
– – if tools are current, check for a windows OS config in the vmx.
– – – if windows VM, shutdown the vm OS, wait until its in a “poweredoff” state, then update the virtual hardware and confirm the prompt to upgrade.

All you need to do is change this var to your VMs name and paste the code below it.
$vmname = “MyVMName”

$checkToolsStatus = Get-VM $vmname | %{$_.Guest.Extensiondata.ToolsVersionStatus}
if($checkToolsStatus -match “guestToolsCurrent”){
$GuestOSCheck = Get-VM $vmname | Get-View | %{$_.Summary.Config.GuestFullName}
if($GuestOSCheck -match “Windows”){
Get-VM $vmname | Shutdown-VMGuest
do {
sleep 3
$vmcheck = get-vm $vmname | %{$_.powerstate}
} until ($vmcheck -match “PoweredOff”)
$id=(get-vm $vmname).id
$vmview=get-view -id $id
$param = @($null)
sleep 5
get-vm $vmname | get-vmquestion | set-vmquestion -defaultOption -confirm:$false

VMware Links:

You can use this code to send that array data, var output, or CSV file to anyone via email.
Two ways you can do this:

The quick way (no attachments):
– For this you will need a from, to, and valid SMTP server to send the message to.
– To email your script output, just replace the $body var or assign the var to $body.
– $body += $yourscriptdata

$emailFrom = “”
$emailTo = “”
$subject = “Email subject”
$body = “Body of the message”
$smtpServer = “”
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($emailFrom, $emailTo, $subject, $body)

The detailed way (using attachments)
– I added $thedate var so you can add a date string to your body or subject.
– You can add more files, just add more $fileX parms.
– You can send it to more than one person or group by adding more “$msg.To.Add” lines.

$thedate = (get-date).tostring(‘ddMMMyyy’)
$smtpServer = “”
$file1 = “C:\temp\file1.csv”
$file2 = “C:\temp\vcenterExport.csv”
$att1 = new-object Net.Mail.Attachment($file1)
$att2 = new-object Net.Mail.Attachment($file2)
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = “”
$msg.Subject = “EMail Subject”
$msg.Body = “Body of message – See attached CSV files `n`n`n`n”
sleep 10
del c:\temp\file1.csv
del c:\temp\vcenterExport.csv

*****Its important to run the $attX.Dispose() to free up system memory.

Quick vMotion code: (extra checks)
Get-VM -Name “MyVM” | Move-VM -Destination (get-vmhost “”) -runasync:$true

Many ways exist to complete this command.
Here is one without the double check so it will run faster:
Move-VM -vm “MyVM” -Destination” -runasync:$true

Some Special adds if needed, just tack these on to the above lines as needed:
-DiskStorageFormat “thin”
-DiskStorageFormat “thick”
-Datastore “myStorageLUN”
-Datastore (get-datastore “myStorageLUN”)

VMWare Link:

This will help you Export/Import the settings for a vApp so you can restore it if vCenter dies or if you need to migrate it to another location.
If you can power off all of your VMs an Export is easy.
Just run this and it will dump to a flat file:
 get-vapp -name “MyvApp” | export-vapp -destination “c:\temp\”

If you cannot power off your VMs or Cannot find some down time, this will do it without any interruption to your VMs.
It may seem interruptive but it works!

1) Screen cap or document all of the vapp settings. This includes the startup order, resources, and any special settings in the Advanced tab under Options. A manual backup will save you if some setting does not fully export using the API.
2) Disconnect all of the hosts and remove from inventory. (This is because you cannot export settings from a powered on vApp.)
– If you are migrating the vApp to another vcenter, just add the hosts to the new vcenter. It will disconnect them on the old vcenter without impacting the VMs.

3) Once all of the hosts that contain the vApp VMs are disconnected and removed, shutdown the vapp.
4) Export the config with this code:
 get-vapp -name “MyVapp” | export-vapp -destination “c:\temp\”

5) Enable DRS on the new cluster you want to import the vapp to. (You cannot Import a vApp without DRS enabled.)
6) Import it with this command
Import-vApp -Source “c:\temp\MyVapp.ovf” -VMHost (get-vmhost “”) -Location (get-cluster MyCluster) -Name “MyVapp” -force

7) Verify and edit the settings on imported vapp. (This is where your notes from step one comes in handy)
8) Move the vms into the imported Vapp. (Just drag the VMs from the host to the vApp.)
9) Once all of the VMs are in the vApp, Edit settings again and fix the startup order.

VMware Links:

Need to run a quick DNS pull for a list of hosts, VM, vmotion IPs?
Run this, it takes seconds to pull 50+ dns items into a list that you can dump into Excel, csv, etc.

$myDNS = @()
$myDNS += [System.Net.Dns]::GetHostAddresses(“”) | %{$_.IPAddressToString}
$myDNS += [System.Net.Dns]::GetHostAddresses(“”) | %{$_.IPAddressToString}
$myDNS += [System.Net.Dns]::GetHostAddresses(“”) | %{$_.IPAddressToString}
$myDNS += [System.Net.Dns]::GetHostAddresses(“”) | %{$_.IPAddressToString}


OR you can reformat it with a loop + Var if you like using arrays for your host list
$hostname = @()
$hostname += “”
$hostname += “”
$hostname += “”
$hostname += “”

$myDNS = @()
Foreach($singleHost in $Hostname){
$myDNS += [System.Net.Dns]::GetHostAddresses(“$singlehost”) | %{$_.IPAddressToString}