Basic PowerCLI Scripting for VMware vSphere
The VMware vCenter HTML5 GUI is the primary management interface for directly managing ESXi hosts and VMs. While it is very feature-rich and well-designed, a variety of administrative tasks are much better served by a command-line scripting interface. You'll be amazed at the amount of things you can accomplish quickly and easily using PowerCLI. Let's take a look at what it can do for you.
What is PowerShell?
For those who may not be familiar with Microsoft PowerShell, in brief, it is a scripting language from Microsoft that was first released in 2006 and has grown in popularity since then. Historically in computing, a non-graphical software program that lets end users interact with the operating system has been referred to as a "shell". PowerShell can be used interactively, or scripts can be written and executed directly or by a scheduling mechanism. It has many built-in capabilities for some things, like administering computers and running a version of the Windows operating system, but to work with things like VMware, extensions or "modules" are needed.
PowerShell has been a free product since its release. It is worth noting here that in 2016, PowerShell code was released as "open source", and has hence been ported to other operating systems such as Linux or MacOS. This gives the administrator even more options.
Items that can be executed in PowerShell are referred to as "cmdlets" (short for "commandlets", either built-in or provided by modules), functions, and scripts. At first, PowerShell might appear to be just another text-based command line shell, but it is built on the Microsoft .NET Common Language Runtime (CLR), and all inputs and outputs are .NET objects. You will soon see how this makes PowerShell, and hence, PowerCLI, very powerful.
What is PowerCLI?
VMware PowerCLI is a free module for Microsoft PowerShell. It provides a powerful method to examine, and in many cases, make changes to your vSphere environment by typing commands in a PowerShell session or executing a saved script. "VMware vSphere PowerCLI 5.5 Release 1" was released 19 September 2013 and has been maintained and enhanced since then.
PowerCLI uses the vSphere Application Programming Interface (API) to "talk to" one or more vCenters and either ask for information, or request actions such as configuration changes.
Where Can You Get PowerCLI?
PowerCLI requires a compatible version of PowerShell to already be installed. PowerShell is typically installed with Windows, but you may need to install or upgrade the version.
You can download an installer for the desired version of PowerCLI here.
Alternatively, you can install PowerCLI by running the following command directly in a PowerShell session:
[…]
Cmdlet Get-Datacenter 12.3.0.17… VMware.VimAutomation.Core
Cmdlet Get-Datastore 12.3.0.17… VMware.VimAutomation.Core
Cmdlet Get-VM 12.3.0.17… VMware.VimAutomation.Core
[…]
Cmdlet Get-VMGuest 12.3.0.17… VMware.VimAutomation.Core
Cmdlet Get-VMGuestDisk 12.3.0.17… VMware.VimAutomation.Core
Cmdlet Get-VMHost 12.3.0.17… VMware.VimAutomation.Core
[…]
PowerCLI cmdlets that start with "Get-" are designed to retrieve information that can then be either viewed or manipulated for some purpose.
VMware Command Documentation
VMware provides ample documentation for the available PowerCLI cmdlets here. Most cmdlets have some command line options and a specific syntax that must be followed. Please refer to the VMware documentation for specifics. Alternatively, you can type "help [cmdlet name] to see usage information that may be available.
What Can PowerCLI Reveal About VMs and ESXi Hosts?
This is most likely the first question new PowerCLI users have. That is right, because most administrators frequently look at that in the vSphere GUI. So, if you are connected to a vCenter, in this example, which has three ESXi hosts and two VMs, simply executing the cmdlets "get-vm" and "get-vmhost" will give you some basic information about your VMs and ESXi hosts.
(Note: some of the lines in the example output have been truncated because the default formatting is very wide. PowerShell has options to improve display formatting; one or more examples will follow later in the article.)
PS C:\> get-vm
Name PowerState Num CPUs MemoryGB
—— ————— ———— ————
Photon-Test PoweredOn 1 2.000
Test_Ubuntu_Server PoweredOn 6 8.000
PS C:\> get-vmhost
Name ConnectionState PowerState NumCpu CpuUsageMhz CpuTotalMhz …
—— ———————- ————— ——— —————- —————- …
ESXi7_1 Connected PoweredOn 16 53 41584 …
ESXi7_2 Connected PoweredOn 16 66 41584 …
ESXi7_3 Connected PoweredOn 16 60 41584 …
Isn't There More Than That?
Yes, there is. Remember it was previously mentioned that "all inputs and outputs are .NET objects"? This fact opens up a world of powerful features.
First, let's look at the information available for a single VM. What was displayed above for each VM is just the default basic information. To get an idea of what is "hidden" but accessible behind that, you can run the cmdlet "get-vm" with options to specify which single VM we want to examine.
Then adding the following vertical bar "pipeline" symbol ("|"), you can pass the results of the first cmdlet to another one. In this case we will use the PowerShell "get-member" cmdlet (or "gm" for short – there are many aliases or abbreviations available in PowerShell/PowerCLI, but some may be ambiguous). What "get-member" does is to enumerate the Properties and Methods available for the object being passed to it.
PS C:\> get-vm -name Test* | gm
Name MemberType Definition
—— ————— —————
ConvertToVersion Method T VersionedObjectInterop.Conve…
Equals Method bool Equals(System.Object obj)
GetClient Method VMware.VimAutomation.ViCore.In…
GetConnectionParameters Method VMware.VimAutomation.ViCore.In…
GetHashCode Method int GetHashCode()
GetType Method type GetType()
IsConvertableTo Method bool VersionedObjectInterop.Is…
LockUpdates Method void ExtensionData.LockUpdates…
ObtainExportLease Method VMware.Vim.ManagedObjectRefere…
ToString Method string ToString()
UnlockUpdates Method void ExtensionData.UnlockUpdat…
BootDelayMillisecond Property long BootDelayMillisecond {get…
CoresPerSocket Property int CoresPerSocket {get;}
CreateDate Property System.Nullable[datetime] Crea…
CustomFields Property System.Collections.Generic.IDi…
DatastoreIdList Property string[] DatastoreIdList {get;}
DrsAutomationLevel Property System.Nullable[VMware.VimAuto…
ExtensionData Property System.Object ExtensionData {g…
Folder Property VMware.VimAutomation.ViCore.Ty…
FolderId Property string FolderId {get;}
Guest Property VMware.VimAutomation.ViCore.Ty…
GuestId Property string GuestId {get;}
HAIsolationResponse Property System.Nullable[VMware.VimAuto…
HardwareVersion Property string HardwareVersion {get;}
HARestartPriority Property System.Nullable[VMware.VimAuto…
Id Property string Id {get;}
MemoryGB Property decimal MemoryGB {get;}
MemoryMB Property decimal MemoryMB {get;}
Name Property string Name {get;}
Notes Property string Notes {get;}
NumCpu Property int NumCpu {get;}
PersistentId Property string PersistentId {get;}
PowerState Property VMware.VimAutomation.ViCore.Ty…
ProvisionedSpaceGB Property decimal ProvisionedSpaceGB {ge…
ResourcePool Property VMware.VimAutomation.ViCore.Ty…
ResourcePoolId Property string ResourcePoolId {get;}
SEVEnabled Property System.Nullable[bool] SEVEnabl…
Uid Property string Uid {get;}
UsedSpaceGB Property decimal UsedSpaceGB {get;}
VApp Property VMware.VimAutomation.ViCore.Ty…
Version Property VMware.VimAutomation.ViCore.Ty…
VMHost Property VMware.VimAutomation.ViCore.Ty…
VMHostId Property string VMHostId {get;}
VMResourceConfiguration Property VMware.VimAutomation.ViCore.Ty…
VMSwapfilePolicy Property System.Nullable[VMware.VimAuto…
Each of the Properties listed may contain information relevant to that object, which, in this case, is a VM. So for example, if we want to just display the VM name, its PowerState, and which ESXi host it is running on, we can use the "Select-Object" cmdlet and list the Properties we wish to see:
PS C:\> Get-VM | Select-Object Name, PowerState, VMHost
Name PowerState VMHost
—— ————— ———
Photon-Test PoweredOn lzm32
Test_Ubuntu_Server PoweredOn lzm31
Exporting Output to .CSV File
A very useful feature of PowerShell that is also frequently used with PowerCLI is the ability to export the output to a Comma-Delimited ".CSV" file (the default delimiter is a comma; other delimiting characters can be specified if desired). The resulting .CSV file can be imported directly into Microsoft Excel, then filtered and manipulated using all the Excel spreadsheet features available.
This is accomplished using another "pipeline" and the PowerShell cmdlet "Export-CSV". Using our previous example of two VMs:
PS C:\> Get-VM | Select-Object Name, PowerState, VMHost | Export-CSV -Path C:\TEMP\MyVMs.CSV -NoTypeInformation
PS C:\> Get-Content -Path C:\TEMP\MyVMs.CSV
“Name”,”PowerState”,”VMHost”
“Photon-Test”,”PoweredOn”,”lzm32″
“Test_Ubuntu_Server”,”PoweredOn”,”lzm31″
This feature is quite handy when there is a need to save information for future reference or filter large amounts of data. Because this is a PowerShell feature and not specific to PowerCLI, the reader is advised to pursue PowerShell training to enhance your knowledge in this area.
Variables: A Convenient Way to Reference Objects
Variables are another PowerShell functionality that can make PowerCLI even more powerful. Refer to PowerShell Foundations training for specifics on how to use variables. In brief, an object or group of objects can be stored in a variable for further use without re-running a cmdlet and can be manipulated in some very interesting ways.
For example, if you store the output of the cmdlet "get-vm" in the variable "$MyVMs", you can reference the individual properties of the VMs by simply adding ".[PropertyName]". In this example, we are only asking to see the values in the "Name" property field for all objects stored in the variable "$MyVMs", which is first populated with the output of the cmdlet "Get-VM":
PS C:\> $MyVMs = Get-VM
PS G:\Documents\scripts> $MyVMs.name
Photon-Test
Test_Ubuntu_Server
Saved Scripts
If there are sets of cmdlets and data manipulations that you find the need to use frequently, you can avoid retyping the commands and just execute your saved script. For example, a quick script to display all the running VMs in your vCenter could be this simple:
(Displaying the contents of a script you've already saved):
PS C:\> type C:\temp\RunningVMs.PS1
# RunningVMs.PS1 – display all running VMs in vCenter
# D.Mundhenk, 2021
$cred = Get-Credential
Connect-VIServer -server 192.168.1.111 -Credential $cred
Get-VM | where -Property PowerState -EQ “PoweredOn” | Format-Table
Executing the script gives you the following output:
PS C:\> C:\temp\RunningVMs.PS1
PowerShell credential request
Enter your credentials.
User: administrator@vsphere.local
Password for user administrator@vsphere.local: ************
Name PowerState Num CPUs MemoryGB
—— ————— ———— ————
Photon-Test PoweredOn 1 2.000
Test_Ubuntu_Server PoweredOn 6 8.000
Some more useful features of saved scripts are:
You don't have to try to remember the cmdlet names.
You can easily execute multiple cmdlets or functions on an object or group of objects by running a single script.
Scripts accept command line options, which makes them more versatile.
You can share them with co-workers or an online community.
What Else Can You Do With PowerCLI?
The short answer to this question is that you can do almost everything in the vSphere GUI, and there are probably some things that you can't do there. So far, everything we've examined in this article has been "non-intrusive", i.e. just displaying information, not changing anything. You can change things, but you need to exercise some caution because scripting in a production environment can sometimes lead to unexpected and undesirable results.
For example, you can shut down a running VM using the cmdlet "Shutdown-VMGuest." If you specify the exact VM name (assuming you are only connected to one vCenter or are certain there are no VMs in other vCenters with the same name), you will have the desired result of the correct VM shutting down. As you may have guessed from the hints above, even specifying an exact name can get you in trouble if you're not careful.
Taking it to another level, if you execute "Shutdown-VMGuest" using one or more wildcards in the name of the VM, you may be shutting down others without realizing it until it's too late.
Fortunately, to help make sure your commands will be applied to the correct objects, PowerShell has a built-in "What if?" feature. Adding the parameter "-WhatIf" at the end of your command line will display what would be executed if the "-WhatIf" were not present.
PS C:\> Shutdown-VMguest -VM *Test* -whatif
What if: Performing operation “Shutdown VM guest.” on VM “Photon-Test”.
What if: Performing operation “Shutdown VM guest.” on VM “Test_Ubuntu_Server”.
That command would have shut down both VMs, which may not be what you want to do.
Here, specifying the exact name of the Ubuntu VM will shut that one down, but not the Photon VM:
PS C:\> Shutdown-VMguest -VM Test_Ubuntu_Server
Perform operation?
Performing operation “Shutdown VM guest.” on VM
“Test_Ubuntu_Server”.
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend
[?] Help(default is “Y”): Y
State IPAddress OSFullName
——- ————- —————
Running {192.168.1.222, fe… Ubuntu Linux (64-bit)
PS C:\> Get-VM
Name PowerState Num CPUs MemoryGB
—— ————— ———— ————
Photon-Test PoweredOn 1 2.000
Test_Ubuntu_Server PoweredOff 6 8.000
As you can see, the Ubuntu VM is now in the "PoweredOff" state, as expected.
Why Not Just Point and Click in the GUI?
If you're having trouble imagining a scenario where using PowerCLI would be more efficient than just signing into the vSphere GUI and following the usual point-and-click routine, here is one to think about:
Let's say you are the vCenter Administrator for a software development group, managing a vCenter and 90 VMs used for testing software. However, the ESXi hosts in this vCenter can only support a maximum of 35 VMs running simultaneously at any given time. The group has three different applications (let's call them "App A", "App B", and "App C"), and they release patches and new versions on a somewhat regular schedule. Your job is to ensure the test VMs (30 per Application) are ready for them to use very quickly when a patch or release is ready for testing.
Monday morning, your manager tells you that there is a patch for App C for a critical security vulnerability that must be tested. Any and all App A and App B VMs need to be shut down (if running), and all 30 App C VMs powered on for testing, as quickly as possible.
Using the GUI method, you would likely need to open the menu and click on "Shut Down Guest OS" on all the App A & App B VMs one at a time, then power on the App C VMs. You could click on the Cluster or ESXi host and under "VMs", select multiple VMs while holding down the CTRL key, but that is still one click per VM before initiating the shutdown.
With PowerCLI, you could have one script, let's call it "TestingAppC.PS1", that shuts down any App A or App B VMs that are running, and powers on all the App C VMs. To take it even a step further, the script could just be "TestingApp.PS1", and would accept the letter of the App to be tested as a command line option, e.g. "PS C:\> TestingApp.PS1 C"
A Complex Example
This article's author has managed a fairly large VMware environment for several years, with at least eight vCenters and around 250 ESXi hosts. Just keeping track of the ESXi hosts has been a challenge; frequent changes occur as workloads move around and hardware ages and is replaced. Having a reliable inventory of all these hosts has been a key factor in making good (and quick) decisions regarding the hosts.
I began with a fairly simple script that created a list of ESXi hosts with a selected set of properties, such as Name, vCenter, Cluster Name, Amount of Memory, etc., for each host and exported the information to a CSV file. Since most of the ESXi hosts are Cisco UCS Blade Servers and Cisco also has a free PowerShell module called the "Cisco UCS PowerTool Suite," I decided to integrate this module with the use of PowerCLI in my script.
Adding the Cisco PowerTool Suite capability enabled me to cross-reference the ESXi hosts from PowerCLI/vCenter with the actual blade hardware they are running on, and collect information such as blade Serial Number, Chassis/Slot location, and Firmware Version. [Note: Using standard naming conventions for ESXi hostnames and UCS Blade Profile names was one key to making the cross-reference possible and simple].
The script also contains commands to see if the ESXi host responds to a "ping" command, as well as logic to compare the hostname and other information with what is recorded in a Configuration Management Database (CMDB) for that serial number. The script has evolved over several years, and there is still room for improvement. However, it has saved countless hours of collecting and filtering information. I would also like to mention that personally, having a background in programming languages such as FORTRAN, C, Pascal, JavaScript, Bourne and Korn Shells, PowerShell, and hence PowerCLI, have been relatively easy to learn and elegant to work with.
Final Thoughts
VMware PowerCLI is a very powerful and time-saving tool for anyone working with VMware vSphere. For those who are already familiar with Microsoft PowerShell, the installation and use of PowerCLI should be quite smooth. It is highly recommended for those who are not yet familiar with PowerShell.
delivered to your inbox.
By submitting this form you agree to receive marketing emails from CBT Nuggets and that you have read, understood and are able to consent to our privacy policy.