Advanced

PowerCLI Best Practice: Correct Use of Strong Typing

All software is changed over time to allow for improvements, this ensures it is providing the best experience for the user and evolving into a better product. PowerCLI is no exception! Yet, as you know PowerCLI is not the typical GUI application where we can move a text box or change the color of a button. Once written, scripts require that every piece of PowerCLI they use retains that same functionality in future versions, this is something we take seriously at VMware as we don’t want to break existing scripts that have been written but clearly do want to move the product forward.

In order to do this we need to provide you, the users of PowerCLI with a compatibility contract. A contract which states which elements are guaranteed to stay the same, and which elements may change. Scripts are supposed to rely on the areas which stay the same and steer clear of the areas we may change to provide a better user experience.

As a general rule of thumb, PowerShell-style use of PowerCLI is safe. This includes cmdlets and their parameters and retrieving the values of properties in objects returned by cmdlets. What is not safe is the .Net programming-style use of PowerCLI, for example relying on the specific types of objects, whilst looking at scripts in the community and talking to customers we have seen a trend which may cause issues when followed.  We want the best for our customers and to keep you informed on what we consider a best practice when using types and therefore we would like to explain a little more about this, we want to ensure this is being used in the correct way and that your scripts are written to always be safe with the changes we make.

I’ll focus on one particular aspect of compatibility which was affected by changes in Get-VM in the recently released PowerCLI 6.3. Script authors often explicitly specify the types of parameters in a function. This adds an extra layer of reliability, especially in highly reusable functions:

function MyFunction([Full.Type.Name.Goes.Here] $myObject)

Or, sometimes types are used to check an input and take different action depending on the type of an object:

if ($myObject -is [Full.Type.Name.Goes.Here]) { … }

But how do you get the correct type name to use here? Use $myObject.GetType() or Get-Member, right? These methods indeed return the actual implementation type of the object. For a VM, the result is “VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl”.

Unfortunately, PowerCLI cannot guarantee that the implementation type won’t change in the future. There are scripts that we have seen that rely on implementation types (see that “impl” in the name?) and these scripts occasionally break when bigger changes need to be made in PowerCLI, this clearly can cause issues, issues we would prefer you didn’t get and therefore we would like to give you a best practice on what we think the safest way to do this actually is, so if you are using types in your scripts you can continue to do this and ensure any future changes we make will not impact you.

The approach we would suggest is to use what the PowerCLI team calls the “.Types” interface. “.Types” is a set of types which is guaranteed to maintain compatibility with scripts, across different PowerCLI versions. The “.Types” type for e.g. a VM is “VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine”.  Note how the “.Impl” part of the name is now replaced by “.Types”.

This brings us to the question, how do you get the correct “.Types” type for a given object?  

Basically, any type in the “Types” namespace, implemented by your object is ok to use. But usually the closest match is a type which has the same name as the implementation type but without the “Impl” suffix. So usually the following will get you the type name:

$myType = $myObject.GetType()

$compatibleTypeName = $myType.Name.Replace(“Impl”, “”)

 

$myType.GetInterfaces()

    | where { $_.FullName -like "*.Types.*" -and $_.Name -eq $compatibleTypeName }

    | select FullName

 

If it doesn’t find the type you are looking for, you can still examine the full list of supported “.Types” types and pick the one you like best:

 

$myObject.GetType().GetInterfaces()

    | where { $_.FullName -like "*.Types.*" }

    | select FullName

Here’s what the previous examples look like once the implementation types are replaced by the correct compatible types:

INCOMPATIBLE:

function MyFunction([VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl] $myObject)

if ($myObject -is [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl]) { … }

 

 

COMPATIBLE:

function MyFunction([VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine] $myObject)

if ($myObject -is [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]) { … }

All of the above can come in handy to you particularly if you have scripts which use the “VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl” type. In PowerCLI 6.3, Get-VM cmdlet performance was optimized and, as a result, the type of objects returned by the cmdlet needed to change to “VMware.VimAutomation.ViCore.Impl.V1.VM.UniversalVirtualMachineImpl”. The change affects cases where the call to Get-VM does not specify filtering by the parent object, such as VMHost. With PowerCLI 6.3, calls such as plain Get-VM or Get-VM –Name ‘infra*’ return objects of the new UniversalVirtualMachineImpl type.

To detect problematic scripts which may be affected by future PowerCLI changes, you can search for the “VMware.VimAutomation.*.Impl.*” string. 

To detect scripts which are likely to be affected specifically by the recent Get-VM change, search for the “VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl” string and use “VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine” instead.