This course will introduce the core concepts of PowerCLI.
Being proficient in “PowerCLI” could be summarised in this way:
70% Know PowerShell core concepts relevant for PowerCLI
30% Understand the concepts specifics to PowerCLI
And as prerequisite, understand VMware technologies
The focus of this study guide will be on these 30%.
Each exercise has been designed to teach you one PowerCLI specific skill.
The other 70% will be covered in the PowerShell study guide – core concepts
Scope of this course
This is not a PowerShell course
However you will need PowerShell skills to complete many tasks.
If you don’t have PowerShell skills yet feel free to start by the following PowerShell study guide – core concepts
It contains only PowerShell core concepts relevant for PowerCLI.
For example, you will not need to learn how to execute command on a remote Windows computer to use PowerCLI.
Make you “proficient” in the PowerCLI language
It does not mean to know everything but instead to know the “logic” to be able to handle any challenge, in others words:
able to reuse and adapt existing scripts
able to create a script from scratch when needed
It will only focus on PowerCLI and API reachable via PowerCLI
For example, the areas below will be out of scope.
Manage some VMware products via PowerShell and Rest API that are not yet manageable via PowerCLI.
Connect to the CIM interface of an ESXi host via PowerShell.
It will not cover all areas of PowerCLI
There are just too many areas, with thousands of functions when using the APIs.
The goal is to teach you how to “think PowerCLI” then you will be able to handle any challenges.
This tutorial is not a self-standing course or a list of recipes
You will need to practice to benefit from it.
If you prefer to study offline, I would recommend the books in the appendix.
Only focus on PowerCLI on Windows
PowerCLI on LINUX is consequently out of scope.
PowerCli in context
The above diagram is extracted from “PowerCLI study guide from rookie to guru”
PowerCLI could be considered as an “extension” from PowerShell and PowerShell is built on top of “.Net”
This is why you need to learn PowerShell and “.net” in order to make the most out of PowerCLI
The VMware.Vim.dll is quite critical
Backward compatibility for VMware.Vim.dll
Documentation
You will often use these links so add them as bookmarks
VMware vSphere PowerCLI Cmdlets Reference
VMware vSphere API Reference
The official PowwerCLI User’s guide contains many useful information
VMware vSphere PowerCLI User’s Guide or PDF
List of exercises
Pre-requisite
Windows workstation
Ideally with latest PowerShell version (5.0)
Latest version of PowerCLI installed with all optional modules. (6.3 Release 1 at this stage)
Able to connect from the workstation to a VMware test environment based on vCenter 6, multiples hosts and shared storage. (It can be nested hypervisors)
How to handle each exercise
Try alone initially
Try to find a solution using the official documentation, Onyx – see appendix, and your test environment.
This is the best way to learn, because it will teach you how to handle a challenge from scratch.
The goal of this tutorial is not to find an answer, but to learn how to “think PowerCLI” to find an answer.
Use the clue if needed
The clue will point you in the right direction then try again alone.
Please note that not all topics will have a clue.
Search a solution online if needed
Some topics are really challenging and maybe someone has already done the job for you.
Check the Answer
This is not necessary “THE” answer.
There are many ways to achieve the same result with PowerCLI and the criteria for a good script will differ from one person to another.
For example, maybe someone will prefer a script with high performance using API and parallel task at a cost of increased complexity.
Read extra information
Finally more information about the concepts associated to each exercise complement the answer.
Start PowerCLI for the first time
Update the PowerShell execution policy if needed.
List all commands specifics to PowerCLI
Keep only the command name, export result as a GridView
Then count how many command are available.
Start PowerCLI
The execution policy is a PowerShell concept, check the PowerShell course.
get-command –module VMware.* | select name | ogv
(get-command –module VMware.* | measure-object).count
#The result is 528 for PowerCLI 6.3 Release 1 with all optional components installed.
However, you may have noticed after starting PowerCLI in the welcome part the function “get-vicommand”. So you can use instead
Get-vicommand | select name | ogv
Actually get-vicommand is not one of the PowerCLI cmdlets it is in fact a function that is calling
get-command -pssnapin VMware.*
(And pssnapin is an alias of module)
you will find the details of this function in the following folder if you have a 64bits system.
C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\Scripts\Initialize-PowerCLIEnvironment.ps1
Finally, if another user has installed PowerCLI you may end up with issues similar as the one described here. Maybe it has been fixed since.
Understand PowerCLI Modules and Snapins
Launch PowerShell
Import all PowerCLI Modules and Snapin
Then count how many PowerCLI command are available.
This is really a PowerShell question. You will get information about the PowerCLI module and Snapin by following the links below.
VMware vSphere PowerCLI 6.3 Release 1 Release Notes
PowerCLI 6.0 – Introducing PowerCLI Modules
Start PowerShell
get-module –ListAvailable VMware* | Import-Module
Add-PSSnapin -name Vmware*
(get-command –module VMware.* | measure-object).count
#You will get again 528
At the end, PowerCLI is just an “extension” to PowerShell. This is why you need to be proficient with PowerShell in order to become proficient with PowerCLI.
It is possible for example to start a PowerShell session and load PowerCLI and Microsoft Exchanges modules. You will not get however the “welcome” message associated to PowerCLI.
When you launch “PowerCLI” you just launch PowerShell with some customization specific to PowerCLI.
To be more precise this is linked to “Initialize-PowerCLIEnvironment.ps1” presented earlier.
It will be also possible to import others PowerShell Modules in a “PowerCLI” session.
Notes:
PowerCLI 6.5 will be 100% modules based.
Connect to vCenter / Use Credential Store / Undestand $DefaultVIserver
Connect to vCenter using windows account if the workstation is one the the same AD domain
Connect to vcenter using User and Password
Connect to vCenter and save password in the credential store
Connect to vCenter and use the credentials in the credential store
Check the content of $Global:DefaultViServer
Check the content of $Global:DefaultViServers
Disconnect from all vcenter
Add credentials in the credential store
List all credentials in the credential store
Notes: You can also connect to an ESXi host to test using credentials
If your windows account has permission on the vCenter you are connecting to you can use the following command.
connect-viserver –server “ServerNameOrIP”
If it not the case you will have to use
connect-viserver –server “ServerNameOrIP” –user ‘YourUser’ – password ‘YourPassword’
However there is a drawback with this approach, the password is written in clear.
You should use instead
$PSCredential = Get-Credential
connect-viserver –server “ServerNameOrIP” –credential $PSCredential
But what about avoiding typing password every time?
The credential store item is an easy solution in that case.
connect-viserver –server “ServerNameOrIP” –user ‘YourUser’ – password ‘YourPassword’ –savecredentials
Then the next time you will need to connect to the same server you can just type
connect-viserver –server “ServerNameOrIP”
$Global:DefaultViServer
$Global:DefaultViServers
$Global:DefaultViServer or $DefaultViServer is mentioned in Connect-VIServer
To summarise you can connect from PowerCLI to one vCenter or ESXi server.
It is also possible to connect to multiples vCenter and/or ESXi server at the same time.
$Global:DefaultViServer is the last connected server and where the command will be executed by default if the parameter “VIServer” is not used from a PowerCLI command.
$Global:DefaultViServers are all connections currently established.
Consider this at the “top” of the hierarchy for a vCenter or ESXi.
Disconnect-VIServer -Server * -Force
Always disconnect when you have finished to work with a vCenter/ESXi server to avoid “idle” session.
You can also check if you have already some credential in the credential store item using
get-vicredentialStoreItem | select *
You can add credential to the storeitem.
New-VICredentialStoreItem -Host "VcNameOrIP" -User 'domain\user' -Password 'Password'
#Or remove some using
Remove-VICredentialStoreItem
Tips:
Even if it is possible to work on multiple session at the same time it is error prone.
I would recommend initially to work only on one vCentre or ESXi at a time, and always disconnect.
When you will have more experience you can consider connecting to multiples vCenter/ESXi if really needed.
Extract the following information about all ESXI hosts connected to vcenter and export it as a CSV file.
Name
State
Model
Version
Build
Identify in the official documentation the most relevant PowerCLI cmdlet.
PowerCLI is using PowerShell approved verb, so you should search within the cmdlet starting by Get
Get-vmhost | select name,state,model,version,build| export-csv
Goal is to find the right PowerCLI cmdlet
Here get-vmhost
if you already know PowerShell this is quite straightforward.
Use .extensiondata and Performance test
This time export for each host, the name, bios version AND the BIOS Release Date using get-vmhost and the property “.extensiondata”
Finally monitor the execution time of this command.
Get-VMHostFirmware will give you the Bios version but not the Bios release date.
The PowerCLI CMDLET only provide you information deemed as the most relevant by the PowerCLI team.
The Bios release date is however available in the VMware vSphere API Reference
Search for “BIOS” or “release” in “all Properties” and you should discover the relevant information.
PowerCLI makes the API properties and methods available in many way.
One of them is to use the property “extensiondata” of some PowerCLI object to get the “view / .net object” associated to the “PowerCLI object”
For example try:
(get-vmhost | select –first 1).extensiondata.GetType().fullname
(get-vmhost | select –first 1).extensiondata | select *
Then compare the result with:
HostSystem
Explore the content of exensiondata and API documentation to find the path to relevant bios information.
Finally to monitor the execution time of a command you could use this PowerShell cmdlet
Measure-command
get-vmhost | select Name,@{Name="BiosVersion";Expression={$_.extensiondata.hardware.biosinfo.BiosVersion}},@{Name=" ReleaseDate ";Expression={$_.extensiondata.hardware.biosinfo.ReleaseDate}}| ogv
Measure-command{get-vmhost | select Name,@{Name="BiosVersion";Expression={$_.extensiondata.hardware.biosinfo.BiosVersion}},@{Name=" ReleaseDate ";Expression={$_.extensiondata.hardware.biosinfo.ReleaseDate}}}
#In my environment with 89 ESXi hosts
#47.756 seconds
New-viproperty and Performance test
This time you will need to get the Name,Bios Version and Bios release date using the following command:
get-vmhost | select name,BiosVersion,ReleaseDate
By default the two Bios related properties are not available for a VMHost object so you will need to use the New-VIProperty
Then measure the execution time of this command.
new-viproperty –objecttype ‘VMHost’ –Name ‘BiosVersion’ –ValueFromExtensionProperty ‘Hardware.BiosInfo.BiosVersion’
new-viproperty –objecttype ‘VMHost’ –Name ‘ReleaseDate’ –ValueFromExtensionProperty ‘Hardware.BiosInfo.ReleaseDate’
#Note the parameter valuefromextentionproperty is case sensitive
get-vmhost | select name,BiosVersion,ReleaseDate | ogv
measure-command {(get-vmhost | select name,BiosVersion,ReleaseDate)}
#Execution time 11.3 seconds
#Then cleaning
get-viproperty –Name ‘BiosVersion’ | remove-viproperty
get-viproperty –Name ‘ReleaseDate’ | remove-viproperty
In this example without the () in the measure-command it was sometime working or hanging.
Maybe a bug somehow in my environment.
Conclusion at this stage.
New-VIproperty doesn’t only make your scripts easier to read, it also improves performance.
Tips:
If you would like to have your custom VIproperty available all the time you can for example add them in your PowerShell profile.
However, I will not recommend doing so. To ensure that yours scripts will execute everywhere, it is better to add these “new-viproperty” lines at the beginning of each script that will require them…and remove them at the end.
Get-View and Get-VIObjectByVIView
Use get-vmhost, and store the first VMhost object, actually a VIObject, in one Variable called
$VMHOST.
get the type of this object
Display all properties
Then use get-view to get the “View” that correspond to this above PowerCLI object and store it in a variable $VMHOSTView
get the type of this object
Show all properties
Then use get-VIOBbjectByVIView to get the VIObject associated to the “view” object $VMHOSTView object and store it in a variable $VMhostVIObject
get the type of this object
Show all properties
$VMHOST = get-vmhost | select –first 1
$VMHOST.getype().fullname
$VMHOST | select *
$VMhostVIew = $VMHOST | get-view
#OR better if you have followed the PowerShell course
#Do not use a pipe when not needed
$VMhostVIew = get-view –VIOBJECT $VMHOST
$VMHOSTView.getype().fullname
$VMHOSTView | select *
$VMhostVIObject = Get-VIObjectByVIView –VIView $VMHOSTView
$VMhostVIObject.getype().fullname
$VMhostVIObject | select *
The .extensiondata is one way to access from the View (or .net) object associated to a “VIObject” (or PowerCLI/PowerShell),
Get-View is another way to access from the VIObject the View object.
Get-view can also be used to get many “view” object in one operation, for example to get all virtual machine or all ESXi hosts View objects.
Finally, Get-VIObjectByVIVIew does more or less the reverse of Get-View. Obtain the VIobject from the View object.
Get-view and Performance test
Export the name of all ESXi hosts using get-vmhost
Export the name of all ESXi using get-view
Compare the execution time of these two commands
Then
Export the name, Version and Build of all hosts using get-vmhost
Export the name, Version and Build of all hosts using get-view
Compare the execution time of these two commands
Measure-Command {get-vmhost | select name}
Measure-Command { get-view -ViewType hostsystem | select name}
Measure-Command {get-view -ViewType hostsystem -Property name}
#In my environment 89 ESXI hosts
#Execution time 11.9 seconds
#Execution time 31.1 seconds
#Execution time 0.1 seconds
Please note that in the third case we will get the “view object” nearly empty except for the Name property.
If you only need to extract only few properties using get-view and is much faster when dealing with top properties of the View object.
However there is here something strange I do not know if it due to my environment of PowerCLI 6 and using the new version of .net but get-view -ViewType hostsystem is slower than get-vmhost in my environment.
Get-View Part 3: Peformance Impact – Is it really THAT much different?
I used to have better performance with get-view in the past.
Could it be linked to New release: PowerCLI 6.3 R1–Download it today! ?
What’s happening if you need to extract subproperties with get-view?
Measure-Command { get-vmhost | select name,Version,Build}
Measure-Command {get-view -ViewType hostsystem -Property name ,’Config.Product.Version’, ’Config.Product.Build’ | select name,@{Name="Version";Expression={$_.Config.Product.Version}},@{Name="Build";Expression={$_.Config.Product.Build}}}
Measure-Command {get-view -ViewType hostsystem -Property name,’Config.Product.’| select name,@{Name="Version";Expression={$_.Config.Product.Version}},@{Name="Build";Expression={$_.Config.Product.Build}}}
#In my environment 89 ESXI hosts
#Execution time 12.2 seconds
#Execution time 4.3 seconds
#Execution time 2.6 seconds
In the second example, adding two sub-properties has drastically affected performance if we compare by extracting only the top property name.
The example 3 is a way to limit the impact, by extracting every sub properties in Config.Product using “Config.Product.”. However this workaround is valid only for subproperties in the same “node”.
The higher “node” in the hierarchy you will export, slower will be the performance.
Moreover you can also filter vSphere Objects with Get-View to export for example all “windows XP VMs” instead of using a powercli “where-object” operator. This is fast…but at a cost of complexity.
Conclusion:
There are many ways to get the same result, but you need to identify the best for your needs based on the performance and how easy it is to maintain the script.
Test the performance of your scripts using “measure-command”.
Moreover don’t forget that you can execute PowerCLI command only with PowerCLI VIObject and not with View object.
Tips:
Even if get-view can be very fast, especially when using filter and only collecting specific properties it is also complex.
As a general rule I will recommend to keep it simple and use only PowerCLI cmdlets if possible.
You will already be much faster with scripting than in a manual way and you really need a large environment to benefit from optimized scripts.
And a script based on PowerCLI cmdlet will be understandable by any person with PowerShell scripts. If you use API or get-view, it is really necessary to understand the VMware API.
Reminder with .extensiondata and new-viproperty
Measure-Command {get-vmhost | select name,@{Name="Version";Expression={$_.extensiondata.Config.Product.Version}},@{Name="Build";Expression={$_.extensiondata.Config.Product.Build}}}
#Execution time 49.3 seconds
Using extension data has a high cost in term of performance
What about new-viproperty?
new-viproperty –objecttype ‘VMHost’ –Name ‘VersionFromView’ –ValueFromExtensionProperty ‘Config.Product.Version’
new-viproperty –objecttype ‘VMHost’ –Name ‘BuildFromView’ –ValueFromExtensionProperty ‘Config.Product.Build’
Measure-Command {Get-vmhost | Select Name,VersionFromVIew,BuildFromVIew }
#Execution time 14.6 seconds….
Get-viproperty –name ‘VersionFromView’ | remove-viproperty
Get-viproperty –name ‘BuildFromView’ | remove-viproperty
Managed Object Reference
Export the property moref of the first ESXi host in the environment
Note: This property is available in the “View” object.
Notice the two properties that makes Moref.
Get all members of the Moref property and check the type.
Find it in the official documentation
As you can see there are no really useful methods for this object.
This class is used to refer to a server-side Managed Object.
Then select all properties in the ConfigManager “View” property of the first host.
Then get all members of the subproperty CPUScheduler
“Déjà Vu” isn’t it?
Then get the “view” object associated to this “CPUScheduler” Managed Object Reference and store it in a variable $CPUSchedulerView”
Get all members associated to this $CPUSchedulerView and check the type.
Find it in the official documentation
(Get-vmhost | select –first 1).extensiondata.moref | select *
(Get-vmhost | select –first 1).extensiondata.moref | gm
Official documentation ManagedObjectReference
(Get-vmhost | select –first 1).extensiondata.configmanager | select *
(Get-vmhost | select –first 1).extensiondata.configmanager.cpuscheduler | gm
$CPUSchedulerView = get-view –ID ((Get-vmhost | select –first 1).extensiondata.configmanager.cpuscheduler)
$CPUSchedulerView | gm
HostCpuSchedulerSystem
It is critical to understand Moref. This is one of the core concept associated to the API
Start by reading this Managed Object Types Overview
A Moref is a unique identifier for a Managed Objet within ONE vcenter inventory.
You could have identical Moref across multiple vCenter instance
Moreover many view objects have properties that are only “Managed Object Reference” to other Managed Object.
With “Get-view –ID” you can get the View object associated to a Moref.
This is especially useful for the hostsystem object.
The majority of “methods” that you can use against a hostsystem are not associated to the “HostSystem” objects itself, but to one of the “Helping” manager objects.
For example to edit CPU settings, you will need to get from the “configmanager.cpusheduler” property the Moref of the “HostSpuShedulerSystem” associated to this host.
You can then use the methods “DisableHyperThreading” or “EnableHyperThreading” associated to the “view” obect HostCPUShedulerSystem.
On top of the official documentation you can use the following diagram to see a visual representation of all Managed object.
Extracted from VMware vSphere API Object Model
Tips:
Because MOREF are not unique across vCenter it is safer to work on one vCenter at a time.
Modify ESXi host advanced settings using PowerCLI cmdlets
Time to perform some changes…in your test environment.
Select the first ESXI host in your environment
Modify the settings “UserVars.SuppressShellWarning” from the default value 0 to 1 with PowerCLI cmdlets.
Then restore settings to the default value.
PowerCLI is using PowerShell approved verb so search for get and set cmdlets.
get-vmhost | select –first 1 | get-advancedSetting -name UserVars.SuppressShellWarning | set-advancedSetting -value 1 -Confirm:$false
The PowerCLI team understands that this kind of operations will be quite common this is why they have created these two cmdlets.
Restore default settings
get-vmhost | select –first 1 | get-advancedSetting -name UserVars.SuppressShellWarning | set-advancedSetting -value 0 -Confirm:$false
Modify advanced settings using API
Same question as the previous exercise…but this time let’s imagine that the PowerCLI team didn’t create cmdlet to configure advanced settings.
A scenario like this one will happen often, especially when new features are introduced in VMware.
In that case you will have to rely on the API…
You already know two ways to access the API properties, this time you will need to access API methods.
In this scenario, it is totally fine to “cheat” and use “onyx”.
Don’t be shy and use “Onyx” it will guide you in the right direction, however you will discover quickly an extra challenge.
OR
Other way is to use the documentation but you will notice very fast that there are no methods associated to a hostsystem to update the advanced settings.
If there is something available in the vSphere Client or the WebClient more often than not the information should be available somewhere in the API.
Start by searching in the All Properties “Settings” and “Advanced” and try to find something that seems linked to host / hostsystem etc.
$VMhost = get-vmhost | select –first 1
$changedValue = New-Object VMware.Vim.OptionValue[] (1)
$changedValue[0] = New-Object VMware.Vim.OptionValue
$changedValue[0].key = "UserVars.SuppressShellWarning"
$changedValue[0].value = [int64]1
$OptionManager = Get-View -Id ($VMHost.ExtensionData.ConfigManager.AdvancedOption)
$OptionManager.UpdateOptions($changedValue)
#Check the result
$OptionManager.QueryOptions("UserVars.SuppressShellWarning").value
#Restore default settings
$changedValue[0].value = [int64]0
$OptionManager.UpdateOptions($changedValue)
$OptionManager.QueryOptions("UserVars.SuppressShellWarning").value
From the OLD ONYX – Output PowerCLI.Net
# ------- UpdateOptions -------
$changedValue = New-Object VMware.Vim.OptionValue[] (1)
$changedValue[0] = New-Object VMware.Vim.OptionValue
$changedValue[0].key = "UserVars.SuppressShellWarning"
$changedValue[0].value = 0
$_this = Get-View -Id 'OptionManager-EsxHostAdvSettings-16'
$_this.UpdateOptions($changedValue)
So ONYX doesn’t do all the work, but guide you in the right direction.
The most important is the last line; you now know that you should use a method “UpdateOptions” You can search more information about this method in the official documentation.
There is only one method with this name, you will then know what is expected instead of “$_this”
However the documentation is a little bit confusing here “_this” should not a Moref but a View object associated to a MOREF.
Moreover, there is another challenge. The code reported by Onyx is not working
Exception calling “UpdateOptions” with “1” argument(s): “A specified parameter was not correct
The reason is described at this link.
You could have obtained the same information by exporting the actual value of this property and check what was the type
$OptionManager.QueryOptions(“UserVars.SuppressShellWarning”).value.GetType()
If you are not using ONYX this is actually more challenging than expected because there are no methods associated to hostsystem objects to update option settings.
If you have followed the clue you should have discovered the advancedOption (in HostConfigManager )
Then you would have discovered by clinking on the Type the
Managed Object – OptionManager
And that it has two methods “QueryOptions” and “Update options”
If you have used ONYX you will have discovered that it was much more simple to get the information in this way.
Take away:
Using PowerCLI cmdlets when available is much easier than using the API.
If a PowerCLI cmdlet is not available for specific tasks, you always have the possibility to use the API.
You will still have to tests performance of various options to identify what is the best option for you.
Notes:
Sometime some information will not be available in any “standard way” for example:
Private API like update manager. It is only possible to manage it with PowerCLI
Information is not in the standard API but in another one like “Cloud suite SDK”
Information extracted from CIM like ESXi host hardware status
Create VM using PowerCLI
Assumption you have at least one VMhost / ESXi not part of a cluster in your inventory.
This host has access to a datastore with enough space.
In my lab it is “10.0.0.11” and “HDD2”
Using only “PowerCLI cmdlets” perform the following task.
Create a VM “testVMPowerCLI” with default settings on the first ESXi host.
Add a disk of “10GB” to “testVMPowerCLI”
$FirstHost = (get-vmhost | select –first 1)
$FirstHost = get-vmhost ‘10.0.0.11’
$testVMPowerCLI = new-vm –VMHost $FirstHost –datastore ‘HDD2’–name ‘testVMPowerCLI’
New-HardDisk –VM $testVMPowerCLI -CapacityKB 10240
PowerCLI is easy to use, however you will be limited in term of what you can do.
For example, at this stage, there are no PowerCLI cmdlet that can modify the “latency” setting of a VM.
Maybe it will be added later by the PowerCLI team if they deem it useful.
Create VM using API
This time create the VM using the API. (In others words without using “new-vm”)
The host has access to a datastore with enough space.
In my lab it is “10.0.0.11” and “HDD2”
Create a VM “testVMAPI” in one operation:
With the bare minimum settings needed to create a VM with the exception of rules below.
Configure the latency Sensitivity to “High”
Add a “VMware paravirtual” controller
Add a disk of “10GB thin” added to this “paravirtual” controller
Finally the VM will need to be added in “VMs and Templates view” under the datacenter where is located the ESXi host.
Note: If you have the choice between two methods with the same name but one of them end by “_Task” use the one without “_Task”
Use ONYX and create a VM with necessary settings. (The code will not provide you the most basic settings)
Then attempt to create a VM with only the bare minimum settings. (In others words try to reduce the code obtain in the first step to only keep what is mandatory to create a VM)
Then adapt the second script and modify it to add all additional settings based on the script of the step 1.
$FirstHost = (get-vmhost | select –first 1)
$FirstHost = get-vmhost ‘10.0.0.11’
#Below is the folder in the “VMs and Templates view” where will be created the VM
$VMFolderView = get–view –id ((get-datacenter –vmhost $FirstHost).extensiondata.VMFolder)
#First we need to identify the “ComputeResource parent” of the host
$ComputeResourceView = get-view –id ($FirstHost.extensiondata.Parent)
#Then get the resource pool (actually hidden) moref associated to this standalone host.
$ResourcePoolMoref = $ComputeResourceView.resourcepool
#This is all settings necessary to create the VM
$config = New-Object VMware.Vim.VirtualMachineConfigSpec
$config.name = "test9"
$config.files = New-Object VMware.Vim.VirtualMachineFileInfo
$config.files.vmPathName = "[HDD2]"
$config.latencySensitivity = New-Object VMware.Vim.LatencySensitivity
$config.latencySensitivity.level = New-Object VMware.Vim.LatencySensitivitySensitivityLevel
$config.latencySensitivity.level = ‘High’
$config.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec[] (2)
$config.deviceChange[0] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$config.deviceChange[0].operation = "add"
$config.deviceChange[0].device = New-Object VMware.Vim.ParaVirtualSCSIController
$config.deviceChange[0].device.key = -46
$config.deviceChange[0].device.busNumber = 0
$config.deviceChange[0].device.sharedBus = "noSharing"
$config.deviceChange[1] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$config.deviceChange[1].operation = "add"
$config.deviceChange[1].fileOperation = "create"
$config.deviceChange[1].device = New-Object VMware.Vim.VirtualDisk
$config.deviceChange[1].device.key = -1000000
$config.deviceChange[1].device.backing = New-Object VMware.Vim.VirtualDiskFlatVer2BackingInfo
$config.deviceChange[1].device.backing.fileName = ""
$config.deviceChange[1].device.backing.diskMode = "persistent"
$config.deviceChange[1].device.backing.split = $false
$config.deviceChange[1].device.backing.writeThrough = $false
$config.deviceChange[1].device.backing.thinProvisioned = $true
$config.deviceChange[1].device.backing.eagerlyScrub = $false
$config.deviceChange[1].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
$config.deviceChange[1].device.connectable.startConnected = $true
$config.deviceChange[1].device.connectable.allowGuestControl = $false
$config.deviceChange[1].device.connectable.connected = $true
$config.deviceChange[1].device.controllerKey = -46
$config.deviceChange[1].device.unitNumber = 0
$config.deviceChange[1].device.capacityInKB = 10485760
$VMFolderView.CreateVM($config, $ResourcePoolMoref, $null)
From the OLD ONYX – Output PowerCLI.Net
# ------- CreateVM_Task -------
$config = New-Object VMware.Vim.VirtualMachineConfigSpec
$config.name = "bbb"
$config.version = "vmx-10"
$config.guestId = "windows7Server64Guest"
$config.files = New-Object VMware.Vim.VirtualMachineFileInfo
$config.files.vmPathName = "[HDD1]"
$config.tools = New-Object VMware.Vim.ToolsConfigInfo
$config.tools.afterPowerOn = $true
$config.tools.afterResume = $true
$config.tools.beforeGuestStandby = $true
$config.tools.beforeGuestShutdown = $true
$config.tools.beforeGuestReboot = $true
$config.numCPUs = 1
$config.numCoresPerSocket = 1
$config.memoryMB = 4096
$config.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec[] (5)
$config.deviceChange[0] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$config.deviceChange[0].operation = "add"
$config.deviceChange[0].device = New-Object VMware.Vim.VirtualCdrom
$config.deviceChange[0].device.key = -44
$config.deviceChange[0].device.backing = New-Object VMware.Vim.VirtualCdromRemotePassthroughBackingInfo
$config.deviceChange[0].device.backing.deviceName = ""
$config.deviceChange[0].device.backing.exclusive = $false
$config.deviceChange[0].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
$config.deviceChange[0].device.connectable.startConnected = $false
$config.deviceChange[0].device.connectable.allowGuestControl = $true
$config.deviceChange[0].device.connectable.connected = $false
$config.deviceChange[0].device.controllerKey = 201
$config.deviceChange[0].device.unitNumber = 0
$config.deviceChange[1] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$config.deviceChange[1].operation = "add"
$config.deviceChange[1].device = New-Object VMware.Vim.VirtualFloppy
$config.deviceChange[1].device.key = -45
$config.deviceChange[1].device.backing = New-Object VMware.Vim.VirtualFloppyRemoteDeviceBackingInfo
$config.deviceChange[1].device.backing.deviceName = ""
$config.deviceChange[1].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
$config.deviceChange[1].device.connectable.startConnected = $false
$config.deviceChange[1].device.connectable.allowGuestControl = $true
$config.deviceChange[1].device.connectable.connected = $false
$config.deviceChange[2] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$config.deviceChange[2].operation = "add"
$config.deviceChange[2].device = New-Object VMware.Vim.ParaVirtualSCSIController
$config.deviceChange[2].device.key = -46
$config.deviceChange[2].device.busNumber = 0
$config.deviceChange[2].device.sharedBus = "noSharing"
$config.deviceChange[3] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$config.deviceChange[3].operation = "add"
$config.deviceChange[3].device = New-Object VMware.Vim.VirtualE1000
$config.deviceChange[3].device.key = -50
$config.deviceChange[3].device.backing = New-Object VMware.Vim.VirtualEthernetCardNetworkBackingInfo
$config.deviceChange[3].device.backing.deviceName = "Console"
$config.deviceChange[3].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
$config.deviceChange[3].device.connectable.startConnected = $true
$config.deviceChange[3].device.connectable.allowGuestControl = $true
$config.deviceChange[3].device.connectable.connected = $true
$config.deviceChange[3].device.addressType = "generated"
$config.deviceChange[3].device.wakeOnLanEnabled = $true
$config.deviceChange[4] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$config.deviceChange[4].operation = "add"
$config.deviceChange[4].fileOperation = "create"
$config.deviceChange[4].device = New-Object VMware.Vim.VirtualDisk
$config.deviceChange[4].device.key = -1000000
$config.deviceChange[4].device.backing = New-Object VMware.Vim.VirtualDiskFlatVer2BackingInfo
$config.deviceChange[4].device.backing.fileName = ""
$config.deviceChange[4].device.backing.diskMode = "persistent"
$config.deviceChange[4].device.backing.split = $false
$config.deviceChange[4].device.backing.writeThrough = $false
$config.deviceChange[4].device.backing.thinProvisioned = $true
$config.deviceChange[4].device.backing.eagerlyScrub = $false
$config.deviceChange[4].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
$config.deviceChange[4].device.connectable.startConnected = $true
$config.deviceChange[4].device.connectable.allowGuestControl = $false
$config.deviceChange[4].device.connectable.connected = $true
$config.deviceChange[4].device.controllerKey = -46
$config.deviceChange[4].device.unitNumber = 0
$config.deviceChange[4].device.capacityInKB = 10485760
$config.firmware = "bios"
$pool = New-Object VMware.Vim.ManagedObjectReference
$pool.type = "ResourcePool"
$pool.Value = "resgroup-162"
$_this = Get-View -Id 'Folder-group-v3'
$_this.CreateVM_Task($config, $pool, $null)
Using API is slightly more complicate.
However you will have access to 100% of all settings available.
Moreover, you have the possibility to create a complex VM with multiples disks in one operation.
Just think in the “lego” way.
A complex object at the end is just the association of many bricks.
Each of these bricks can also be complex object.
But at the end you will get very simple object like “number” or “string”
Even with Onyx you will still have some “homework” needed to identify what is the “_this” and the “pool”.
Regarding device.key, for each device added this must be a negative value, and all keys must be unique.
device.controllerKey = -46 The controller key property of the disk must match the device key of the controller.
It you learn how to use the API and Onyx it will pay off in the long term.
As good is the PowerCLI team is, they will never create cmdlets to handle everything.
This is not their goal neither a desirable goal. PowerCLI is supposed to handle the most common scenario.
To understand a little bit more about the “Folder” structure. Please check the following link
Folder
ServiceInstance
Everything start from the “ServiceInstance” (We will cover it in a later stage)
You will get the root folder from the service Instance
$RootFolderView = get-view -id ((get-view -id ServiceInstance).content.rootfolder)
And now check the “ChildType” and “ChildEntity” properties.
For all folders the “ChildEntity” will give you Moref of subfolders or others objects.
In fact you can create a hierarchy of folder above one or many datacenter objects.
Then each datacenter have 4 properties “VmFolder” / “HostFolder” / “DatastoreFolder” / “NetworkFolder” that are Moref pointing to hidden folder.
These 4 properties are in fact matching the different Inventory view you will get from vSphere Client or WebClient.
Everything above datacenters will be identical in the 4 inventory view.
One area is a little bit complex there are hidden folders below each datacenter.
(get-view ((Get-Datacenter “MYDATACENTER”).extensiondata.vmfolder)).name
#vm
In the same way the others hidden folders are “host” “datastore” “Network”.
The “top” root folder of a vCenter is also hidden “Datacenters”
Try it. If you use get-folder “VM” you will get the “hidden” folder AND any folder that you have created with the name “VM”
Finally you have 5 types of Folder 1 above the datacenter, 4 below datacenter one type for each view.
At this level PowerCLI is easier to use you have a different FolderType
From the API i think that the only way is to check the “ChildType”
And some objects will be present on two “views”, a VirtualApp is an object inherited from “resourcepool”…but it is also in the VirtualMachine folder.
Tips:
Never use as folder name “vm/host/datastore/network/datacenters” to avoid confusion with the hidden folders.
Understand the difference between “View” methods with or without “_task”
Get the “View” object of the virtual machine folder of the datacenter that you have used in the previous exercise and identify all methods available for this object.
Create two new VMs with the API using only the bare minimum settings (So the most simple VM without disks/Network etc)
Create a VM “VM1WithoutTask” using the method “CreateVM”
Create a VM “VM2WithTask” using the method “CreateVM_Task”
Perform the same tasks for two new VMs but this time sort the result in a variable and get the type of each variable.
“VM3WithoutTask” in variable “VM3WithoutTask”
“VM4WithTask” in variable “VM4WithTask”
Then get the Managed Object View associated to the above moref and check the type.
$FirstHost = (get-vmhost | select –first 1)
$FirstHost = get-vmhost ‘10.0.0.11’
#Below is the folder in the “VMs and Templates view” where will be created the VM
$VMFolderView = get–view –id ((get-datacenter –vmhost $FirstHost).extensiondata.VMFolder)
$VMFolderView | gm
#Now you can see the
#First we need to identify the “ComputeResource parent” of the host
$ComputeResourceView = get-view –id ($FirstHost.extensiondata.Parent)
#Then get the resource pool (actually hidden) moref associated to this standalone host.
$ResourcePoolMoref = $ComputeResourceView.resourcepool
#This is all settings necessary to create the VM
$config = New-Object VMware.Vim.VirtualMachineConfigSpec
$config.name = "VM1WithoutTask"
$config.files = New-Object VMware.Vim.VirtualMachineFileInfo
$config.files.vmPathName = "[HDD2]"
$VMFolderView.CreateVM($config, $ResourcePoolMoref, $null)
$config.name = "VM2WithTask"
$VMFolderView.CreateVM_Task($config, $ResourcePoolMoref, $null)
$config.name = "VM3WithoutTask"
$VM3WithoutTask = $VMFolderView.CreateVM($config, $ResourcePoolMoref, $null)
$config.name = "VM4WithTask"
$VM4WithTask = $VMFolderView.CreateVM_Task($config, $ResourcePoolMoref, $null)
$VM3WithoutTask.gettype().fullname
$VM4WithTask.gettype().fullname
Get-view –id $VM3WithoutTask | gm
Get-view –id $VM4WithTask | gm
Details:
If you check the API for Folder you will notice that there is a method «CreateVM_Task” but no “CreateVM”.
The “CreateVM” is a gift from the PowerCLI team.
By default, the only way to create a VM with the API is to do it in an asynchronous way.
You use “CreateVM_Task” and get the moref of the “VMware.Vim.Task”.
It will be possible to execute others PowerCLI commands just after, and if you want information about this task (Like when it will be completed) you will have to check the task.
The “CreateVM” is synchronous it means that it will execute the command and wait for the command to be completed (or fail) before executing the next commands.
Which one should you use?
I will recommend by default to use the “synchronous” version because it is easier and you will avoid affecting your infrastructure.
Like for example creating 100 VMs simultaneously than can affect storage performance.
However, the asynchronous is the way to go if you are executing long tasks that can be executed in parallel without affecting your environment.
You will find more information about how to deal with Asynchronous command in books in the appendix.
Find VM with a specific IP
I have seen this question often in the PowerCLI community.
Goal: find which vm(s) have a specific guest OS IP.
Assumption:
VMs have VMware tools installed and so you can see the guest OS IP from vCenter
Try to find the fastest way to get it with PowerCLI or the API
You will probably find many scripts using the following approach:
Export for all VMs the guest OS IP
Filter to keep only the VMs matching specifics IPs.
This approach works but it is slow.
If you have used the vSphere client you are probably, familiar with the “Search Inventory”
It is possible to use it to find matches by Virtual Machine IP address…and it is very fast.
So do we have an API to perform the same search?
Yes
Tips:
Before spending time to create a script, always spend a little bit more time to check if there is a native function that will provide you exactly what you need.
Quick note on the searchindex and the function “FindByDatastorePath”
If you are planning to use it you must know that you need to include the “hidden” folders that we have mentioned earlier in the path (But not the “datacenters” that is already at the top)
ServiceInstance probably the most critical ManagedObject
You must be connected to one and only one vCenter
Get the serviceinstance View object using get-view and store it in a variable $ServiceInstanceView
Explore the members and properties of $ServiceInstanceView
Explore the property of
$global:DefaultViServer
And
($global:DefaultViServer).extensiondata
Store the ServiceContent Object in a variable $ServiceContentView
Explore all members and check the official documentation for this object.
Create a new IP pool in the datacenter where you have created your VMs
Name test20
Subnet 10.20.20.0 /24
Gateway 10.20.20.1
Enable IP Pool
Range 10.20.20.10#15
Onyx always 😉
$ServiceInstanceView = get-view ‘serviceinstance’
$ServiceInstanceView | gm
$ServiceInstanceView | select *
$global:DefaultViServer | gm
$global:DefaultViServer |select *
($global:DefaultViServer).extensiondata | gm
($global:DefaultViServer).extensiondata | select *
The ServiceInstance is really the “top” object that you get when connecting to a vCenter or directly to a ESXi server.
If you connect directly to an ESXi server you will not get all properties and methods available in vCenter.
$ServiceContentView = $ServiceInstanceView.content
$ServiceContentView | select *
ServiceContent
Many properties of ServiceContent are related to the management of vCenter.
The rootfolder has been covered earlier
The ipPoolManager will be the one interesting for the next challenge
$IpPoolManager = get-view –id ($ServiceContentView.ipPoolManager)
$DatacenterMoref = (Get-datacenter ‘V6’).extensiondata.moref
$pool = New-Object VMware.Vim.IpPool
$pool.name = "test20"
$pool.ipv4Config = New-Object VMware.Vim.IpPoolIpPoolConfigInfo
$pool.ipv4Config.subnetAddress = "10.20.20.0"
$pool.ipv4Config.netmask = "255.255.255.0"
$pool.ipv4Config.gateway = "10.20.20.1"
$pool.ipv4Config.range = "10.20.20.10#15"
$pool.ipv4Config.dns = New-Object System.String[] (1)
$pool.ipv4Config.dns[0] = ""
$pool.ipv4Config.dhcpServerAvailable = $false
$pool.ipv4Config.ipPoolEnabled = $true
$pool.ipv6Config = New-Object VMware.Vim.IpPoolIpPoolConfigInfo
$pool.ipv6Config.subnetAddress = ""
$pool.ipv6Config.netmask = "ffff:ffff:ffff:ffff:ffff:ffff::"
$pool.ipv6Config.gateway = ""
$pool.ipv6Config.dns = New-Object System.String[] (1)
$pool.ipv6Config.dns[0] = ""
$pool.ipv6Config.dhcpServerAvailable = $false
$pool.ipv6Config.ipPoolEnabled = $false
$pool.dnsDomain = ""
$pool.dnsSearchPath = ""
$pool.hostPrefix = ""
$pool.httpProxy = ""
$IpPoolManager.CreateIpPool($DatacenterMoref, $pool)
Note: My datacenter has the name “V6” you will need to edit the script as needed for your environment
I do not think that there is any PowerCLI cmdlet to manage this area yet.
The key take away is that you will find many useful from the object referenced in ServiceContent.
Finally you could also have accessed directly the $IpPoolManager by using “get-view IpPoolManager”
There are actually many shortcuts. LUCD has created a script to get this information if you are interested available in Chapter18 of https://www.safaribooksonline.com/library/view/vmware-vsphere-powercli/9781118925119/
Onyx
# ------- CreateIpPool -------
$dc = New-Object VMware.Vim.ManagedObjectReference
$dc.type = "Datacenter"
$dc.Value = "datacenter-2"
$pool = New-Object VMware.Vim.IpPool
$pool.name = "test"
$pool.ipv4Config = New-Object VMware.Vim.IpPoolIpPoolConfigInfo
$pool.ipv4Config.subnetAddress = "10.20.20.0"
$pool.ipv4Config.netmask = "255.255.255.0"
$pool.ipv4Config.gateway = "10.20.20.1"
$pool.ipv4Config.range = "10.20.20.10#15"
$pool.ipv4Config.dns = New-Object System.String[] (1)
$pool.ipv4Config.dns[0] = ""
$pool.ipv4Config.dhcpServerAvailable = $false
$pool.ipv4Config.ipPoolEnabled = $true
$pool.ipv6Config = New-Object VMware.Vim.IpPoolIpPoolConfigInfo
$pool.ipv6Config.subnetAddress = ""
$pool.ipv6Config.netmask = "ffff:ffff:ffff:ffff:ffff:ffff::"
$pool.ipv6Config.gateway = ""
$pool.ipv6Config.dns = New-Object System.String[] (1)
$pool.ipv6Config.dns[0] = ""
$pool.ipv6Config.dhcpServerAvailable = $false
$pool.ipv6Config.ipPoolEnabled = $false
$pool.dnsDomain = ""
$pool.dnsSearchPath = ""
$pool.hostPrefix = ""
$pool.httpProxy = ""
$_this = Get-View -Id 'IpPoolManager-IpPoolManager'
$_this.CreateIpPool($dc, $pool)
We have already created VM in previous tasks.
Extract all events “Created virtual machine” using PowerCLI
If the change has been done recently you may use with PowerCLI something like this
Get-VIEvent -MaxSamples 1000 | where {$_.fullformattedMessage -match "Created virtual machine *"} | ogv
MaxSamples is by default 100. Adjust as needed.
However get-viEvent has some main issues:
If you do not select an entity it will collect ALL EVENT during the period select up to the maximum of MaxSamples so if you have multiples datacenter cluster, everything will be collected.
If you use instead the parameter “entity” and select one datacenter for example, you will get only events for this datacenter. No events related to child entities and not option to perform a recursive search.
It is not possible to search for “Created Virtual Machine” event only. You can filter by event category but this is not precise enough.
Extract all events “Created virtual machine” using API
Use get-vieventplus
With event-o-matic you will find the exact name of events you are looking for:
After connecting Event-O-Matic to your vcenter search “created virtual machine”
You will see only one event on the left “VmCreatedEvent” select it and it will be on the selected event on the right.
Click the box “Use Get-ViEvent” plus and click generate code you will get that
Get-VIEventPlus -EventType "VmCreatedEvent"
Copy the function get-vieventplus to your prompt and then execute the above command
(Or add it in your profile)
You will get a result very fast because this time we just use the API to get only event of type VmCreatedEvent
But get-vieventplus has others advantage:
You can filter on one specific entity AND use a recuse switch to get child event
Notes:
EventOMatic will not get you information about the “Task”
All tasks can be exported with:
Get-VIEventPlus -EventType "TaskEvent"
Finally get-vieventplus works with UTC time. It you want to use Start or Finish use UTC time, and result are in UTC time by default.
You can convert local time in utc in this way
$MYdate = get-date
$MyDate
$MyDate.ToUniversalTime()
Conclusion:
If you start to be lost while trying to understand how something works in the API check if someone has already done it.
If you don’t tick the “Get-VieventPlus” box you will get that
Get-VIEvent -MaxSamples ([int]::MaxValue) | Where-Object {$_ -is [VMware.Vim.VmCreatedEvent]}
This one is quite similar to the first suggested, get all events, and then filter but this time based on type and no on “full formatted message”
This will be very slow.
Execute ESXCLI command from PowerCLI
Find the PowerCLI command that provide access to ESXCLI.
Select the first ESXi host
Execute the equivalent of the esxcli command “esxcli network diag ping” with the following paraemters:
Ping VC IP address
Only 3 time
Check the result and confirm that the ping is a success
Note: You should not use the “deprecated” command
Not really needed here, just list all PowerCLI command and you will find only one related to esxcli.
$esxcli2 = Get-ESXCLI -VMHost (Get-VMhost | Select -first 1) -V2
$arguments = $esxcli2.network.diag.ping.CreateArgs()
$arguments.count = 3
#Replace below by relevant IP or DNS name of vCenter level
$arguments.host = “10.0.0.8”
($esxcli2.network.diag.ping.Invoke($arguments)).summary
Being able to use esxcli from PowerCLI is really powerful.
There were some challenges in the past with the V1 but they have been fixed with the V2.
However the PowerCLI team listen to VMware customers.
The example provided in the blog for the v1 and challenge associated is actually extracted from exchanges I got with Alan Renouf.
The V2 was the answer and it is really a good answer.
Before creating a function using esxcliv2 I invite you to check Get-EsxCli on steroids V2
This is a script that generate a PowerCLI function for every esxcli function.
You can then use for example:
(Get-VMhost | Select -first 1 | ping-EsxCLI.network.diag –host2 “10.0.0.8” –count 3).summary
PowerCLI providers
Connect to vCenter
List all “Windows PowerShell providers”
Identify the difference between the four defaults VMware PowerShell PSdrives
Copy VM logs of the first VM to a temp folder on the workstation using the VimDatastoreProvider
Disconnect from vCenter
Note:
The last task will be much more complicate if two datastores have the same name.
Do not check for it and consider that the environment is using proper naming convention avoiding duplicates datastore names.
about_vimdatastore
Get-PSDrive
Get-PSProvider
Manage Datastores Through Datastore Drives
connect-viserver “vcentername”
get-psdrive
#4 PS drive are related to VMware and based on the providers “VimInventory” or “VimDatastore”
vmstores shows all datastores available on all vSphere servers connected within the current vSphere PowerCLI session
vmstore displays the datastores available only on the last connected vSphere server
vis show all all datastores available on all vSphere servers connected within the current vSphere PowerCLI session
vis and vi follow the same logic however with a focus on the inventory of objects.
To be more precise it follows the logic presented in “Create VM with API”, so you will find as child item of a dacenter the hidden folders “vm,network,host and datastore”
You can “connect” to one of them using
set-location vis:
Then you can navigate using
get-childitem
set-location (auto completion with TAB will be useful)
For example
set-location vis:
Get-childItem
Set-location .\\IpOfVcenter@443
Set-location .\DatacenterName
etc
$FirstVM = get-vm | select -first 1
$LogDirectory = $FirstVM.ExtensionData.Config.Files.LogDirectory
$LogDirectory
#LogDirectory only contains the datastore name and not the moref.
#It means that if two datastores have the same name in the environment it will be ambigious
#Always have a good naming convention to avoid duplicate, special characters to reduce extra work later
$LogDirectorySplited = $LogDirectory.split(" ")
$DatastoreNameUnfiltered = $LogDirectorySplited[0]
$DatastoreName = $DatastoreNameUnfiltered.substring(1,$DatastoreNameUnfiltered.length -2)
#Take out the "[" and "]" around the datastore name.
$VMPathInDatastore = $LogDirectorySplited[1]
$Datastore = get-Datastore -name $DatastoreName
$DatastoreBrowserPath = $Datastore.DatastoreBrowserPath
new-PSDrive -Name "TempDatastorePSDrive" -PSProvider "VimDatastore" -Root $DatastoreBrowserPath
set-location TempDatastorePSDrive:
set-location $VMPathInDatastore
#Then you need to copy the file...using the same provider so "copy-item" doesn't seem to be an option
copy-DatastoreItem *.log C:\temp\ccalvet\
set-location C:
remove-PsDrive -name "TempDatastorePSDrive"
#Or as a shortcut
copy-DatastoreItem -item ($DatastoreBrowserPath + "\" + $VMPathInDatastore + "*.log") -Destination C:\temp2
I have seen many scripts including in the official PowerCLI guide that are based on new-psdrive and the parameter “–location”
However I do not see this parameter in the documentation of new-psdrive or while using tab for autocompletion.
I am just wondering if it has been deprecated.
I have tried to use also copy-item, as in the official PowerCLI documentation, but got the following error:
copy-Item : Source and destination path did not resolve to the same provider.
I have not investigated further on this area.
It seems to be very slow so I guess there are probably way to improve this script or adapt it to copy to a local folder on the workstation with the name of the VM.
Or use it as part of a function.
PowerCLI configuration
Establish two VIServers connection. (It can be to two separate vCenter or multiples ESXi hosts)
Check the content of $global:DefaultVIServers
Configure PowerCLI to allow only one connection at a time to a VIServer for this PowerCLI session only using PowerCLI cmdlet.
Check the content of $global:DefaultVIServers
Establish again a connection to the first VIServer
Check the content of $global:DefaultVIServers
It will be quite easy to find the relevant PowerCLI cmdlet based on the name of this exercise.
connect-viserver “FirstVIServer”
connect-viserver “SecondVIServer”
$global:DefaultVIServers
#At this stage you should have two VIServer connections.
Set-PowerCLIConfiguration –DefaultVIServerMode Single –Scope session – Confirm:$false
$global:DefaultVIServers
#At this stage you should only have the second or last VIServer connection
connect-viserver “FirstVIServer”
$global:DefaultVIServers
#At this stage you should only have the connection to the first VIServer
Configure “DefaultVIServerMode” to Single could be convenient to ensure that you are working only with one VIServer at a time.
There are also others settings that can be configured with Set-PowerCLIConfiguration if you need them.
PowerShell function and strong parameter type
Create a PowerShell function that accept only one VMHost VIobject as a parameter and return the name of the ESXi host.
Test the function with one host
Same exercise with a distributed port group and this time return the name of the distributed port group.
Test the function with one distributed port group
You will probably manage to make a function working with the VMhost
But you will have issues with the Distributed Port Group…this is exactly the purpose of this exercise.
function check-vmhost{
param(
[VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost]$VMhost
)
Process{
$VMhost.name
}
}
Check-vmhost –vmhost (get-vmhost | select –first 1)
function check-VDPortgroup{
param(
[VMware.VimAutomation.Vds.Types.V1.VmwareVDPortgroup]$VDPortgroup
)
Process{
$VDPortgroup.name
}
}
Check-VDPortgroup –VDPortgroup (get-vdportgroup | select –first 1)
The classic error here is to get the type of an object and use it as a strong parameter for the function.
For example:
(get-vmhost | select –first 1).GetType().fullname
You will get for the two exercise
VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl
VMware.VimAutomation.Vds.Impl.V1.VmwareVDPortgroupImpl
However if you try to use them as a strong type parameter for your function
VMware.VimAutomation.ViCore.Impl.V1.Inventory.VMHostImpl OK
VMware.VimAutomation.Vds.Impl.V1.VmwareVDPortgroupImpl Fail with the error:
Unable to find type [VMware.VimAutomation.Vds.Impl.V1.VmwareVDPortgroupImpl].
You should use instead:
VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost OK
VMware.VimAutomation.Vds.Types.V1.VmwareVDPortgroup OK
More details here:
https://blogs.vmware.com/PowerCLI/2016/04/powercli-best-practice-correct-use-strong-typing.html
Take Away:
If you want to create a future proof function never use an “Impl” type as a strong parameter.
List tag category with PowerCLI
Using only PowerCLI cmdlet
Create two new TAG category “TagCategoryTest” and “TagCategoryTest2”
List all TAG category using PowerCLI
New-TagCategory –name “TagCategoryTest”
New-TagCategory –name “TagCategoryTest2”
Get-TagCategory | ogv
Is is quite easy to manipulate Tag with the PowerCLI tags cmdlets.
Actually using these PowerCLI cmdlets was the only way to automatize TAG related tasks in the past.
List tag category with API and vCloud Suite
#Pre requisite vSphere 6
List all TAG category without using any of the following PowerCLI cmdlet
Get-Tag / Get-TagAssignment / Get-TagCategory
Connect-CisServer -Server “yourVC”
#Optional to list all cloud service you can work with
#get-CisService | ogv
$TagCategory = Get-CisService "com.vmware.cis.tagging.category”
$AllTagCategoryURN = $TagCategory.list().value
$AllTagCategoryURN | ForEach-Object {$TagCategory.get($_)} | ogv
Disconnect-CisServer * -Confirm:$false
The take away is that among other things TAG and Content Library are managed at the “vCloud Suite” and not at the “vSphere Management” level.
Moreover in order to extract information or perform change it will be necessary to use CisService.
Note:
CisServer has also the concept of $global:DefaultCisServers very similar to $global:defaultViServers
vCloud director
For this one you need to have access to vCloud director. There are not so many people who have access to this product since it is now only available for cloud provider.
Connect to cloud director
List all organization using PowerCLI cmdlet
Check the content of $global:DefaultCiServers
Explore .extensiondata of a default CIServer
List all organization using a method and not a PowerCLI cmdlet
Disconnect from cloud director
Sample Scripts for Managing vCloud Director with VMware vCloud Director PowerCLI
Connect-CIServer «vcloud server name»
get-org | ogv
$global:DefaultCiServers
$CiServer = $global:DefaultCiServers | select –first 1
$CiServer.extensiondata | gm
$CiServer.GetOrg().org | ogv
Disconnect-ciserver
It is possible to connect to cloud director, and you have many PowerCLI cmdlets already available to perform the most standard tasks.
Using the extensiondata you have also access to others methods but it doesn’t seem to be all methods available with API.
vRealize Operations Manager
For this one you need to have access to vROPS that is collecting performance metrics of an ESXi host.
Connect to vRops
Connect to the VC where is located the ESXi host
Extract for the first host the following performance metric CPU > Usage(%) for the last day with PowerCLI cmdlets.
Explore the content of $global:DefaultOMServers
Explore the extensiondata of the first OMServer
Obtain the license keys of the products
Disconnect from Vrops and vCenter
Sample Scripts for Managing vRealize Operations Manager with VMware vSphere PowerCLI
http://blogs.vmware.com/PowerCLI/2016/05/working-recommendations-statistics-vr-ops-powercli.html
http://blogs.vmware.com/PowerCLI/2016/05/using-entire-api-vrealize-operations-via-powercli.html
Connect-viServer "VCenterName"
Connect-OMServer "OPSServerName"
#Maybe you will to specify the AuthSource
#Connect-OMServer "OPSServerName" -AuthSource "VCenterName"
#Optional List All metrics for HostSytem
# get-omstatkey | where {$_.ResourceKind -eq "hostsystem" } | ogv
$OMStatKey = Get-OMStatKey -Name "cpu|workload" -ResourceKind "hostsystem"
$OMResource = Get-OMResource –entity (get-vmhost | select –first 1)
$FinishDate = get-date
$StartDate = $FinishDate.AddDays(-1)
$OmStat = Get-OMStat -resource $OMResource -Key $OMStatKey -from $StartDate -to $FinishDate
$OmStat | ogv
$OMServer = $global:DefaultOMServers[0]
$OMServer.extensiondata | gm
$OMServer.extensiondata.GetLicenseKeysForProduct().solutionlicense | ogv
Disconnect-Omserver
Disconect-ViServer
vRealize Operations Manager is really powerful.
The PowerCLI team has provided useful cmdlets for the most common operations.
On top of that if needed it is possible to access the entire API using “extensiondata”
http://blogs.vmware.com/PowerCLI/2016/05/using-entire-api-vrealize-operations-via-powercli.html
vCenter Site Recovery Manager
Connect to the vCenter server with VMs protected by SRM
Connect to SRM
Explore the content of $global:DefaultSrmServers
Explore the extensiondata of the first SrmServer
Get the name of all protected virtual machines
Disconnect SRM
Disconnect vCenter
Sample Scripts for Managing vCenter Site Recovery Manager with VMware vSphere PowerCLI
connect-viserver «vCenterServer»
connect-SrmServer “SRMServer”
$global:DefaultSrmServers
$SrmServer = $global:DefaultSrmServers[0]
$VirtualMachineProtectedMoref = $SrmServer.ExtensionData.Protection.ListProtectedVms().moref
$VirtualMachineProtectedMoref | ForEach-Object { (get-view ($_)).name} | ogv
Disconnect-SrmServer
Disconnect-Viserver
SRM is definitely one of the VMware product that benefits the most from automatization.
It is critical to have a consistent “view” between SRM and the VMware infrastructure protected and PowerCLI will help to identify mismatch.
It seems that the extensiondata provides access to the whole SRM API.
vCloud Air Server
I didn’t have the opportunity to test vCloud Air yet, so there will be no answers for this exercise.
Connect to vCloud Air
Identify what you can do with PowerCLI cmdlets.
Identify if there is anything interesting in extensiondata of PIserver object.
Disconnect from vCloud Air
Get-VICommand | where {$_.name -like “*-PI*”}
Managing vCloud Air with VMware vCloud Air PowerCLI
Conclusion
That’s it, you now know how to “think PowerCLI”
All the key concepts unique to PowerCLI have been presented.
You should also know now how to search in the documentation and use Onyx.
If you were already proficient in PowerShell, and if you know already VMware, this is all you need to handle any challenges.
What’s next?
Now you only need to practice to gain more experience.
I will recommend at the beginning to try to handle any new challenge in the same way as recommended for all exercises.
Try alone using official documentation, Onyx, and a test environment.
It will provide you the skills needed to create a script from scratch if needed.
After a while, you will reach a level of confidence where you will know that you can handle any challenge … as long as you have enough time in front of you.
This is where you will need to start to use existing scripts
It will be much faster to find, judge the quality, and adapt existing scripts than creating your own.
This is also where the “Receipe books” will be very useful, they will help you to kick start your own scripts.
There are also many areas that have not been covered in this training.
It is possible to nearly automatize all areas of VMware but not necessary with PowerCLI.
Connect to CIM of an ESXi server
Use REST to manage many products – Refers to recommend book
Automatize the installation of PowerCli or vCenter on Windows – Refers to recommend book
You can call from PowerShell putty to execute Linux command
etc
Regarding Rest you will have sometimes the options to pick between working with REST or via PowerCLI
This is the case for the vCloud Suite for example, you can use what has been described in this course or the vCloud Suite SDK for REST.
You will get more information about the others SDKS not necessary linked to PowerCLI in the Developer Center
If you would like to reach the guru level you can follow the advices in this guide:
PowerCLI study guide from rookie to guru
And to stay up to date always check if there is a new PowerCLI release available.
Appendix
Onyx
There are two versions of Onyx
Old Onyx:
Onyx
It works only with vSphere client, it means that you will not be able to capture settings that you can only configure from the vSphere Web Client.
Pro:
Easy to use and set up
No need to perfom any change at the vCenter level.
Con:
Only compatible with vSphere Client. Not possible to capture settings only available in WebClient.
New Onyx:
Onyx for the web client
Pro:
Compatible with Web Client and all settings only available with it
Con:
More complicated to setup
Change needed at the vCenter level
I have not tested yet the new Onyx due to the constraint at the vCenter level.
I will only recommend it in a test environment but it limits what you will be able to capture if your test environment doesn’t have all specifications of a production environment.
I use the following workaround with the old Onyx:
Execute the closest command to what I need.
Edit the output based on the official documentation to add all settings “unique” to vSphere 6.
Reference poster
VMware vSphere PowerCLI 6.3 Release 1 Reference Poster
Books recommended
Beginner:
Learning PowerCLI – February 2014
PowerCLI cookbook – March 2015
Advanced:
VMware vSphere PowerCLI Reference – January 2016
Mastering PowerCLI – October 2015
VMware VI and vSphere SDK: Managing the VMware Infrastructure and vSphere
I strongly recommend the VMware vSphere PowerCLI reference, even if the title is misleading.
It describes how to automate many areas of VMware but not only with PowerCLI.
Read all books.
They will often contain similar information but it is a good way to learn different way to achieve the same result.
Blogs recommended
VMware PowerCLI Blog
LucD notes
virtuallyGhetto
virtu-al.net
The list will probably evolves in the future I just end up very often on these blogs while looking for information.
Pingback: PowerCLI study guide – core concepts | Yogesh