Tag Archives: vSphere

Refactoring PowerCLI scripts or functions for PowerActions

If Carlsberg is “probably the best beer in the world“, then PowerActions is more than probably the best VMware fling in the world.

It brings PowerCLI automation goodness directly within the vSphere Web Client in 2 ways : a PowerShell/PowerCLI console and the ability the extend the Web Client context menu actions with your custom actions based on your PowerCLI scripts.

This article is not intended as a general how-to guide for PowerActions, everything you need is here : presentation, video tutorial, documentation and installer download links.

In this article, we are going to focus on how to modify existing scripts or functions to add them as context menu actions in the Web Client.

Refactoring a script

Let’s say we have a basic PowerCLI script (a .ps1 file) to list all the VIBs installed on a ESXi host, its content looks like this :


$EsxCli = Get-EsxCli -VMHost $VMhost
$EsxCli.software.vib.list() | Select-Object -Property Name,CreationDate,InstallDate,Version

We want the same functionality when we right-click on a ESXi host in the Web Client and we want to play with it like it’s a just-unboxed toy from the Christmas tree. So, let’s get to it.

From the Web Client home page, we click “PowerCLI Scripts” and we see this :

PowerCLI Scripts

We click on the icon with a green “+” to add a new script to the PowerActions script library. Then, we need to specify the type of object(s) that our custom action can target. This is very important because this defines the type of PowerCLI object that the script takes as input parameter. Our script targets ESXi hosts so we choose “Host”.

To make our custom action even more powerful, we can potentially act on multiple objects (of the same type) at once. In this case, we would check the box “Expects multiple objects”. As we can see above, our original script expect only one VMHost object so we don’t need to do this.

Argument type
In the next screen, we give our script a name and a optional description. More importantly, we choose an “Output format” : “Action” or “Report”. Essentially, we choose “Action” for scripts performing an action on (or modifying) one or more vSphere object(s) and we choose “Report” for scripts obtaining information (similar to a Get-* cmdlet). In our case, it obtains a list of VIBs, so we choose “Report”.

What we are presented with in the next screen is the basic structure of the script which will be used by PowerActions :

Add script

The most important point here is that the vSphere object on which we right-click in the Web Client will be used as the input parameter called vParam. In other words, the target of the context menu action will be stored as the variable $vParam in the script. Don’t try to change the parameter name, it has be $vParam to work with PowerActions.

You might be under the impression that we are limited to a single parameter, but it is not the case. Let’s add -Vendor as a mandatory parameter to filter the VIBs on their vendor. We will see later, when we run the custom action in the Web Client that we are prompted to enter a value for this parameter.

Here is our final PowerActions script :



$EsxCli = Get-EsxCli -VMHost $vParam
$VibList = $EsxCli.software.vib.list()
$FilteredVibList = $VibList | Where-Object { $_.Vendor -eq $Vendor }
$FilteredVibList | Select-Object -Property Name,CreationDate,InstallDate,Version

Now, let’s run it !
To do that, we right-click on a ESXi host in the Web Client, at the bottom of the context menu, we choose “PowerCLI”, and then “Execute Script” :

Execute Script
In the next screen we select our new script and OK. Now, we are prompted to enter values for any mandatory parameter (other than vParam) :

Vendor Parameter

The Web Client displays the result in a nice table :

Report Result

Refactoring a function

Now, let’s say we are good PowerShell citizens and we encapsulate our PowerCLI tools as advanced functions to facilitate reusability. How can we reuse our existing PowerCLI functions with PowerActions ?
It is very straightforward.

As an example, we are going to use the function Audit-vCenterOperation, available here. The idea is to be able to right-click a vSphere object in the Web Client to get a list of events and operations related the selected object. This could be a workaround for the “Export Events” feature not working well in the Web Client (http://kb.vmware.com/kb/2071612).

Looking at the param(...) block, we see that it has many parameters :

    [string]$VIServer = "localhost",
    [Parameter(ValueFromPipeline = $True,Position=0)]
    [ValidateScript({ $($_[0].GetType()).Namespace -eq "VMware.VimAutomation.ViCore.Impl.V1.Inventory" })]

Fortunately, none of these parameters is mandatory so we can leave them as they are.

Looking at the line just above “$Entity,“, we see that the parameter Entity is designed to work with any type of vCenter inventory object. A given PowerActions script can take only one object type as input parameter, so we’ll need to choose what kind of vSphere object we want to target with our custom action. Let’s go for VMs.

So, we add a new script in PowerActions and this time, we choose “Virtual Machine” as the target type. For the output format, we select “Report” because the script is getting information, not modifying anything.

Again, in the next screen, we are presented with a blank script structure.
At the end of it, we add the whole function definition, unchanged. By itself, this whole function {...} block does nothing, it merely defines the function. So, to make our script actually run the code encapsulated in our function, we need to call the function.

Remember, the VM we right-click in the Web Client will be stored by PowerActions in the variable $vParam. So, all we have to do is to feed $vParam as the value for the -Entity parameter of our function :



function Audit-vCenterOperation {

    # Content of the existing function

Audit-vCenterOperation -Entity $vParam

That’s it.
Now, we can run the custom action in the Web Client.
Aha, we see that our friend “RogueAdmin” has reconfigured the VM named “New-VM”.

Audit result
By the way, when we have this “Report Results” page, we can resize, reorder and sort the columns to our heart’s content.

Checking vCenter Server certificate requirements with PowerShell

Given the number and the complexity of certificate-related issues, I wanted an automated way to check whether a certificate file meets the vCenter Server certificate requirements.

There are 2 ways to extract the necessary information from a certificate file : openssl.exe and the cmdlet Get-PfxCertificate, which was introduced with PowerShell 3.0.

Here is the openSSL command and its output :

OpenSSL command
Here is the Get-PfxCertificate command and its output :


I wrote a PowerShell function named Test-VpxdCertificate, which checks if a certificate file (.crt or .cer) meets all the requirements. I chose to build this tool upon the Get-PfxCertificate cmdlet for 2 main reasons :

  • openssl.exe returns plain text and you know what I think about text-parsing in PowerShell.

  • You don’t really need to have PowerShell 3.0 on the vCenter Server itself.
    You can copy the certificate file to another machine (which has PowerShell 3.0 or later) and run the cmdlet from there.
    Given the huge boost in functionality in 3.0 compared with 2.0 and the fact that 3.0 can be installed on down-level OSes, if you still don’t have any machine with 3.0 or later, you probably don’t need, or want, or deserve PowerShell automation.

What does it check ?

The vCenter Server certificate requirements are not clearly and exhaustively documented. There is something in the vSphere 5.0 documentation, but this is old and not exhaustive.
Fortunately, we can deduce most of the requirements from the KB article explaining how to create certificate requests for custom certificates.

So here are the certificate requirements for vCenter Server 5.x :

  • Certificate must be X.509 v3.
  • Certificate should begin with : “—–BEGIN CERTIFICATE—–“.
  • Certificate should end with : “—–END CERTIFICATE—–“.
  • The subject Alternative Name must contain the FQDN of the vCenter server.
  • The certificate must be valid : the current date must be between the “Valid from” date and the “Valid to” date.
  • The Key usage must contain the following usages : Digital Signature, Key Encipherment, Data Encipherment
  • The Enhanced key usage must contain : “Server Authentication” and “Client Authentication”.
  • The public key algorithm must be : RSA (2048 Bits).
  • The certificate must NOT be a wildcard certificate.
  • The signature hash algorithm must be SHA256, SHA384, or SHA512.

And here are the requirements for vCenter Server 6.0 :

  • Certificate must be X.509 v3.
  • Certificate should begin with : “—–BEGIN CERTIFICATE—–“.
  • Certificate should end with : “—–END CERTIFICATE—–“.
  • The subject Alternative Name must contain the FQDN of the vCenter server.
  • The certificate must be valid : the current date must be between the “Valid from” date and the “Valid to” date.
  • The Key usage must contain the following usages : Digital Signature, Key Encipherment.
  • The public key algorithm must be : RSA (2048 Bits).
  • The certificate must NOT be a wildcard certificate.
  • The signature hash algorithm must be SHA256, SHA384, or SHA512.

How to use it :

Here, we specified the certificate file path and the vCenter FQDN because this was not run from the vCenter Server itself.
If we run this command from the vCenter Server and if it is able to resolve its own FQDN, then there is no need to use the -vCenterFQDN parameter.
If we run this command from the vCenter Server and if the certificate is at its default location, then there is no need to use the -CertFilePath parameter.

The function performs a test for each of the requirements listed above and outputs an object with a property corresponding to each of these tests. The value of each property is either True or False. True means that the certificate passed the corresponding test and False means that it failed the test.

As we have seen above, the vCenter Server certificate requirements are different between vCenter 5.x and 6.0.
So, the -VpxdVersion parameter is used to specify the version of vCenter Server and the value of this parameter determines which tests are performed.
If the function is run from the vCenter Server itself, it will detect the vCenter version by itself and use this value, unless it is specified via the -VpxdVersion parameter.

By the way, the parameters -CertFilePath, -vCenterServerFQDN and -VpxdVersion are positional, so we can save some typing, like so :

PS C:\> Test-VpxdCertificate "$env:USERPROFILE\Desktop\rui.crt" "VC1.vcloud.local" "5.x"

Certificate ends with "-----END CERTIFICATE-----"             : True
Signature hash algorithm is SHA256 or higher                  : True
Certificate is NOT a wildcard certificate                     : True
Current date is between the "Valid from" and "Valid to" dates : True
Certificate has the required key usages                       : True
Certificate begins with "-----BEGIN CERTIFICATE-----"         : True
Certificate has the required enhanced key usages              : False
Subject alternative names contain the vCenter FQDN            : True
Public key algorithm is RSA 2048 or higher                    : True
Certificate is X.509 v3                                       : True

Here, we see that the vCenter certificate doesn’t meet the requirement regarding the enhanced key usages. To have better insight into why a certificate failed a test, we can use the -Verbose parameter. This allows us to see the certificate properties which are checked and their values :

Now, we can see why it failed the test for enhanced key usage : it is missing the “Client Authentication” enhanced key usage.

But there is no requirement for enhanced key usage in vCenter 6.0, so this certificate passes all the checks for 6.0 :

On the other side of the verbosity spectrum, we can just output a boolean value : True or False using the -Quiet parameter. True means that the specified certificate meets all the requirements, False means that it doesn’t meet all the requirements :

This behaviour is conform to the -Quiet parameter of Test-Connection and other Test-* cmdlets. This is useful mostly when we call the cmdlet from another automation tool and we do something, depending on the result (True or False).

As usual, I packaged the function in a nice little module, which is available here.

Auditing events and changes in a vCenter environment

When we get a customer opening a support case telling : “… was working before and now it is not working anymore”.

The first question which pops up is :

“What changed ? What happened before it stopped working ?”

Quite often, the customer is not sure. Or, some customers have a selective memory and tend to “forget” configuration changes for various reasons.

Also, there are cases where we know something happened but we want to know if it was a user-initiated action. Or, the customer might even want us to retrieve by who a specific action was initiated (probably to engage in some finger-pointing/blame-assigning fun).

The vSphere client being limited to display a maximum of 1000 events, this corresponds generally to only a few days worth of events. Besides, the “Export Events” functionality of the C# client and the Web client doesn’t work well (http://kb.vmware.com/kb/2071612).
As a result, we cannot rely on the vSphere client/web client for auditing purposes.

You might think : “all this information is in the tables VPX_EVENT and VPX_EVENT_ARG in the vCenter database, I can just query it”. I would answer with 3 points :

  • This data is not user-friendly and requires further processing to become consumable information
  • A kitten dies every time you query the VCDB
  • If you want to keep 2, 3, or 5 years of events for compliance purposes, the vCenter database is a typical OLTP system and should be used as such , not as a Data Warehouse !

To make querying this kind of information easier, I wrote a function Audit-vCenterOperation .

This is essentially a wrapper around the PowerCLI cmdlet Get-VIEvent with a bit of intelligence to filter out irrelevant events and 2 additional parameters : one to select actions initiated by a specific user and one to select actions of a specific type.

Let’s see the stuff we can do with it.

To track when the configuration of the cluster “Test Cluster” was changed and by who :

vCenterOperation Cluster Reconfigure
Notice that here, we sent the cluster object from the pipeline. In fact, we can throw any vCenter inventory object at it, through the pipeline, and the object will be bound to the -Entity parameter of the function.

The parameter -OperationType allows to filter the operations down to a specific type or topic.
The possible values are : Create, Reconfigure, Remove, DRS, HA, Password, Migration, Snapshot, Power, Alarm, Datastore, Permission.
Don’t worry, we don’t have to know all the possible values, we can just make use of tab completion.

To track all the migrations (vMotion and Storage vMotion) for all VMs over the last 6 hours :

C:\> Audit-vCenterOperation -OperationType Migration -Start (Get-Date).AddHours(-6)

Key               : 10624
CreatedTime       : 11/25/2015 9:57:58 AM
UserName          : User
Datacenter        : Test-DC
ComputeResource   : Test Cluster
Host              :
Vm                : Test-VM
Message           : Migration of virtual machine Test-VM from, iscsi-lefthand-1 to, iscsi-lefthand-1 completed
NewConfigSettings :

Key               : 10632
CreatedTime       : 11/25/2015 10:01:16 AM
UserName          : VSPHERE.LOCAL\Administrator
Datacenter        : Test-DC
ComputeResource   : Test Cluster
Host              :
Vm                : New-VM
Message           : Task: Migrate virtual machine
NewConfigSettings :

Key               : 10633
CreatedTime       : 11/25/2015 10:01:17 AM
UserName          : VSPHERE.LOCAL\Administrator
Datacenter        : Test-DC
ComputeResource   : Test Cluster
Host              :
Vm                : New-VM
Message           : Migrating New-VM from, ISCSI-2 to, ISCSI-2 in
NewConfigSettings :

We can easily see the VM name, the source host/datastore and the destination host/datastore.

What is this empty property named NewConfigSettings ?
It is populated only for “reconfigure” operations on VMs. It contains the VM setting(s) which have been changed and their new value :

PowerCLI C:\> Get-VM "New-VM" | Audit-vCenterOperation -OperationType Reconfigure -Start (Get-Date).

Key               : 10376
CreatedTime       : 11/24/2015 7:59:08 AM
UserName          : VSPHERE.LOCAL\Administrator
Datacenter        : Test-DC
ComputeResource   : Test Cluster
Host              :
Vm                : New-VM
Message           : Reconfigured New-VM on in Test-DC
NewConfigSettings : @{ChangeVersion=2015-11-13T16:22:54.801558Z;
                    Files=VMware.Vim.VirtualMachineFileInfo; MemoryMB=3072; NumCPUs=2;

PowerCLI C:\> Get-VM "New-VM" | Audit-vCenterOperation -OperationType Reconfigure -Start (Get-Date).
AddDays(-7) | Select-Object -ExpandProperty NewConfigSettings | Format-List *

ChangeVersion : 2015-11-13T16:22:54.801558Z
Files         : VMware.Vim.VirtualMachineFileInfo
MemoryMB      : 3072
NumCPUs       : 2
VmProfile     : {VMware.Vim.VirtualMachineEmptyProfileSpec}

In this case, the number of vCPUs and the memory amount were changed. Unfortunately, there is no easy way to get the original values of the changed settings, so it gets only the new values.

If we have an ESXi host which have been rebooted and we want to know if it was a user-initiated action (and if yes, by who) :

vCenterOperation power
Aha ! It was the (suspiciously named) user “RogueAdmin”.

To track down snapshot operations which happened today on a VM named “New-VM”, here is how to do it :

vCenterOperation Snapshot
This “RogueAdmin” user is definitely doing weird things. Let’s track down everything he has done (output cut for brevity) :

PowerCLI C:\> Audit-vCenterOperation -Username "VCLOUD\RogueAdmin"

Key               : 13157
CreatedTime       : 11/26/2015 10:03:30 AM
UserName          : VCLOUD\RogueAdmin
Datacenter        :
ComputeResource   :
Host              :
Vm                :
Message           : User VCLOUD\RogueAdmin@ logged in as VMware vim-java 1.0
NewConfigSettings :

Key               : 13162
CreatedTime       : 11/26/2015 10:04:58 AM
UserName          : VCLOUD\RogueAdmin
Datacenter        : Test-DC
ComputeResource   : Test Cluster
Host              :
Vm                :
Message           : User logged event: Because I can
NewConfigSettings :

That’s it.

This Audit-vCenterOperation is in a module available here. It requires Powershell 3.0 or later and PowerCLI 5.5 or later.

Configure ESXi host RAMdisks with PowerCLI

The symptoms of a full RAMdisk on a ESXi host can be pretty nasty and diverse. The possible causes are also very diverse (search “ramdisk full” in the VMware Knowledge Base, you will see many articles). Also, it can be affecting the RAMdisk “root”, “tmp”, or even the RAMdisk “hostdstats”, depending on the cause, so this is not easy to troubleshoot.

To help prevent this type of issues, we can increase the size of ESXi RAMdisks by increasing their memory reservation, memory limit and set their reservation as “expandable”, just like in resource pools.

This corresponds to settings in “System Resource Allocation” :

System resources allocation

Let’s see how we can configure this in a more automated way, with PowerCLI.

PS C:\> $ESXiHosts = Get-VMHost
PS C:\> $Spec = New-Object VMware.Vim.HostSystemResourceInfo

Here, we save all our ESXi Hosts into a variable for later use, because we want to configure all the ESXi hosts in the vCenter. We also create a new, empty HostSystemResourceInfo object, which we are going to populate with the memory settings we want.

Now, the tricky part is to use the appropriate key, depending on the RAMdisk we want to configure. This can be one of 3 possible RAMdisks that we might want to configure, so this is a good candidate for a Switch statement :

PS C:\> $RamDisk = "tmp"

PS C:\> switch ($RamDisk) {
             'tmp' {$Spec.Key = "host/system/kernel/kmanaged/visorfs/tmp"}
             'root' {$Spec.Key = "host/system/kernel/kmanaged/visorfs/root"}
             'hostdstats' {$Spec.Key = "host/system/kernel/kmanaged/visorfs/hostdstats"}

As an example, we are going to configure the “tmp” RAMdisk.
Then, we create a new, empty ResourceConfigSpec object and store it into our Config property :

PS C:\> $Spec.Config = New-Object VMware.Vim.ResourceConfigSpec
PS C:\> $Spec.Config

Entity           :
ChangeVersion    :
LastModified     :
CpuAllocation    :
MemoryAllocation :
LinkedView       :
DynamicType      :
DynamicProperty  :

Even though, the CPU allocation is not applicable to a RAMdisk, we need to create one and assign it to the CpuAllocation property of our ResourceConfigSpec. Why ? Because the vSphere API won’t let us apply the ResourceConfigSpec to a host, if the CpuAllocation or the MemoryAllocation property is null.

PS C:\> $Spec.Config.cpuAllocation = New-Object VMware.Vim.ResourceAllocationInfo

Now, let’s set the memory reservation to 30 MB, the limit to 400 MB and the reservation as expandable. Expandable reservation means that more than the reservation can be allocated to the RAMdisk if there are available resources in the parent resource pool.

PS C:\> $Spec.Config.memoryAllocation = New-Object VMware.Vim.ResourceAllocationInfo
PS C:\> $Spec.Config.memoryAllocation.Reservation = 30
PS C:\> $Spec.Config.memoryAllocation.Limit = 400
PS C:\> $Spec.Config.memoryAllocation.ExpandableReservation = $True

Now, it’s time to apply the configuration to each individual ESXi host :

Foreach ($ESXiHost in $ESXiHosts) {
    $Spec.Config.ChangeVersion = $ESXiHost.ExtensionData.SystemResources.Config.ChangeVersion

What is this ChangeVersion business ?

We get the version identifier of the current ESXi host configuration and we make sure the ChangeVersion property in our ResourceConfigSpec matches with it. This is to prevent problems in case the ESXi host configuration was changed between the moment we last read it and the moment we apply a new ResourceConfigSpec to it. For more information, you can refer to this documentation page.

Lastly, we apply the resource allocation settings contained in our $Spec, using the method UpdateSystemResources of our HostSystem view (we used the ExtensionData property above, but it is the same as a view).

Putting it all together :

Using these techniques, I wrote a function called Set-VMHostRamDisk and packaged it in a module available here.

As you can see below, it is fully parameterized and accepts one or multiple ESXi hosts from the pipeline :


I took the time to write a proper comment-based help, so if you need more information on how to use the function, Get-Help is your BFF.

A PowerCLI alternative to the Storage Reports feature

As you may know, the Storage Views and Storage Reports features have been removed from vSphere 6. Here is the official (and laconic) statement from the vSphere 6.0 release notes :

“vSphere Web Client. The Storage Reports selection from an object’s Monitor tab is no longer available in the vSphere 6.0 Web Client.
vSphere Client. The Storage Views tab is no longer available in the vSphere 6.0 Client.

Quite a few customers were unhappy and asking what we were offering as a replacement/alternative.

To ease the pain of some customers, I wrote a PowerCLI alternative for the defunct Storage Reports feature. It is also a good way to showcase PowerCLI capabilities because it is a very typical usage of PowerCLI : extracting the information you need from different objects and grouping these pieces of information into custom objects.

The resulting PowerCLI module, Get-StorageViewsReport.psm1, made its way to a public knowledge base article with examples and screenshots of its usage. So, all you need to know to use this module is in the KB article and in the module Help accessible via Get-Help.

It obtains storage capacity and utilization information by datastore, by VM or by ESXi host. It provides the same information as the Storage Views reports.

It requires PowerCLI 5.5 or later and Powershell 3.0 or later.

You can download the module from the KB article but it is not up-to-date, so I would recommend to get it from GitHub to get the latest version. This version adds support for PowerCLI 6.0.