Hi,
I am nubby on PowerCLI and I would like some help with building a script.
The script needs to check if two VMs (named test1 and test2) are running on the same host, in a vCenter and send a notification(email) if they do.
Something similar with affinity / anti-affinity DRS rules (but without having DRS enabled on vCenter). My focus is on anti-affinity. In case this happens, I need to vMotion one of them on another ESXi host(manually or automated).
What I have done so far is this:
Get-VM | Select Name, @{N="Cluster";E={Get-Cluster -VM $_}}, `
@{N="ESX Host";E={Get-VMHost -VM $_}}, `
@{N="vCenter";E={$_.ExtensionData.CLient.ServiceUrl.Split('/')[2]}}, `
@{N="Datastore";E={Get-Datastore -VM $_}} | `
Export-Csv -NoTypeInformation C:\Scripts\file.csv
Which is getting the all the VMs and export the information on a CSV:
Name | Cluster | ESX Host | vCenter | Datastore |
test2 | cluster_test | ESXi_test1 | vCenter_test1:443 | datastore1 |
test1 | cluster_test | ESXi_test1 | vCenter_test1:443 | datastore1 |
for1.local | cluster_test | ESXi_test1 | vCenter_test1:443 | datastore1 |
VM1.local | cluster_test2 | ESXi_test2 | vCenter_test1:443 | datastore1 |
VM2.local | cluster_test3 | ESXi_test3 | vCenter_test1:443 | datastore1 |
VM31.local | cluster_test3 | ESXi_test3 | vCenter_test1:443 | datastore1 |
Thank you.
Try like this.
$tgtVM = 'test1','test2'
Get-VM -Name $tgtVM | Group-Object -Property VMHost | %{
if($_.Count -gt 1){
$vm = $_.Group | Get-Random
$esx = $vm.VMHost
$tgtEsx = Get-Cluster -VM $vm | Get-VMHost | where{$_.Name -ne $esx.Name} | Get-Random
Move-VM -VM $vm -Destination $tgtEsx -Confirm:$false
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Give a try with below code.
I am assuming only two host in your cluster. Let me know if that is not the case, I will try to alter the script.
You can add this script in scheduled task to check the VMs and automatically move to other host when they happen to run on same host.
Connect-VIServer yourVC
$ehost1 = Get-VMHost hostname1
$ehost2 = Get-VMHost hostname2
$vm1 = Get-VM test1
$vm2 = Get-VM test2
$vm1L = Get-VMHost -VM $vm1
$vm2L = Get-VMHost -VM $vm2
if($vm1L -eq $vm2L)
{
if ($vm1L -eq $ehost1) { Move-VM -VM $vm1 -Destination $ehost2 -Confirm:$false}
else { Move-VM -VM $vm1 -Destination $ehost1 -Confirm:$false }
}
Disconnect-VIServer yourVC -Confirm:$false
Here is the updated script (handles more than two hosts in the cluster)
Connect-VIServer yourVC
$vm1 = Get-VM test1
$vm2 = Get-VM test2
$vm1L = Get-VMHost -VM $vm1
$vm2L = Get-VMHost -VM $vm2
if($vm1L -eq $vm2L)
{
foreach($ehost in (Get-Cluster yourClusterName |Get-VMHost))
{
if ($vm1L -ne $ehost)
{
Move-VM -VM $vm1 -Destination $ehost -Confirm:$false
Disconnect-VIServer yourVC -Confirm:$false
exit
}
}
}
else { Disconnect-VIServer yourVC -Confirm:$false }
Try like this.
$tgtVM = 'test1','test2'
Get-VM -Name $tgtVM | Group-Object -Property VMHost | %{
if($_.Count -gt 1){
$vm = $_.Group | Get-Random
$esx = $vm.VMHost
$tgtEsx = Get-Cluster -VM $vm | Get-VMHost | where{$_.Name -ne $esx.Name} | Get-Random
Move-VM -VM $vm -Destination $tgtEsx -Confirm:$false
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi LucD, Prakash,
Thank you very much for your quick reply.
Here is what I made, after getting your replies, and I want to share it.
# Check VMs presence Report
# Variable definitions
$Timer = (Get-Date -Format yyyyMMdd-hhmm)
$OutputFile = "C:\data\report"+$Timer+".csv"
$vCenterServer = "vCenter1.local"
$vCenterUser = "Administrator@vsphere.local"
$vCenterUserPwd = "xxxxxxxxxxxxxxxxxxxxxxx"
$MailFrom = "User01 <user01@example.com>"
$MailTo = "User02 <user02@example.com>"
$MailSubject = "Alert:VM on the same host"
$MailBody = "Alert:VM on the same host. Perform manual migration."
$SmtpServer = "smtp.server.com"
# Add the PowerCLI snapin
Add-PSSnapin VMware* -ErrorAction SilentlyContinue
# Connect to the vCenter server
Connect-VIServer -Server $vCenterServer -User $vCenterUser -Password $vCenterUserPwd
# Get all the VM information and append this to the output file
$tgtVM = 'test1.local','test2.local'
Get-VM -Name $tgtVM | Group-Object -Property VMHost | %{
if($_.Count -gt 1){
$vm = $_.Group
$esx = $vm.VMHost
$tgtEsx = Get-Cluster -VM $vm | Get-VMHost | where{$_.Name -ne $esx.Name}
Get-VM $vm |`
Select-Object Name, @{N="ESX Host";E={Get-VMHost -VM $_}}, @{N="vCenter";E={$_.ExtensionData.CLient.ServiceUrl.Split('/')[2]}} | Out-File -FilePath $OutPutFile
}
}
# Send the output file via e-mail
Send-MailMessage -from $MailFrom -to $MailTo -subject $MailSubject `
-body $MailBody -Attachment $OutputFile -smtpServer $SmtpServer
Disconnect-VIServer $vCenterServer -Confirm:$false
I do not want to move automatically the VMs just yet, not before I do an audit of the internal services, so the vMotion will be done manually(for now).
Next stage:
I have several pairs of VMs(2 email_servers, 2DNS_servers and so on...) on the vCenter1 and I want to have the same notification (from above). How can I do that?
I have similar requirements, for multiple vCenters, so I need to run these script against on multiple vCenters. How can I do that?
For security reason, how can I hash the password and present the hash to vCenter to allow connection?
Thank you.
Hi,
Can someone give me some hints for the second part of my script?
Thank you
Is the VM's DisplayName sufficient to determine if 2 VMs are the same ?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi,
Vms display names should be enough.
I have 3 pairs :
mail1.* , mail2.*
dns1.* , dns2.*
dhcp1., dhcp2.
These vms types reside on 6 different vcenters.
I need to get emails in case 2 vms with similar names reside on the same host.
Thanks a lot.
Do the names always follow that convention: <n * alpha characters><1 * numeric character>. ?
If yes, grouping based on RegEx expression might give the desired result.
See for example
$vmNames = 'mail1.test','mail2.test','vm1.test','dhcp1.test','dhcp4.test'
$vmNames | Group-Object -Property {([regex]"^(?<Name>[a-zA-Z]+)\d\.").match($_).Groups['Name'].Value} |
where {$_.COunt -gt 1} |
Select @{N='Problem';E={$_.Count}},@{N='VMs';E={[string]::Join(',',$_.Group)}}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks LucD,
This works better for my scenario.
Your help is well appreciated.
Hi.... Required an help on the below script that once it is checked and if they are in same host need to be vmotion to another host & send the email
PLease help on it