Showing posts with label vmware. Show all posts
Showing posts with label vmware. Show all posts

Sunday, August 2, 2020

Powershell: VMWare vCenter Standard, Move all VM from a host and place it in maintenance mode

I have VMWare vCenter standard edition, and there is a limitation with placing the server in maintenance mode, as it will never complete unless you move all the VM from that host to another host and then place the server in maintenance mode. something I really don't like, its a small basic regular thing any admin need to do, maybe updating the server or whatever.
When it comes to manual work (which I hate so much), you will need to distribute your VMs based on the host which has more free memory and also healthy. the challenge I have is I have about 30 servers all running the standard edition, and I need to update the hosts, so redistribute the load and check which server has more memory, and Bla Bla Bla, of boring things, so I got the idea to automate this.
The below script (can be downloaded from here too) will do the following:
  • Import the VMWare module and connect to the VI Server.
  • Get a list of all the VM in the host that should be placed in maintenance mode.
  • for each virtual machine, find the proper server to place it (based on the most server which has the freest memory).
  • Redistribute the load.
    • if no server is available with enough memory to have the VM, the script will let you know and won't overcommit your servers, unless you want so.
  • After all is done, will provide you with a basic report about each VM, the old host, and the new host.
  • place the server in maintenance mode.
Parameter and Overcommit prevention
The script requires some parameter to be filled before it can do the magic:
  • FromVMHostName: The name of the server you want to move the VM from and place it in maintenance mode, Please Note that the server name should be exactly as the one registered in your vCenter, so if you are using FQDN, pass it here too.
  • MaxMemAllowed: The Percentage of the total free memory of the destination server before being excluded from the selection, the default value is 80, so no VM will be shipped to any server which has more than 80 percent of utilized memory.
  • vCenter: your vCenter IP or name
  • FromCluster: the cluster you want to search through
Usage and Execution

Set-AutoEMM.ps1 -FromVMHostName myserver.domain.local -MaxMemAllowed 80 -FromCluster Production

The above line will get all the VMs from myserver.domain.local and distribute them to all hosts in the same cluster which has less than 80 percent utilized memory.

What if and during the migration the servers get utilized more than 80 percent?

Well, the script will evaluate the server before and after each VM being moved and do the proper calculation, so before moving the VM the script will calculate and check if the destination server will be over 80 percent, it will be excluded from being a destination for the migration. If no more hosts are available with less than 80 percent memory utilization (or whatever the value you set in the MaxMemAllowed ), the script will fail and stop, surely it will display something on the screen telling that no more hosts available.

Hope you enjoy this script and find it useful, please let me know by commenting or dropping me a message farisnt@gmail.com

If you notice any bug or issue, let me know :)



  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<# .Description
    Function To Move VMs From 1 host to other 
    It Depend on the host Memory availibilty 
    .Example
    Set-AutoEMM.ps1 -FromVMHostName MyVMHostServer -MaxMemAllowed 80 -FromCluster Production
    -FromVMHostName: The Source VMHost Server
    -MaxMemAllowed: Percentage of memory limit, default is 80, if the server memory load is 80% or more VMs wont be moved to this server
                    and the script will search for another server to move the VM to
                    if there is no more available server with less than 80% or the required value, the script will stop and show an error
                    indicating the failure.
    -FromCluster: Cluster name where the hosts are exist
    This Script is for free you can update and use it as you want, Please add your name under the contributor
    Created By: 
     -Faris Malaeb
    Contributor
    #Requires -Modules VMware.VimAutomation.Core
#>
param (
	[parameter(mandatory = $True)]
	$FromVMHostName ,
	[parameter(mandatory = $False)]
	[int]$MaxMemAllowed = "80",
	[parameter(mandatory = $True)]
	$vCenter ,
	[parameter(mandatory = $True)]
	$FromCluster 
)

################# General Variables
$Finalresult=@()
[bool]$ErrorFlag=$False
##########
########## Required module
Import-Module VMware.VimAutomation.Core
###############

Function Get-MostFreeServer ($NeededMemorySizeinGB) {

        #Below I will get the list of VMHost which are applicable for migration which include the following filter
          #Excluding the Move From Server
          #Server with a proper state
          # Have enough memory that match the user input parameter
    $CurrentServersLoad=Get-VMHost |  where{ ($_.name -notlike $FromVMHostName) -and ($_.ConnectionState -notlike "*main*") -and ($_.ConnectionState -notlike "NotResponding") -and ($_.ConnectionState -notlike "Unknown") -and ((($_.MemoryUsageGB + $NeededMemorySizeinGB)/$_.MemoryTotalGB * 100) -lt $MaxMemAllowed) } | Sort-Object MemoryUsageGB  
    if (($CurrentServersLoad).count -lt 1){ Write-Host "I am sorry, but there is no space for any migration..."
    # No Server available to hold the migration
    return "PS_FAIL_No_Resource"
    }
    Else{
    #Yes there are at least one server that is good to host the VM Migration.
    return $CurrentServersLoad[0].Name
    }   

}
#Checking the MaxMemAllowed User input to make sure that the user type a proper value
Write-Host "Validating the input" -ForegroundColor Yellow
if (($MaxMemAllowed -le 5) -or ($MaxMemAllowed -gt 99)){
Write-Host "I am sorry, but it seems that the MaxMemAllowed is not correct" -ForegroundColor Red
Write-Host "The MaxMemAllowed cannot be as "$MaxMemAllowed -ForegroundColor Red
break
}


Try
{
	
	if ($global:DefaultVIServer.count -eq 0)
	{
		#If No Connection to VC found then the script will start a new connection, otherwise the -vCenter Parameter is ignored
		write-host "Please Connect to vCenter using Connect-VIServer first" -ForegroundColor Yellow
		$VC = Get-Credential -Message "Please type the username and password for vCenter" -ea Stop -UserName "administrator@vsphere.local"
		if ($VC -eq $null) { Write-Host -ForegroundColor Red "User press Cancel, I am leaving ..."; exit }
		Connect-VIServer -Credential $VC -Server $vCenter -ErrorAction Stop
		
	}
	
	Write-Host "Getting a list of VMs in host "$FromVMHostName -ForegroundColor Yellow
	#Get a list of VM on the server that should be migrated. only powered on VM.. I dont care about powered off VM
	$VMsInHost = Get-VMHost $FromVMHostName -ErrorAction Stop | Get-VM | where{ $_.PowerState -like "*On" }
	Write-Host "Total Number of VM to move is:"$VMsInHost.Count -ForegroundColor Yellow
	Foreach ($SingleVM in $VMsInHost){
        #Creating an Object to store the progress report
	    $VMnewLocation=new-object PSObject
        $VMnewLocation | Add-Member -NotePropertyName "VM Name" -NotePropertyValue $SingleVM.Name
        $VMnewLocation | Add-Member -NotePropertyName "Old Host" -NotePropertyValue $SingleVM.VMHost
        
		Write-host "Parsing VM " $SingleVM.Name -ForegroundColor Yellow
        #Call the function to get a list of possible servers to move the VM to.
        $Migrate=Get-MostFreeServer -NeededMemorySizeinGB $SingleVM.MemoryGB
        #PS_FAIL_No_Resource is a custom message will return from the function incase there is no available server to host the VM Migration.
            if ($Migrate -notlike "PS_FAIL_No_Resource"){
                Write-Host "Moving "$SingleVM "to "$Migrate ",Please wait a few seconds" -ForegroundColor Yellow
                #Move the VM
                Move-VM -VM $SingleVM -Destination $Migrate -ErrorAction Stop
                sleep -Seconds 1
                $VMnewLocation | Add-Member -NotePropertyName "New Host" -NotePropertyValue ((get-vm $SingleVM).vmhost.Name)
                Write-Host $SingleVM "is now in the following host" $VMnewLocation.'New Host' -ForegroundColor Yellow
                $Finalresult+=$VMnewLocation 
            }
		    Else {
                    #No available server, the following message will be displayed.
                Write-Host "It seems there is no more servers to move the load, you can change the value of the MaxMemAllowed to allow more load... Nothing more to do." -ForegroundColor Red
                Write-Host "I cannot move "$SingleVM
                Write-Host "final report is:"
                $Finalresult
                $ErrorFlag=$true
                return
                }
    }
}



Catch [exception]{
# Any unexpected error will return here and stop the script execution.
	Write-Host $_.Exception.message -ForegroundColor Red
    $ErrorFlag=$true
    break

}

Finally{
        #Checking the server is any more VM on it, if there is no VM, then place the server in maintenance Mode
        #Else, there should be an error indicating what is going on.
        if ($ErrorFlag -notlike $true){
            if ((Get-VM | where{ ($_.host -like $FromVMHostName) -and ($_.PowerState -like "*on")}).count -eq 0) { 
                Write-Host "All Done, will place the server in maintenance mode" -ForegroundColor Yellow
                Set-VMHost $FromVMHostName -State Maintenance
                Get-VMHost $FromVMHostName
                $Finalresult | ft
            }
            if ((Get-VM | where{ ($_.host -like $FromVMHostName) -and ($_.PowerState -like "*on")}).count -gt 0) { 
                 Write-Host "It seems that VM Migration not completed. maybe some resource issue"
                 $Finalresult | ft
            }
        }
}

#Use it on your own risk.

Monday, May 2, 2016

VMWare PowerCLI - Connecting to Esxi Server and get ESXi hosts Part 2

In part 1 Getting command and remote connection, I write about how to import PowerCLI modules to be able to execute commands.
Now I will write about how to connect, and where.
Depend on the requirement, you may want to connect to ESXi host or vCenter in order to perform an operation.
Most of the operation can be executed direct after connecting to vCenter, but incase and for a reason vCenter is not available you might connect direct with ESXi Host insted of connecting to vCenter.
Lets assume that we want connect to vCenter and get all the host in all the clusters.
We can use the following commands

#Import Vmware Module
Add-PSSnapin VMware.VimAutomation.Core
#We Will ask the user to write the username and password for vSphere, you can comment this line if your
#vCetner is joined to the domain and you are connected to a domain joined computer
$viCredential = Get-Credential -Message "Please Write your vCenter username and password"
#This command will be used to connect to Esxi Server or vCenter
#You can remote the -Credential $viCredential, if your using domain joined computer and your vCenter is
#Joined to the domain
Connect-VIServer MyvCenterServer -Credential $viCredential
#Get all the Servers in the vCenter in all clustered
Get-VMHost | Format-Table -AutoSize name, NumCpu, ConnectionState
#Close the remote connection
Disconnect-VIServer * 

As you can see the main steps are
1- Make sure that you have the module or import then as I explained in part 1
2- Connect-VIServer is used to connect with ESXi host or with the vCenter, in my case I will connect with vCenter
you can remove the -Credential $viCredential if your Esxi hosts and vCenter are joined to the domain and the computer you are using is domain joined computer.
Get-VMHost can be used to get Esxi hosts piping this command to Format-Table it mean that we want to have custom properties in the returned table.
-Autosize will make the columns close to each other.
name, NumCpu, ConnectionState, are properties we want show in the table.
The output will be something like this

Name              NumCpu ConnectionState
----              ------ ---------------
esxi01.lab.local     32       Connected
esxi02.lab.local     32       Connected
esxi03.lab.local     32       Connected
esxi04.lab.local     32       Connected
esxi05.lab.local     32       Connected
esxi06.lab.local     32       Connected
esxi07.lab.local     32       Connected
esxi08.lab.local     32       Connected
esxi09.lab.local     32       Connected
esxi10.lab.local     32       Connected
esxi11.lab.local     32       Connected
esxi12.lab.local     32       Connected
esxi13.lab.local     32       Connected
esxi14.lab.local     32       Connected
esxi15.lab.local     32       Connected
esxi16.lab.local     32       Connected

Disconnect-viserver * will disconnect all the open session to all VI Servers (ESXi host or vCenter).

If you want to show different properties in the table, you can Pipe Get-VMHost to get-member
so the command will be like Get-VMHost | get-member
Just Run the command above after you connect to vCetner, the result will be like the following

Name                  MemberType
----                  ----------
ConvertToVersion          Method
Equals                    Method
GetHashCode               Method
GetType                   Method
IsConvertableTo           Method
LockUpdates               Method
ToString                  Method
UnlockUpdates             Method
ApiVersion              Property
Build                   Property
Client                  Property
ConnectionState         Property
CpuTotalMhz             Property
CpuUsageMhz             Property
CustomFields            Property
DatastoreIdList         Property
DiagnosticPartition     Property
ExtensionData           Property
FirewallDefaultPolicy   Property
HyperthreadingActive    Property
Id                      Property
IsStandalone            Property
LicenseKey              Property
Manufacturer            Property
MaxEVCMode              Property
MemoryTotalGB           Property
MemoryTotalMB           Property
MemoryUsageGB           Property
MemoryUsageMB           Property
Model                   Property
Name                    Property
NetworkInfo             Property
NumCpu                  Property
Parent                  Property
ParentId                Property
PowerState              Property
ProcessorType           Property
State                   Property
StorageInfo             Property
TimeZone                Property
Uid                     Property
Version                 Property
VMSwapfileDatastore     Property
VMSwapfileDatastoreId   Property
VMSwapfilePolicy      Property

You can add any Property value to the pipe, lets assume u wana get a list of VMHost in a table and view only PowerState,Name,ProcessorType        

#Import Vmware Module
Add-PSSnapin VMware.VimAutomation.Core
#We Will ask the user to write the username and password for vSphere, you can comment this line if your
#vCetner is joined to the domain and you are connected to a domain joined computer
$viCredential = Get-Credential -Message "Please Write your vCenter username and password"
#This command will be used to connect to Esxi Server or vCenter
#You can remote the -Credential $viCredential, if your using domain joined computer and your vCenter is
#Joined to the domain
Connect-VIServer MyvCenterServer -Credential $viCredential
#Get all the Servers in the vCenter in all clustered
Get-VMHost | Format-Table -AutoSize PowerState, Name, ProcessorType
#Close the remote connection
Disconnect-VIServer * 


VMWare PowerCLI - Getting command and remote connection Part 1

Recently we purchase VMware ESXi 6.0 Standard Edition, we did not go for Enterprise Plus edition which have the DRS and other nice feature due to budgets issue.
In my environment we have 16 ESXi host configured as 3 cluster
- Production
- DMZ
- MGMT (vCenter - SRM - vOps)
After installing ESXi, it come the boring part which is doing the configuration 16 time for each host as we dont have DRS
The Configuration include the following:
  • vSwitch
    • NIC Teaming Policy
    • VMKernel
    • Security Profiles
  • Virtual PortGroup
    • I have a lot.. 
  • NTP Configuration
  • Start and stop services
And other details, doing this on server by server is a real time wasting, luckily VMWare have PowerCLI which is a Powershell module for ESXi, you can download and read about it here
As any other module or new module I have to work with the first thing to do is to import the module and discover its commands.
Run the following command on the computer were you install PowerCLI

    Get-Module -ListAvailable -Name vmware* | select name


The result will return the following modules


Name
----
VMware.VimAutomation.Cis.Core
VMware.VimAutomation.Cloud
VMware.VimAutomation.Core
VMware.VimAutomation.HA
VMware.VimAutomation.License
VMware.VimAutomation.PCloud
VMware.VimAutomation.SDK
VMware.VimAutomation.Storage
VMware.VimAutomation.Vds
VMware.VimAutomation.vROps
VMware.VumAutomation


The main module we will use it VMware.VimAutomation.Core, which include almost everything we need
you can import the module using PowerShell_ISE 

Once you import the module you will be able to see the module name in the module list, by selecting it all the command will appear in the list which will make your life easier.
Or if you want you can use the PowerCLI itself to access the ESXi Command and list them by using
get-command -Module VMware.VimAutomation.Core

Now you are ready to go :)

If you dont have PowerCLI installing in your computer and u wana import the command from remote server that have ESXi modules installed, you can use the following script

$RemoteCLI = New-PSSession -ComputerName PowerCLIServer
Invoke-Command -Session $RemoteCLI -ScriptBlock { Import-Module VMware.VimAutomation.Core }
Import-PSSession $RemoteCLI

Now you have ESXi Powershell modules and you can use then to execute and ESXi command

In My Next Post I will write about also basic understanding for PowerCLI and how to start using its commands

Hope this help

Like it, Share it, or comment on what you want
Hope this help as a start yet more interesting information are coming.