Chapter 18
The SDK

In this chapter, you will learn to:

  • Work with the vSphere SDK
  • Use the vSphere API Reference
  • Setting a Host in Maintenance Mode
  • Did the Alarm Fire the SNMP Trap?
  • Finding Metrics for Thin Provisioning
  • Can You Migrate This Guest?
  • Use Managed Objects
  • Managed Object Types
  • Data Objects and Their Methods
  • Using vSphere Managers
  • Managed Object References
  • Code Parameter Objects
  • Find the Method You Need
  • Changing the Boot Delay of a Virtual Machine
  • Finding the Patches Installed on an ESXi Host
  • Finding the Host HWuptime
  • Changing the vCenter Logging Options
  • Understand Return Values and Faults
  • Put Some Tips and Tricks to Good Use
  • Waiting for an Asynchronous Task
  • Better Error Handling after Asynchronous Tasks
  • Finding Service Managers with Get-View Shortcuts
  • Advanced Filters with Get-View

Although the PowerCLI product has grown over the various releases, there still will come a time when you won’t find a cmdlet to do the task you have in mind. That’s when you have to start looking at the vSphere APIs. These APIs give you full access to all the vSphere management components. Working with the vSphere APIs might appear to be an obscure black art, but rest assured, once you find your way around, you will find them easy to use.

Now, why would a book on PowerCLI bother with the vSphere API? The answer is simple. With the help of the vSphere API, your scripts can go that extra mile. The PowerCLI cmdlets cover a large part of the functionality that’s available in a vSphere environment, but not everything. There are, for example, some properties that you cannot retrieve or change through the PowerCLI cmdlets. And that’s where the vSphere API comes in. Luckily, the PowerCLI developers realized from day one that it would be difficult to offer a product that could only do part of the job. That is why they provided access to the vSphere API through specialized cmdlets called Get-View and Get-VIObject.

This chapter will show you how to use the vSphere API to perform functions that would otherwise not be available to you.

Work with the vSphere SDK

The full name of this beast is the vSphere Web Services SDK, but most of the time we will refer to it as the vSphere SDK or even just the SDK. While the SDK is a collection of documents, Web Service Definition Language (WSDL) files, Java libraries, and sample code, we will most of the time refer to one specific document, the vSphere API Reference. This reference document provides all the information concerning the data structures that are available through the vSphere API. This section provides a short summary of how the vSphere Web Services are implemented and how you can use them from within your PowerCLI scripts.

The vSphere API is exposed as a web service that runs on vSphere servers. These servers can be the vCenter Server or a VMware vSphere Hypervisor server (formerly known as an ESXi server). In other words, you use the same API for the vCenter Server as for the ESXi server. So far, so good—as a theory. As you might have guessed, this rule doesn’t hold true in some cases. For example, to download a screenshot of a guest’s console you need to connect directly to the vSphere Hypervisor server. And to retrieve tasks and events information, you have to connect to the vCenter Server.

Because the API is exposed as a web service, it is language independent from a client perspective. The requests and responses that your application sends and receives from the vSphere servers use the XML format. The protocol that is used to send and receive these requests and responses is the Simple Object Access Protocol (SOAP). The underlying network protocol used is HTTPS but can be configured as HTTP. The object model that is used contains the three major types of objects listed in Table 18-1.

Table 18-1: vSphere API object model

Object typeDescription
Managed objectsThese are server-side objects and represent a vSphere entity (host, guest, datastore, etc.) or a vSphere service (LicenseManager, PerformanceManager, etc.).
Data objectsThese contain information about the managed objects. They can contain:
Managed object properties (number of vCPUs in a guest, mount information about an NFS datastore, etc.).
Method parameters (for example, the HostVirtualNicSpec, which is a parameter object to the AddVirtualNic method).
Return values (for example, the GetAlarm method returns an array of Alarm object references).
Fault objectsThese are objects that are returned when a method could not be executed correctly. They contain information about the error that has occurred.

An important concept you should understand at this point is that you do not access these vSphere objects directly. The client, the PowerCLI session in our context, has a copy of these vSphere objects. These copies are called the .NET VIObjects, or .NET objects for short. These .NET objects are asynchronous copies of the vSphere objects. That means that when a property in one of the vSphere objects changes, that change will not appear automatically in the .NET object. It is up to the client to refresh its copy, the .NET object!

Use the vSphere API Reference

The vSphere API Reference can be quite intimidating at first view. But rest assured; it all clicks together nicely once you get the hang of it.

You access the vSphere API Reference with a web browser (Figure 18-1).

c18f001.eps

Figure 18-1: The vSphere API Reference layout

The layout of the vSphere API Reference has four distinct areas, as described in Table 18-2.

The Table of Contents (ToC) is logic itself if you understand the different object types that live in vSphere. (We described them in the section “Work with the vSphere SDK.”) The ToC includes a list of all the managed objects. As of this writing, there are more than 120 managed objects. Some of the entries in the ToC could in fact have been listed together. The enumerated types are just a special type of data object. An enumerated type is a data object with a specific set of predefined values. A good example is the DayOfWeek type, which, as you might have guessed, can only contain the names of the weekdays (Monday, Tuesday, and so on). There are more than 1,800 data objects and more than 290 enumeration types. You will also find a Fault Type entry in the ToC. Fault types are used to pass error information from the server to your application. There are more than 680 fault types.

Table 18-2: vSphere API Reference

AreaDescription
Table of ContentsLocated on the left-hand pane, the Table of Contents shows the topics that are available in the reference.
IndexThe Index provides an alphabetical list of all the elements available under a subject selected in the Table of Contents.
SearchThe Search field allows you to specify the full or partial name of the element you are looking for. The results of the search are displayed in a pop-up list below the Search field. When there is more than one hit, you will be able to select a specific element with the help of the cursor keys and the Enter key.
ContentThe Content for a specific element is shown in the right-side frame of the browser.

The following entries in the ToC are there to make your life as an API user a lot easier. Instead of wading through the vSphere objects, these entries (listed in Table 18-3) provide indexes to commonly used concepts in the vSphere objects.

Table 18-3: vSphere object concepts

Object conceptDescription
All TypesLists all known object types (managed objects, data objects, enumeration types, and fault objects). There are more than 2,990 entries here.
All MethodsLists all methods available in the API. There are currently more than 720 available methods for you to call.
All PropertiesLists all the properties and the object(s) where you can find the property. This is the longest list of them all, with more than 6,150 entries.
All EnumerationsLists all the possible values you can find in the enumerated types. There are more than 1,390 entries in this list.

There are several ways to use the SDK Reference, and which you choose depends on what you are trying to find. To be truly proficient, you’ll need to acquire a lot of hands-on-experience. The next sections provide some use cases to get you started.

Setting a Host in Maintenance Mode

One common task is to set a host into Maintenance mode. Let’s look to see if there is a method that does this. Enter maintenance in the Quick Index field for the All Methods entry. Bingo, you have a winner (Figure 18-2)!

c18f002.tif

Figure 18-2: EnterMaintenanceMode_Task

Just like PowerShell scripts, there is no single correct solution for a problem. You can arrive at the same result via the All Properties entry. Enter maintenance in the Quick Index field (Figure 18-3).

c18f003.tif

Figure 18-3: inMaintenanceMode property

There is a property called inMaintenanceMode that looks promising. Let’s investigate the data object that contains the property (Figure 18-4).

In the description of the property, you can see a link to EnterMaintenanceMode_Task.

c18f004.eps

Figure 18-4: HostRuntimeInfo

Did the Alarm Fire the SNMP Trap?

As you learned in Chapter 17, “Alarms,” you can set up alarms in the vCenter Server that will fire when a specific event occurs in your vSphere environment. As a result, the alarm will execute one or more actions. One type of action that is used often for monitoring is to fire an SNMP trap. This SNMP trap will be transmitted to a monitoring server where you can take appropriate action for the event that occurred.

But what if you’re pretty sure the event occurred and you never see the SNMP trap arriving at your monitoring server?

Now this is, perhaps, a question you would not expect to find an answer to in a section on the vSphere API Reference. We include it here to show you that the vSphere API Reference can also be useful even when you do not intend to use the API. All the events that can be created in a vSphere environment are documented under the Data Object Types entry. Let’s take a look. Type snmp in the Quick Index field (Figure 18-5).

c18f005.tif

Figure 18-5: SNMP events

Two of the entries that appear are obviously related to SNMP traps that are fired by an alarm. Since we want to find out what went wrong, we will have to look for the AlarmSnmpFailedEvent. With the techniques you learned in Chapter 15, “Reporting and Auditing,” it is quite easy to use AlarmSnmpFailedEvent as a filter after the Get-VIEvent cmdlet. Doing so lets you investigate whether the problem is due to a failure of the vCenter Server to send out the SNMP trap.

Finding Metrics for Thin Provisioning

When you want to collect statistical data on your thin provisioning, you should know which of many available metrics to use. The vSphere API Reference documents them well. First, select the PerformanceManager object in the Managed Objects entry, and under the Performance Counters heading you will find the available performance counters (Figure 18-6).

c18f006.tif

Figure 18-6: Performance counters

Under the Storage Capacity category, select the Datastore / Virtual Machine entry. You can now see all the available metrics (Figure 18-7).

c18f007.eps

Figure 18-7: Storage capacity metrics

You can compile your report on thin provisioning based on the provisioned and used metrics. See Chapter 16, “Using Statistical Data,” for further details on working with metrics and statistical data.

Can You Migrate This Guest?

In the vSphere client, you get a message when a vMotion operation is not possible. The Move-VM cmdlet does not have this functionality. So, how does the vSphere client do this? Type migrate in the Quick Index field in the All Methods text box, as shown in Figure 18-8.

c18f008.tif

Figure 18-8: Can a vMotion be done?

Notice the CheckMigrate_Task. That looks promising; let’s take a look at the method (Figure 18-9).

c18f009.tif

Figure 18-9: CheckMigrate_Task

Let’s take a closer look at the parameters this method requires. (On screen, optional parameters have a red asterisk behind their name.) Instead of passing an actual object, you can pass the $null value.

The testType parameter requires an array of strings with the names of the tests that should be executed. But where can you find the test names? For such questions, it’s always good to start with the enumeration types. Type test in the Quick Index field of the Enumerated Types entry (Figure 18-10).

c18f010.tif

Figure 18-10: CheckTestType

That enumeration seems to hold the different tests you can use in the testType property (Figure 18-11).

But wait. There was a second entry in the index query result. If you go to the ValidateMigrationTestType enumeration (Figure 18-12), you will see that this is a deprecated type and that in API 4.0 you should use CheckTestType. The small print is important in the vSphere API Reference!

c18f011.tif

Figure 18-11: CheckTestType enumeration

c18f012.tif

Figure 18-12: ValidateMigrationTestType

Now that we’ve solved the mystery of the testType parameter, let’s return our focus to the CheckMigrate_Task method (see Figure 18-9). Attentive readers might have noticed that the CheckMigrate_Task method apparently only handles vMotion. This seems to be confirmed by the reference to the MigrateVM_Task method. But what about SVMotion?

In the first line of the parameters for the CheckMigrate_Task method, you notice the _this entry, which, in fact, points to the managed object on which the method is called, VirtualMachineProvisioningChecker. When you go to the VirtualMachineProvisioningChecker object (Figure 18-13), you can see that it provides several other methods. One is the CheckRelocate_Task method (Figure 18-14). That method seems to be intended to test the feasibility of the RelocateVM_Task—in other words, the SVMotion task.

Walking the SDK documentation might seem complex, but rest assured it all links nicely together and, after your first few scripts that use vSphere API, it will become a natural exercise.

c18f013.eps

Figure 18-13: VirtualMachineProvisioningChecker

c18f014.tif

Figure 18-14: CheckRelocate_Task

Use Managed Objects

As we explained in the beginning of this chapter, a managed object is a server-side object that represents a vSphere object or a vSphere service as they exist inside vSphere. These objects contain all the information vSphere needs to work with these entities. The information present in these objects includes properties (the data objects) or methods (functions you can execute). In your PowerCLI scripts, you cannot access these server-side objects directly. Your scripts will work, as we explained earlier, with an asynchronous copy of the server-side objects. These copies are generally referred to as .NET View objects.

A PowerCLI object, on the other hand, is an object that is returned by a PowerCLI cmdlet. This object is a selection of properties and methods as selected by the PowerCLI Development Team. It is not a 1-to-1 copy of the underlying vSphere object.

The naming convention for these two types of objects in the PowerCLI documentation is as follows:

  1. PowerShell VIObject A PowerShell VIObject is an object that is returned by a PowerCLI cmdlet. We will use the short name VIObject in the rest of this chapter.
  2. vSphere .NET View Object A vSphere .NET View object is the client copy of a managed object. We will use the short name View object.

Let’s look at some examples so that you can see the difference more clearly.

Managed Object Types

The Get-Datastore cmdlet returns an object for each datastore that is known in the vSphere server your session is connected to. Take a look at the VIObject that the cmdlet returns. The object is a derived type off the base DatastoreImpl type. Most of the VIObjects will have a type name that ends with Impl. That allows a script to recognize where an object comes from. You’ll find yourself type-casting parameters on a function, but it also allows you to interpret the results returned by the GetType method (Table 18-4).

$dsImpl = Get-Datastore -Name DS1
$dsImpl.GetType()

Table 18-4: Results returned by the GetType method

CharacteristicReturn value
IsPublicTrue
IsSerialFalse
NameNasDatastoreImpl
BaseTypeVMware.VimAutomation.ViCore.Impl.V1.DatastoreMan…

Now, let’s use the Get-View cmdlet to get the vSphere object. Notice that the object returned is a Datastore type. This object is documented in the vSphere API Reference under the Managed Object Types. (You’ll remember that a VIObject only contains a subset of all the available properties. The subset is a selection made by the developers.)

$ds = Get-Datastore -Name DS1 | Get-View
$ds.GetType()

IsPublic IsSerial Name        BaseType
-------- -------- ----        --------
True     False    Datastore   VMware.Vim.ManagedEntity

As we said earlier, the VIObjects have a selection (defined by the PowerCLI Development Team) of properties and methods attached. You can use the Get-Member method to view their selection. Let’s take a closer look at the properties and methods that are attached to the VIObject that represents a Datastore:

$dsImpl | Get-Member

   TypeName:
VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.NasDatastoreImpl

Name                           MemberType Definition
----                           ---------- ----------
ConvertToVersion               Method     T VersionedObjectInterop.Conv...
Equals                         Method     bool Equals(System.Object obj)
GetHashCode                    Method     int GetHashCode()
GetType                        Method     type GetType()
IsConvertableTo                Method     bool VersionedObjectInterop.I...
LockUpdates                    Method     void ExtensionData.LockUpdates()
ToString                       Method     string ToString()
UnlockUpdates                  Method     void ExtensionData.UnlockUpda...
Accessible                     Property   bool Accessible {get;}
CapacityGB                     Property   decimal CapacityGB {get;}
CapacityMB                     Property   decimal CapacityMB {get;}
Client                         Property   VMware.VimAutomation.ViCore.I...
CongestionThresholdMillisecond Property   System.Nullable[int] Congesti...
Datacenter                     Property   VMware.VimAutomation.ViCore.T...
DatacenterId                   Property   string DatacenterId {get;}
DatastoreBrowserPath           Property   string DatastoreBrowserPath {...
ExtensionData                  Property   System.Object ExtensionData {...
FreeSpaceGB                    Property   decimal FreeSpaceGB {get;}
FreeSpaceMB                    Property   decimal FreeSpaceMB {get;}
Id                             Property   string Id {get;}
Name                           Property   string Name {get;}
ParentFolder                   Property   VMware.VimAutomation.ViCore.T...
ParentFolderId                 Property   string ParentFolderId {get;}
RemoteHost                     Property   string RemoteHost {get;}
RemotePath                     Property   string RemotePath {get;}
State                          Property   VMware.VimAutomation.ViCore.T...
StorageIOControlEnabled        Property   bool StorageIOControlEnabled ...
Type                           Property   string Type {get;}
Uid                            Property   string Uid {get;}
UserName                       Property   string UserName {get;}

The vSphere objects typically have a lot more properties and methods attached to them, as the following closer look at a managed object that represents a Datastore reveals:

$ds | Get-Member

   TypeName: VMware.Vim.Datastore
Name                              MemberType Definition
----                              ---------- ----------
DatastoreEnterMaintenanceMode     Method     VMware.Vim.StoragePlacemen...
DatastoreExitMaintenanceMode      Method     void DatastoreExitMaintena...
DatastoreExitMaintenanceMode_Task Method     VMware.Vim.ManagedObjectRe...
Destroy                           Method     void Destroy()
DestroyDatastore                  Method     void DestroyDatastore()
Destroy_Task                      Method     VMware.Vim.ManagedObjectRe...
Equals                            Method     bool Equals(System.Object ...
GetAllEventsView                  Method     VMware.Vim.EventHistoryCol...
GetAllTasksView                   Method     VMware.Vim.TaskHistoryColl...
GetEntityOnlyEventsCollectorView  Method     VMware.Vim.EventHistoryCol...
GetEntityOnlyTasksCollectorView   Method     VMware.Vim.TaskHistoryColl...
GetEventCollectorView             Method     VMware.Vim.EventHistoryCol...
GetHashCode                       Method     int GetHashCode()
GetTaskCollectorView              Method     VMware.Vim.TaskHistoryColl...
GetType                           Method     type GetType()
RefreshDatastore                  Method     void RefreshDatastore()
RefreshDatastoreStorageInfo       Method     void RefreshDatastoreStora...
Reload                            Method     void Reload()
Rename                            Method     void Rename(string newName)
RenameDatastore                   Method     void RenameDatastore(strin...
Rename_Task                       Method     VMware.Vim.ManagedObjectRe...
setCustomValue                    Method     void setCustomValue(string...
SetViewData                       Method     void SetViewData(VMware.Vi...
ToString                          Method     string ToString()
UpdateViewData                    Method     void UpdateViewData(Params...
UpdateVirtualMachineFiles         Method     VMware.Vim.UpdateVirtualMa...
UpdateVirtualMachineFiles_Task    Method     VMware.Vim.ManagedObjectRe...
WaitForTask                       Method     System.Object WaitForTask(...
AlarmActionsEnabled               Property   bool AlarmActionsEnabled {...
AvailableField                    Property   VMware.Vim.CustomFieldDef[...
Browser                           Property   VMware.Vim.ManagedObjectRe...
Capability                        Property   VMware.Vim.DatastoreCapabi...
Client                            Property   VMware.Vim.VimClient Clien...
ConfigIssue                       Property   VMware.Vim.Event[] ConfigI...
ConfigStatus                      Property   VMware.Vim.ManagedEntitySt...
CustomValue                       Property   VMware.Vim.CustomFieldValu...
DeclaredAlarmState                Property   VMware.Vim.AlarmState[] De...
DisabledMethod                    Property   string[] DisabledMethod {g...
EffectiveRole                     Property   int[] EffectiveRole {get;}
Host                              Property   VMware.Vim.DatastoreHostMo...
Info                              Property   VMware.Vim.DatastoreInfo I...
IormConfiguration                 Property   VMware.Vim.StorageIORMInfo...
LinkedView                        Property   VMware.Vim.Datastore_Linke...
MoRef                             Property   VMware.Vim.ManagedObjectRe...
Name                              Property   string Name {get;}
OverallStatus                     Property   VMware.Vim.ManagedEntitySt...
Parent                            Property   VMware.Vim.ManagedObjectRe...
Permission                        Property   VMware.Vim.Permission[] Pe...
RecentTask                        Property   VMware.Vim.ManagedObjectRe...
Summary                           Property   VMware.Vim.DatastoreSummar...
Tag                               Property   VMware.Vim.Tag[] Tag {get;}
TriggeredAlarmState               Property   VMware.Vim.AlarmState[] Tr...
Value                             Property   VMware.Vim.CustomFieldValu...
Vm                                Property   VMware.Vim.ManagedObjectRe...

Data Objects and Their Methods

All the properties in a managed object contain data objects. The data objects can be simple types—for example, the Name property, which is a String type—or they can be other data objects—like the AvailableField property, which is a CustomFieldDef type.

The methods in the managed objects are, simply said, functions you can invoke on these objects. For example, the RenameDatastore method on the Datastore managed object obviously renames a datastore. You can find all the details on this method in the vSphere API Reference if you select the Datastore object in the Managed Object Types entry.

The documentation for each managed object follows a similar layout in the vSphere API Reference. First there is a section that lists the following:

  • Property of: Where the managed object is used
  • Parameter to: Which methods use the managed object
  • Returned by: Which methods return the managed object
  • Extends: The type on which this managed object is based
  • See also: The data objects that are used in the managed object’s properties

The next section contains a description of the managed object. This is a must-read section if you are serious about working with managed objects. The description is followed by a tabular list of all the properties of the managed object and a list of all the methods available for the managed object. The API reference also includes a detailed description of all the methods.

If you look in the list of methods for the Datastore object in the vSphere API Reference, you will notice that there are a number of methods that are marked as being inherited. Let’s take the inherited method called Rename that exists in addition to the more specific RenameDatastore method. Most managed objects are based on a parent class. Class inheritance ensures that common properties and methods can be defined for a parent class instead of for each of the managed objects.

In the case of the Datastore object, you can see (Figure 18-15) that a Rename_Task method was inherited from the ManagedEntity object, which is itself also a managed object.

c18f015.eps

Figure 18-15: Rename_Task method

So what’s the deal here? We seem to have two different methods—one called DatastoreRename and another called Rename_Task. And both seem to be doing the same thing: renaming a datastore. The explanation for this can be found in the vSphere API Reference. The RenameDatastore method is marked as Deprecated, and it says that you should use the Rename_Task method. This is obviously something that the vSphere API developers introduced with version 4.0 of the API. Historically most of the managed objects had their own rename method; in our example, that would be the RenameDatastore method.

With API 4.0 it was apparently deemed wiser to use a unified renaming method, and so the developers created a Rename_Task method on the ManagedEntity object. Since most of the important managed objects are derived from this ManagedEntity object, they all inherit this unified Rename_Task method.

The following code uses the synchronous Rename method from the Datastore managed object. The prompt only comes back when the actual rename is finished. Don’t forget that the Rename method is not a method that you will find in the vSphere API Reference. The method was added by the PowerCLI Development Team to the .NET Framework to give you a synchronous version of what an asynchronous method is.

[vSphere PowerCLI] C:> $ds.Rename("DS22")
[vSphere PowerCLI] C:>

Let’s verify that the rename was done correctly:

$ds.Name

DS1

It looks as if the method call didn’t work! Rest assured, the method call did work. You just have to remember that you’re using a client-side copy of the actual managed object that exists on the vSphere server.

One method of checking that the name change actually happened would be to get a fresh copy of the Datastore managed object like this:

$ds = Get-Datastore -Name DS22 | Get-View
$ds.Name

DS22

Another method to verify that the rename of the datastore was done is to refresh part of the copy that you have. To do that, use the UpdateViewData method that the PowerCLI Development Team added to most managed objects. The UpdateViewData method allows you to refresh either the complete managed object or specific properties of the object. The ability to specify the properties you wish to refresh can be a significant time-saver if the property itself is a complex data object. It saves even more time if you need to refresh properties on thousands of managed object copies!

$ds.UpdateViewData("Name")
$ds.Name

DS22

Using vSphere Managers

The other major type of managed objects consists of the service managers. Service managers are special objects that provide services in the virtual environment. Some examples of such services are EventManager, LicenseManager, and PerfManager.

To access the service managers, start from the ServiceInstance managed object, which is the root object of the inventory. In the Content property, you will find a MoRef for most of the service managers:

Get-View ServiceInstance

ServerClock : 4/28/2015 3:00:42 PM
Capability  : VMware.Vim.Capability
Content     : VMware.Vim.ServiceContent
MoRef       : ServiceInstance-ServiceInstance
Client      : VMware.Vim.VimClientImpl


Get-View ServiceInstance | Select -ExpandProperty Content

RootFolder                : Folder-group-d1
PropertyCollector         : PropertyCollector-propertyCollector
ViewManager               : ViewManager-ViewManager
About                     : VMware.Vim.AboutInfo
Setting                   : OptionManager-VpxSettings
UserDirectory             : UserDirectory-UserDirectory
SessionManager            : SessionManager-SessionManager
AuthorizationManager      : AuthorizationManager-AuthorizationManager
ServiceManager            : ServiceManager-ServiceMgr
PerfManager               : PerformanceManager-PerfMgr
ScheduledTaskManager      : ScheduledTaskManager-ScheduledTaskManager
AlarmManager              : AlarmManager-AlarmManager
EventManager              : EventManager-EventManager
TaskManager               : TaskManager-TaskManager
ExtensionManager          : ExtensionManager-ExtensionManager
CustomizationSpecManager  : CustomizationSpecManager-CustomizationSpec…
CustomFieldsManager       : CustomFieldsManager-CustomFieldsManager
AccountManager            :
DiagnosticManager         : DiagnosticManager-DiagMgr
LicenseManager            : LicenseManager-LicenseManager
SearchIndex               : SearchIndex-SearchIndex
FileManager               : FileManager-FileManager
DatastoreNamespaceManager : DatastoreNamespaceManager-DatastoreNamespa…
VirtualDiskManager        : VirtualDiskManager-virtualDiskManager
VirtualizationManager     :
SnmpSystem                : HostSnmpSystem-SnmpSystem
VmProvisioningChecker     : VirtualMachineProvisioningChecker-ProvChecker
VmCompatibilityChecker    : VirtualMachineCompatibilityChecker-CompatC…
OvfManager                : OvfManager-OvfManager
IpPoolManager             : IpPoolManager-IpPoolManager
DvSwitchManager           : DistributedVirtualSwitchManager-DVSManager
HostProfileManager        : HostProfileManager-HostProfileManager
ClusterProfileManager     : ClusterProfileManager-ClusterProfileManager
ComplianceManager         : ProfileComplianceManager-MoComplianceManager
LocalizationManager       : LocalizationManager-LocalizationManager
StorageResourceManager    : StorageResourceManager-StorageResourceManager
GuestOperationsManager    : GuestOperationsManager-guestOperationsManager
OverheadMemoryManager     : OverheadMemoryManager-OverheadMemoryManger
CertificateManager        : CertificateManager-certificateManager
IoFilterManager           : IoFilterManager-IoFilterManager
LinkedView                :

Managed Object References

Now what is a MoRef? The acronym stands for managed object reference. A MoRef is a data object that is used as a kind of pointer or link to a managed object. You can use the Get-View cmdlet to retrieve a copy of the managed object from the MoRef. All managed objects have a property called MoRef, which points to the object itself.

The following code shows how to retrieve a service manager through a MoRef pointer. First we use the predefined shortcut to get the ServiceInstance data object with the Get-View cmdlet. And then, as an example, we retrieve the data object that represents the AlarmManager. This time we use the Get-View cmdlet with the MoRef we retrieved from the ServiceInstance, and the Config.AlarmManager property.

$si = Get-View ServiceInstance
$si.Content.AlarmManager

Type                                    Value
----                                    -----
AlarmManager                            AlarmManager

Get-View $si.Content.AlarmManager

DefaultExpression  Description        MoRef              Client
-----------------  -----------        -----              ------
{VMware.Vim.Stat.. VMware.Vim.Alarm.. AlarmManager-Ala.. VMwa...

When you have the service manager’s object, you can access all of its properties and call all its methods:

$alarmMgr = Get-View $si.Content.AlarmManager
$alarmMgr | Get-Member

   TypeName: VMware.Vim.AlarmManager
Name                   MemberType Definition
----                   ---------- ----------
AcknowledgeAlarm       Method     void AcknowledgeAlarm(VMware.Vim.Mana...
AreAlarmActionsEnabled Method     bool AreAlarmActionsEnabled(VMware.Vi...
CreateAlarm            Method     VMware.Vim.ManagedObjectReference Cre...
EnableAlarmActions     Method     void EnableAlarmActions(VMware.Vim.Ma...
Equals                 Method     bool Equals(System.Object obj)
GetAlarm               Method     VMware.Vim.ManagedObjectReference[] G...
GetAlarmState          Method     VMware.Vim.AlarmState[] GetAlarmState...
GetHashCode            Method     int GetHashCode()
GetType                Method     type GetType()
SetViewData            Method     void SetViewData(VMware.Vim.ObjectCon...
ToString               Method     string ToString()
UpdateViewData         Method     void UpdateViewData(Params string[] p...
WaitForTask            Method     System.Object WaitForTask(VMware.Vim....
Client                 Property   VMware.Vim.VimClient Client {get;}
DefaultExpression      Property   VMware.Vim.AlarmExpression[] DefaultE...
Description            Property   VMware.Vim.AlarmDescription Descripti...
MoRef                  Property   VMware.Vim.ManagedObjectReference MoR...

This example with the AlarmManager shows us that there is a method, called GetAlarm. This GetAlarm method will return an array of MoRefs and each MoRef points to an actual Alarm managed object. We know this by examining the definition field for the GetAlarm method. The format used in the default formatter shows the type retuned and the parameter overload for each method. Obtain more details by drilling into the object itself.

The GetAlarm method has one parameter, where you can pass the MoRef of a vSphere entity. A vSphere entity is a managed object, such as a host, a virtual machine, or a folder. When you call GetAlarm this way, the method will return all alarms defined on that specific entity and all the entity’s child objects.

$alarmMgr.GetAlarm($null)

Type                                    Value
----                                    -----
Alarm                                   alarm-1
Alarm                                   alarm-10
Alarm                                   alarm-11
Alarm                                   alarm-12
Alarm                                   alarm-15
Alarm                                   alarm-16
Alarm                                   alarm-17
Alarm                                   alarm-18
Alarm                                   alarm-19
Alarm                                   alarm-2
Alarm                                   alarm-20
Alarm                                   alarm-21
Alarm                                   alarm-22
Alarm                                   alarm-23
Alarm                                   alarm-24
Alarm                                   alarm-27
Alarm                                   alarm-28
Alarm                                   alarm-29
Alarm                                   alarm-30
Alarm                                   alarm-31
Alarm                                   alarm-32
Alarm                                   alarm-33
Alarm                                   alarm-34
Alarm                                   alarm-388
Alarm                                   alarm-4
Alarm                                   alarm-481
Alarm                                   alarm-482
Alarm                                   alarm-483
Alarm                                   alarm-5
Alarm                                   alarm-582
Alarm                                   alarm-6
Alarm                                   alarm-681
Alarm                                   alarm-7
Alarm                                   alarm-72
Alarm                                   alarm-73
Alarm                                   alarm-74
Alarm                                   alarm-75
Alarm                                   alarm-76
Alarm                                   alarm-77
Alarm                                   alarm-78
Alarm                                   alarm-8
Alarm                                   alarm-81
Alarm                                   alarm-82
Alarm                                   alarm-83
Alarm                                   alarm-84
Alarm                                   alarm-85
Alarm                                   alarm-9

If you pass $null to an entity instead of a MoRef, the GetAlarm method will return all of the alarms defined in your vSphere environment:

$cluster = Get-Cluster CLUS1
$alarmMgr.GetAlarm($cluster.ExtensionData.MoRef)

Type                                    Value
----                                    -----
Alarm                                   alarm-681

Notice how we used the ExtensionData property to get to the MoRef of the cluster. This avoids the use of the Get-View cmdlet to get to the managed object that represents the cluster—a real time-saver if you need to run this in a somewhat bigger vSphere environment.

As we said earlier, the GetAlarm method returns an array of MoRefs to Alarm objects. That means you have to use the Get-View cmdlet to get a copy of the managed object that represents an Alarm itself. The Get-View cmdlet takes the MoRef and returns the managed object. And again, once you have the managed object, you will have access to all its methods and properties, as shown by the output of the Get-Member cmdlet:

$al = $alarmMgr.GetAlarm($cluster.ExtensionData.MoRef)
Get-View $al | Get-Member

   TypeName: VMware.Vim.Alarm

Name             MemberType Definition
----             ---------- ----------
Equals           Method     bool Equals(System.Object obj)
GetHashCode      Method     int GetHashCode()
GetType          Method     type GetType()
ReconfigureAlarm Method     System.Void ReconfigureAlarm(VMwa...
RemoveAlarm      Method     System.Void RemoveAlarm()
setCustomValue   Method     System.Void setCustomValue(string...
SetViewData      Method     System.Void SetViewData(VMware.Vi...
ToString         Method     string ToString()
UpdateViewData   Method     System.Void UpdateViewData(Params...
WaitForTask      Method     System.Object WaitForTask(VMware....
AvailableField   Property   VMware.Vim.CustomFieldDef[] Avail…
Client           Property   VMware.Vim.VimClient Client {get;}
Info             Property   VMware.Vim.AlarmInfo Info {get;}
MoRef            Property   VMware.Vim.ManagedObjectReference…
Value            Property   VMware.Vim.CustomFieldValue[] Val…

Get-View $al

Info           : VMware.Vim.AlarmInfo
Value          : {}
AvailableField : {}
MoRef          : Alarm-alarm-681
Client         : VMware.Vim.VimClient

Get to know the available service managers. They will allow you to access the services that are available in the vSphere environment, and are key to automating some of the more critical core services in vSphere.

Code Parameter Objects

Most of the methods you encounter will need one or more parameters. These parameters are (most of the time) data objects of a specific type themselves. How do you create these data objects? Luckily the PowerCLI Development Team included all the vSphere object types in the PowerCLI binding. This allows you to use the constructor of these data objects, via the New-Object cmdlet, to create an instance of a specific type.

On the New-Object cmdlet, you pass the Typename of the object you want to create. Do so by appending the Typename to the VMware.Vim instance:

$spec = New-Object -TypeName VMware.Vim.AlarmSpec
$spec | Get-Member

   TypeName: VMware.Vim.AlarmSpec

Name            MemberType Definition
----            ---------- ----------
Equals          Method     bool Equals(System.Object obj)
GetHashCode     Method     int GetHashCode()
GetType         Method     type GetType()
ToString        Method     string ToString()
Action          Property   VMware.Vim.AlarmAction Action {get…
ActionFrequency Property   System.Nullable`1[[System.Int32, m...
Description     Property   System.String Description {get;set;}
DynamicProperty Property   VMware.Vim.DynamicProperty[] Dynam...
DynamicType     Property   System.String DynamicType {get;set;}
Enabled         Property   System.Boolean Enabled {get;set;}
Expression      Property   VMware.Vim.AlarmExpression Expressi…
Name            Property   System.String Name {get;set;}
Setting         Property   VMware.Vim.AlarmSetting Setting {g…

If a property of the data object is another data object, use the New-Object cmdlet again to create this nested data object. Continue this way until all the required properties of the parameter object are present. (Consult the vSphere SDK Reference or investigate the error that the method will produce when there are properties missing or of the wrong type.)

$spec.Action = New-Object VMware.Vim.AlarmAction

Find the Method You Need

Just like with a PowerShell script, you will find there is no single correct solution for determining the method you need to use. A lot depends on your experience with the vSphere environment, but an analytical mind and some experience with the vSphere API Reference can help you a lot.

In this section, you’ll see examples of using the vSphere API. Each example illustrates a specific aspect of using the vSphere API and shows how you can find the method or property you are looking for to do what you want to accomplish with your script.

Changing the Boot Delay of a Virtual Machine

To change the boot delay of a VM, it is clear you need to look at the VirtualMachine managed object. But the Reference Guide has documented an enormous number of properties. Which one to use? In a case like this, it is easier to go to the All Properties entries and type a word that describes the property you’re looking for (for this example, we began entering bootdelay) in the Quick Index field, as shown in Figure 18-16.

c18f016.tif

Figure 18-16: The bootDelay property

The first entry, bootDelay (VirtualMachineBootOptions), in the returned list looks promising. If you follow the link, you arrive at the VirtualMachineBootOptions data object. In the Property Of section, you see that the bootDelay data object is referenced in two other data objects: VirtualMachineConfigInfo and VirtualMachineConfigSpec. Now, you have a property that seems to do what you are looking for. If you follow a trail through the vSphere API Reference, you can find the method that will allow you to change that property. But which one to choose? In cases where you want to change something on a vSphere entity, it is always the data object that contains the Spec suffix you need. The Info suffix indicates that this is a data object that can be used to retrieve information from a vSphere entity. That brings you to inspecting the VirtualMachineConfigSpec data object, where you can see that the object is used as a parameter in the ReconfigVM_Task. Bringing everything you’ve learned thus far all together, you can use this small script to change the boot delay of a virtual machine:

$vmName = "PC1"
$delayMS = "5000"    # Boot delay in milliseconds

$vm = Get-VM -Name $vmName
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.bootOptions = New-Object VMware.Vim.VirtualMachineBootOptions
$spec.bootOptions.bootDelay = $delayMS

$vm.Extensiondata.ReconfigVM_Task($spec)

Remember that we briefly discussed the New-Object cmdlet and how you can use it to create it objects in the section “Code Parameter Objects.” You’ll learn more about the creation of data objects and their properties in Appendix: Example Reports.

Finding the Patches Installed on an ESXi Host

To find the patches installed on an ESXi host, you can start from the Managed Object Types entry. Enter a common term like the word patch in the Quick Index field and you will see only an entry called HostPatchManager in the results.

On the HostPatchManager page, there is a method called QueryHostPatch_Task in the Methods section. This method requires a single parameter, a data object of the HostPatchManagerPatchManagerOperationSpec type. On the reference page for that object, you will find that all the properties are optional. Remember those red asterisks? They mean that no properties are required, which ultimately means that you can pass $null as the parameter to the method, as we did here:

$esx = Get-VMHost esx1.test.local
$pmMoRef = $esx.ExtensionData.ConfigManager.PatchManager
$pm = Get-View $pmMoRef
$pm.QueryHostPatch()
Cannot find an overload for "QueryHostPatch" and the argument
count: "0".
At line:1 char:19
+ $pm.QueryHostPatch <<<< ()
 + CategoryInfo          : NotSpecified: (:) [], MethodException
 + FullyQualifiedErrorId : MethodCountCouldNotFindBest

Notice that the method returned an error. You can’t leave out the parameter, even though you don’t pass any information. Whenever you want to pass an empty parameter, pass the $null value. Let’s try again:

$pm.QueryHostPatch($null) | Format-List

Version         : 1.40
Status          :
XmlResult       : <esxupdate-response>
                  <version>1.40</version>
                  </esxupdate-response>

Finding the Host HWuptime

Suppose you want to know how long the hardware hosting one of your ESX hosts has been powered on. If you enter uptime in the All Methods entry, you will find the RetrieveHardwareUptime method. From the entry in the SDK Reference, you find out that the method is available on a HostSystem managed object, that the method has no required parameters, and that the time is returned as the number of seconds. Using the method, calculating the HWuptime is now rather straightforward:

$esx = Get-VMHost esx1.test.local
$esx.ExtensionData.RetrieveHardwareUptime()
301248

Changing the vCenter Logging Options

By now, you’re probably thinking that the SDK Reference is the ultimate resource, but not all information you will ever require while you’re working with vSphere is so readily available in the SDK Reference. Let’s look at another example.

In the Managed Object Types, you will find the OptionManager, which is obviously what you would look for if you wanted to change vCenter Server options. But if you further investigate the UpdateOptions method, you will find that the OptionValue parameter is required. Now, here’s the problem: There seems to be no list of accepted values for the Key and Value fields.

A closer look at the OptionManager object entry provides the solution. The OptionManager object has two properties that hold the answer: the Setting property and the SupportedOption property. When you check those, you’ll find that the Setting property holds all the Key-Value pairs for current settings and the SupportedOption property holds the accepted Key-Value pairs. Let’s use Get-View to see if you can find the information you need:

$si = Get-View ServiceInstance
$optMgr = Get-View $si.Content.Setting
$optMgr.SupportedOption | Where {$_.Key -like "*log*"} | fl Key, Label

Key   : DBProc.Log.Level.Stats.Purge1
Label : Log level for daily stats purge

Key   : DBProc.Log.Level.Stats.Purge2
Label : Log level for weekly stats purge

Key   : DBProc.Log.Level.Stats.Purge3
Label : Log level for monthly and yearly stats purge

Key   : DBProc.Log.Level.Stats.Rollup1
Label : Log level for daily stats rollup

Key   : DBProc.Log.Level.Stats.Rollup2
Label : Log level for weekly stats rollup

Key   : DBProc.Log.Level.Stats.Rollup3
Label : Log level for monthly stats rollup

Key   : DBProc.Log.Level.Topn.Calc1
Label : Log level for topn rank of daily stats

Key   : DBProc.Log.Level.Topn.Calc2
Label : Log level for topn rank of weekly stats

Key   : DBProc.Log.Level.Topn.Calc3
Label : Log level for topn rank of monthly stats

Key   : DBProc.Log.Level.Topn.Calc4
Label : Log level for topn rank of yearly stats

Key   : DBProc.Log.Level.Topn.Purge1
Label : Log level for purge of daily topns

Key   : DBProc.Log.Level.Topn.Purge2
Label : Log level for purge of weekly topns

Key   : DBProc.Log.Level.Topn.Purge3
Label : Log level for purge of monthly topns

Key   : DBProc.Log.Level.Topn.Purge4
Label : Log level for purge of yearly topns

Key   : log.level
Label : Logging level

The last option returned seems to be the one you are after. Using the following code, you can now obtain the permitted values:

$ll = $optMgr.SupportedOption | here {$_.Key -like "log.level"}

$ll.OptionType.ChoiceInfo | ft -AutoSize

Key     Label       Summary
---     -----       -------
none    None        Disable logging
error   Error       Errors only
warning Warning     Errors and warnings
info    Information Normal logging
verbose Verbose     Verbose
trivia  Trivia      Trivia

After you have retrieved the permitted values, you are ready to call the method. Here’s how we did it:

$opt = New-Object VMware.Vim.OptionValue
$opt.Key = "log.level"
$opt.Value = "verbose"
$optMgr.UpdateOptions($opt)

Understand Return Values and Faults

Earlier in the chapter, we introduced the Task object. Task managed objects allow you to verify the state of a particular task, check the result of that task, and determine whether any faults occurred. Let’s use the PatchManager and see how this works:

$esx = Get-VMHost esx1.test.local
$pmMoRef = $esx.ExtensionData.ConfigManager.PatchManager
$pm = Get-View $pmMoRef
$taskMoRef = $pm.QueryHostPatch_Task($null)

Notice in the last code line that the method ends with the _Task suffix; it is an asynchronous task and will return a MoRef to a Task object. With the help of the Get-View cmdlet, you can get a local copy of the Task object. We used the following code:

$task = Get-View $taskMoRef

In the Task object, you can find the current state of the task. The returned state can be queued, running, success, or error, as shown next:

$task.Info.State
success

In this case, the method call completed successfully. You can find more information about the results of the call to the method in the Task object by using $task.Info.Result:

$task.Info.Result

Version      Status      XmlResult
-------      ------      ---------
1.40                     <esxupdate-response>...

Now, let’s see what happens when an error occurs. In this example, we used a VMHost profile and the API extension to check the current compliance status of a vSphere host. To do so, we leveraged the CheckProfileCompliance_Task method on the VMHostProfile object. This method does have a strongly typed parameter, but the parameter is calling for a MoRef. (This is a common occurrence throughout the API; the EVC mode configuration passes an invalid EVC mode.) Here’s the code we used:

$esx = Get-VMHost -Name esx1.test.local
$vm = Get-VM -Name VM001
$hProf = Get-VMHostProfile -Name Prod

# Mistake, pass the VM MoRef to the method
$taskMoRef = `
  $hprof.ExtensionData.CheckProfileCompliance_Task($vm.ExtensionData.MoRef)

$task = Get-View -Id $taskMoRef
while($task.Info.State -eq [VMware.Vim.TaskInfoState]::running){
    sleep 2
    $task.UpdateViewData('Info')
}

You can see that we provoked a method failure by passing an incorrect parameter to the CheckProfileCompliance_Task method.

$task = Get-View $taskMoRef
$task.Info.State
Error

As expected, the method returned an error. Let’s see what other information we can get using $task.Info.Error.Fault.GetType():

 $task.Info.Error.Fault.GetType()

IsPublic IsSerial Name            BaseType
-------- -------- ----            --------
True     False    InvalidType     VMware.Vim.InvalidRequest

The information returned tells us that fault is an InvalidType type, which is a kind of catchall fault. You can investigate further through the LocalizedMessage and the Fault properties. Here’s how we did that:

$task.Info.Error.LocalizedMessage
The request refers to an unexpected or unknown type.

$task.Info.Error.Fault

Argument         FaultCause       FaultMessage
--------         ----------       ------------
entity

As you can see, the faults that are returned are often cryptic. But, when you investigate the return code and display some of the Error properties, it will become a lot clearer to the script users (yourself included) that something went wrong. In this instance, we supplied the MoRef for the incorrect Type of Managed Object to the entity property of the method. A quick review would reveal our mistake and a simple update to pass in the vSphere host’s MoRef would result in a successful invocation.

Put Some Tips and Tricks to Good Use

The more you work with the vSphere API, the more you’ll find the same script elements appearing again and again. It is useful to keep these code snippets for easy reuse in your scripts. This section illustrates some of these general code snippets.

Waiting for an Asynchronous Task

In your scripts you can construct a simple loop to wait for the completion of asynchronous tasks. The following script shows one way of doing this:

$taskMoRef = <any_call_to_an_asynchronous_method>
$task = Get-View $taskMoRef
while("running","queued" -contains $task.Info.State){
  $task.UpdateViewData("Info")
  Start-Sleep -Seconds 1
}

The script loops until the status of the task is no longer queued (waiting to run) or running. Since the script looks at a copy of the Task object, we had to refresh the Task object contents periodically. We used the UpdateViewData method and specified that only the Info property needed to be refreshed.

Better Error Handling after Asynchronous Tasks

The ability of your scripts to intercept errors and produce meaningful error messages will improve their user friendliness. The following code snippet, which you can insert immediately after a wait loop, will check whether a call to an asynchronous method completed successfully. If the call to the method failed, the script displays an error message and then exits.

if($task.Info.State -eq "error"){
  $task.UpdateViewData("Info.Error")
  $task.Info.Error.Fault.faultMessage | % {
    $_.Message
  }
  exit
}

Finding Service Managers with Get-View Shortcuts

As we mentioned earlier, the Get-View cmdlet has shortcuts for several of the service managers that you would normally access via the ServiceInstance object. But how can you find out which shortcuts are recognized by Get-View? The following short function returns a list of the shortcuts you can use with Get-View:

function Get-GVShortcut {
  Write-Verbose -Verbose "Shortcuts supported by Get-View"
  $si = Get-View ServiceInstance
  $si.content | Get-Member -MemberType Property | Foreach-Object {
    if($_.Name -match "Manager"){
      $t = Get-View $_.Name -ErrorAction SilentlyContinue
      if($t -ne $null){
        Write-Output $_.Name
      }
    }
  }
}

Advanced Filters with Get-View

When writing scripts against truly massive environments, you may need to optimize your code by filtering the response server size, as well as pruning the properties returned. When these two techniques are paired with the UpdateViewData method, you can minimize the amount of data being parsed by the system to the absolute bare minimum. This in turn will result in lower memory utilization and faster processing speed. However, be forewarned: When using PowerCLI in this manner, it is possible to overrun the vCenter Server by sending more requests and subsequent tasks than the web services can handle. It is inconveniently easy to DDOS vCenter with PowerCLI. You will find that in the long run this low-level micromanagement can lead to drastic improvements in performance. For example, consider the task of quickly counting all the Server 2008 VMs currently running in an environment.

# a simple one liner using the PowerCLI cmdlets
Measure-Command -Expression {
    $vmsByVIObj = Get-VM | 
        Where {$_.Guest.GuestId -eq 'windows7Server64Guest'}
}


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 13
Milliseconds      : 527
Ticks             : 135278784
TotalDays         : 0.000156572666666667
TotalHours        : 0.003757744
TotalMinutes      : 0.22546464
TotalSeconds      : 13.5278784
TotalMilliseconds : 13527.8784
# a direct query into the vSphere API for only the information requested
Measure-Command -Expression {
    $vmsByView = Get-View -ViewType VirtualMachine `
        -Filter @{'Guest.GuestId'='windows7Server64Guest'} -Property Name
}


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 132
Ticks             : 1328241
TotalDays         : 1.53731597222222E-06
TotalHours        : 3.68955833333333E-05
TotalMinutes      : 0.002213735
TotalSeconds      : 0.1328241
TotalMilliseconds : 132.8241

As you can see, the performance gains are dramatic. This isn’t due to any flaw in the cmdlets; it’s simply due to the fact that PowerShell is given less data to process. Pruning the data being returned to only the name of the VM benefits vCenter as well. It reduces the data that vCenter has to look up and return, and it physically lowers the impact all around. This doesn’t reduce your ability to perform more complex tasks, because any missing properties can be dynamically loaded in as needed with UpdateViewData.

Finally, the -Filter parameter accepts a simple hash table where the key is the name of the property and the value is the value. However, the Value field accepts a regular expression, meaning it is possible to create sophisticated queries. For example, to find all the VMs with either Windows 2008 or Ubuntu Linux and one or two vCPUs, use the following statement:

Get-View -ViewType VirtualMachine -Filter @{
    'Guest.GuestId'='windows7Server64Guest|ubuntu64Guest'
    'Config.Hardware.NumCPU'='[1-2]'
} -Property Name

In this instance, we’re searching for any object with the ViewType of VirtualMachine that matches either windows7Server64Guest or ubuntu64Guest in the GuestId property with one or two vCPUs. As you can see, when you know exactly what you want it is rather easy to build an extremely performant and scalable script.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset