03.31
I just found Alan Renouf ‘s VI Toolkit Quick Reference [PDF], which I wish I’d seen a few months ago.
vSphere & Powershell Scripting
I just found Alan Renouf ‘s VI Toolkit Quick Reference [PDF], which I wish I’d seen a few months ago.
Remotely accessing ESX Guests on an (emulated) portable device. If only I could convince work to get me a BlackBerry it would free me from my desk.
The only problem being; I’m not entirely sure where I would go instead.
If you’re using templates in ESX, and guest customisation fails when the drive is set to non-persistent.
This script looks at your templates, and outputs a list of those with non-persistent drives.
# Set up an empty array $arrTemplatesWithPersistentDrives = @() # Get all the template objects $objTemplates = Get-Template # Loop through each template ForEach ($objTemplate in $objTemplates){ # Get the drives associated with that template $objHardDisks = $objTemplate | Get-HardDisk # Loop through each drive ForEach ($objHardDisk in $objHardDisks){ # If any of the drives are non-persistent, add the template object to the empty array If ($objHardDisk.Persistence -match "non"){$arrTemplatesWithPersistentDrives += $objTemplate} } } # List the names of the unique templates in the array (as a template with more than one non-perisistent drive would appear more than once) $arrTemplatesWithPersistentDrives | Sort-Object -Unique | Select-Object Name
In a previous post, I said that there was no real way of extracting information from the VC database.
This isn’t entirely true, as until I started using PowerShell, I was using SQL to query the VC database directly.
SELECT VPX_VM.GUEST_OS, VPX_VM.MEM_SIZE_MB FROM VC_DB.dbo.VPX_VM VPX_VM WHERE (VPX_VM.GUEST_OS='winXPProGuest')
SELECT VPX_VM.LOCAL_FILE_NAME, VPX_VM.GUEST_OS, VPX_VM.IS_TEMPLATE, VPX_VM.MEM_SIZE_MB, VPX_VM.HOST_ID, VPX_VM.ID FROM VC_DB.dbo.VPX_VM VPX_VM WHERE (VPX_VM.IS_TEMPLATE=1) ORDER BY VPX_VM.LOCAL_FILE_NAME
SELECT VPX_HOST.ID, VPX_HOST.DNS_NAME, CAST (VPX_HOST.MEM_SIZE AS BIGINT) FROM VC_DB.dbo.VPX_HOST VPX_HOST ORDER BY VPX_HOST.DNS_NAME
SELECT VPX_VM.LOCAL_FILE_NAME, VPX_VM.DNS_NAME, VPX_VM.GUEST_OS, VPX_VM.IS_TEMPLATE, VPX_VM.IP_ADDRESS, VPX_VM.MEM_SIZE_MB, VPX_VM.GUEST_STATE, VPX_VM.POWER_STATE, VPX_VM.HOST_ID, VPX_VM.ID, VPX_VM.BOOT_TIME FROM VC_DB.dbo.VPX_VM VPX_VM WHERE (VPX_VM.IS_TEMPLATE<>;1) ORDER BY VPX_VM.DNS_NAME, VPX_VM.LOCAL_FILE_NAME
These were based on ideas from Wayne’s World of IT. While it’s a lot less friendly to work with, the advantage is that it’s a lot quicker than the VI Toolkit’s Get- commands, and I still use them from time-to-time.
Although you could use this approach to modify entries in the database, I would only ever feel comfortable using this to extract information.
We were working recently to align our guest VM object names with their DNS names. As we have over 800 guests, this would have taken us a while to compile by hand. I wrote the following PowerShell script to flag machines where the hostname differs from the object name.
# Get all of the VMs as an object
$objVMs = Get-VM
# Loop through all of the VMs
ForEach ($objVM in $objVMs){
# Get the VM Guest object (which contains the DNS information)
$objGuest = Get-VMGuest -VM $objVM
# Set a variable to the VM object name
$objVMName = $objVM.Name
# Set a variable to the DNS name
$objVMFQDN = $objGuest.Hostname
# Sometimes the FQDN is empty or blank, so we screen those out with an "If not equals"
If (($objVMFQDN -ne "") -and ($objVMFQDN -ne $null)){
# The host name is the first part of the FQDN, so we split it, and take the first (0) segment as our host name
$objVMHostName = $objVMFQDN.split('.')[0]
}
Else {
$objVMHostName = $null
}
# Check that the host name is not null, and if the hostname does not match the VM name, echo the results
If (($objVMHostName -ne $null) -and ($objVMName -notlike $objVMHostName)){
# Write the results on one line, the VM object name, then the host name in square brackets. The "`" is an escape character
Write-Host $objVMName `[$objVMHostName`]
}
}
This worked perfectly. While I could have extended the script to rename these machine objects to the hostname, it was safer to look at each one individually. Even so, the script saved us a few hours of tedious work.
About 2 years ago, I moved from working as an application packager, and being responsible for 2 or three (VMware Workstation) virtual machines, to working on the supporting infrastructure for over 200 packagers who require around 700 virtual machines on VMware vSphere (which was at that point called VMware ESX).
While I was (and I still am) impressed by the technology, there were a few things that started to grate with such an otherwise excellent product:-
I had a look into running scripts on the host, and toyed with the Remote CLI Appliance, but it was the VMware PowerCLI that unlocked the functionality I’d been looking for.
VMware VMware PowerCLI (Formerly VI Toolkit for Windows) utilises Windows PowerShell to provide a command-line driven interface for your virtual infrastructure. This can dramatically reduce the amount of time taken to perform almost all tasks and also allows advanced reporting functionality.
This is nowhere near a proper introduction in how to use PowerShell, but should give enough information to get you started, and hopefully make you want to find out more.
Firstly download and install the appropriate version of Windows PowerShell for your operating system.
Then you need to download and install VMware vSphere PowerCLI.
If you’re installing PowerShell for the first time you need to change the default execution policy. To do this:
Set-ExecutionPolicy - ExecutionPolicy Unrestricted
This allows you to run scripts which have not been signed with a digital signature (which will almost certainly include the scripts you’re using to learn)
The PowerShell security model is designed to address the failures of VBScript, which is a common virus attack vector. PowerShell scripts (which have a PS1 suffix) do not run when invoked in Windows. Also, as noted above, the default execution policy is not to run unsigned scripts. In order to run a script, you need to modify the execution policy, and then run the script name from the command line. This helps to prevent them from being launched by accident.
Users only have the same permissions as they would get if they logged into Virtual Infrastructure Client. However as wide-scale modification is made easier, the potential impact of mistakes is made greater. PowerShell includes specific measures to alleviate risk.
PowerShell works using cmdlets. These are typically fairly descriptive, and great care has been taken to make them work in a consistent and logical way. Most cmdlets follow the format verb-noun, with modifiers for the target of the action, and any cmdlet specific options. They are not case sensitive.
The downside of the commands being so descriptive is that they are sometimes quite long. In order to alleviate this PowerShell allows Aliases to be created. Most common Windows Shell commands already exist in PowerShell as aliases. For example CD, DIR, CLS & REN all work as expected. I find these quite useful when working interactively (entering commands at the prompt for immediate execution), but I tend to avoid them in scripts for the sake of consistency and clarity.
When launching scripts, you need to use absolute paths. For example, if you want to launch the script C:\Scripts\ExampleScript.ps1, when you’re in C:\Scripts you would either need to enter the whole path, or use ./ExampleScript.ps1.
In order to use PowerShell, you need to import the VI commands using
Add-PSSnapin VMware.VimAutomation.CoreRunning the VMware vSphere PowerCLI shortcut created when you install the application does this on launch.
![]()
Running the standard PowerShell shortcut does not.
![]()
PowerShell is object-oriented, meaning that the information returned from commands can be easily used as the input for another command.
If you want to put comments into your scripts, PowerShell ignores anything after the #symbol.
Here are a couple of commands to get you started. Open up the PowerCLI command line using the VMware vSphere PowerCLI shortcut, then enter them as shown.
Get-HelpCan display help on the various cmdlets. Running this as above shows the syntax for getting help.
Get-CommandUse to find out all the commands containing certain keywords. For example…
Get-Command *-VM
…uses the wildcard character (*) to show all commands that end with VM, this shows all the cmdlets that can be used to operate on Virtual Machines. Let’s try a simple one…
Get-VMYou should now get an error message saying that “You are not currently connected to any servers. Please connect first using Connect-VIServer or one of its aliases.”. Let’s do that…
Connect-VIServer Name_of_your_vCenter_ServerThis uses your current windows credentials to connects to the specified server. You need to do this before you run any VMware specific PowerShell commands. Now try this again…
Get-VMYou should now be looking at a list of virtual machines managed by your vCenter server. You can reduce the scope by adding switches, for example…
Get-VM –Name A*
…gets all machines with names starting “A”. For more information, try
Get-Help Get-VM -Detailed
Variables in PowerShell are always preceded by a $ symbol. You can set a variable to the result of any kind of PowerShell command, for example, you can store the results of a Get-VM in a variable…
$objVMs = Get-VM
then use that variable any time you need it, typing
$objVMs
Will display the virtual machine objects stored in the variable. This variable is a collection of objects, each object representing a virtual machine, so we can run more commands against this variable:
Get-VMGuest -VM $objVMs
This lists the State, IP Address and guest OS of all your machine objects.
Instead of using variables for commands like this, you can also pipe the result of one command, straight into another. The equivalent of the above command, using pipes rather than variables is
Get-VM | Get-VMGuest
The objects output byt he first command are piped straight into the second command. Pipes are used extensively in PowerShell, and many cmdlets can be linked together using pipes. This means you can run some complex commands in PowerShell at the command prompt in one line, rather than resorting to writing a script.
Have a play around with these commands in your test environment before moving onto the next section. As long as you’re using Get- based commands, (rather than Set- or Remove-) you shouldn’t make any changes.
Scripts are simply collections of commands linked together into a text file.
Here are a couple of example scripts, showing what can be done. Copy into notepad, and save with a PS1 extension. You should run Connect-VIServer interactively before running any of the scripts (or add it as the first line to the script file).
$strVm = Read-Host "Please enter the VM name" $vm = Get-VM -Name $strVm if ($vm.PowerState -eq "PoweredOn") { $event = Get-VIEvent -Entity $vm | where-object {$_.fullFormattedMessage -like "Task: Power on Virtual Machine"} $VM.Name $VM.PowerState (Get-VMGuest -VM $VM).IPAddress[0] if ($event -eq $null) { Set-Variable -Name user -Value "N/A" } else { Set-Variable -Name user -Value $event[0].username } $strMessageText = "Machine: " + $VM.Name + "`n" + "Power State: " + $VM.PowerState + "`n" + "IP Address: " + (Get-VMGuest -VM $VM).IPAddress[0] + "`n" + "Switched on by: " + $user $strMessageText } else {Write-Host "Machine not powered on"}
This script asks the user for a machine name (using Read-Host), then converts that string to a computer object, then (assuming the machine is switched on and VMware Tools is running), displays the DNS name, IP address and the username of the last user to power on the machine (as shown in the machine’s Event Log). The `n is a carriage return.
ForEach ($strMachine in (get-vm | Where-Object {$_.MemoryMB -gt "2000"})){ Get-VMGuest -VM $strMachine | Where-Object {$_.OSFullName -like "Microsoft Windows XP Professional*"} | Select-Object VMName, IPAddress }
This script could easily be modified and used as a component to make modifications on machines fulfilling certain criteria.
Almost anything that can be done in the GUI can be done in PowerShell. Machines can be deployed, customized, switched on, migrated between hosts and resource pools etc. Or you could get the last time a machine was switched on, and by whom.
You can also use PowerCLI to report on the status of guests and hosts. Check out Alan Renouf’s excellent PowerCLI Daily Report, or Hugo Peeter’s script to track free space in your datastores.
One drawback of the API is that performance of cmdlets (especially Get-VM) is quite slow. Hopefully this will be addressed in future versions.
There are many tools, example scripts and on-line resources available. Your first stop for help should be the VMware vSphere PowerCLI Community. I also recommend you keep Alan Renouf’s PowerCLI reference card close-to-hand when you’re just starting out.