Basic PowerCLI Scripting for VMware vSphere
| CBT Nuggets - David Mundhenk

Basic PowerCLI Scripting for VMware vSphere

The VMware vCenter HTML5 GUI is the primary management interface for managing ESXi hosts and VMs directly. While it is very feature-rich and well designed, there are a variety of administrative tasks that 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 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 functions by using 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… VMware.VimAutomation.Core
Cmdlet Get-Datastore… VMware.VimAutomation.Core
Cmdlet Get-VM… VMware.VimAutomation.Core
Cmdlet Get-VMGuest… VMware.VimAutomation.Core
Cmdlet Get-VMGuestDisk… VMware.VimAutomation.Core
Cmdlet Get-VMHost… 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.

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. Rightly so, because that is what most administrators are looking at frequently 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 "and 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, in this case 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

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 functionality of PowerShell that can be used to 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> $

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 -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, almost everything you can do in the vSphere GUI, and 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. However, you can change things, but you need to exercise some caution because scripting in a Production Environment can sometimes lead to unexpected and undesired 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 that 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
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend
[?] Help(default is “Y”): Y
State   IPAddress   OSFullName
——-   ————-   —————
Running  {, 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 3 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 make sure 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

The author of this article has been involved in managing 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; there are frequent changes taking place 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 the use of 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, and 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 the span of 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 with 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 who is working with VMware vSphere. For those who are already familiar with Microsoft PowerShell, the installation and use of PowerCLI should be quite smooth and seamless. For those who are not yet familiar with PowerShell, it is highly recommended.



Ultimate Systems Administration Cert Guide

A 158-page guide to every Microsoft, VMware, Citrix, AWS, Google, and Linux certification, and how they fit into your career.

By submitting this form you agree that you have read, understood, and are able to consent to our privacy policy.

Get CBT Nuggets IT training news and resources

I have read and understood the privacy policy and am able to consent to it.

© 2022 CBT Nuggets. All rights reserved.Terms | Privacy Policy | Accessibility | Sitemap | 2850 Crescent Avenue, Eugene, OR 97408 | 541-284-5522