Hi Everyone,
I have a little job that I would like your help with. I am quite new to powercli side of things etc (Apologies if I posted in wrong forum, but couldn't see a more relevent one)
I have an estate of approx 1,400 clients that I need to get the version for because I suspect a lot of them are severely out of date.
Now there is a useful script that reports this that I got from philthevirtualiser.com as below. On my own test rig with a few VMs it works fine . However I don't want to clobber the Vcenter server with a request for tools versions from over 1400 clients at once. Therefore what would be useful if I could get a list of the servers and then just run the query, one machine at a time with a small pause. Where do I start modifying the below script ?
Any help appreciated.
01 # Add in the VI Toolkit goodness |
02 | if ( ( Get-PSSnapin -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) -eq $null ) |
03 | { |
04 | Add-PSsnapin VMware.VimAutomation.Core |
05 | } |
06 |
07 | # Connect to the vCenter server(s) |
08 | $vcserver = @() |
09 |
10 | $vcserver += connect -VIServer "<Your vCenter Server>" |
11 |
12 | # get the vmware tools version for each VM |
13 |
14 | get -vm |% { get -view $_.id } | select Name, @{ Name= "ToolsVersion" ; Expression={$_.config.tools.toolsVersion}} |
15 |
16 | # Disconnect from the vCenter server(s) |
17 | disconnect -viserver $vcserver -Confirm : $False |
18 |
19 | # END |
20 | ### |
I think that doing the Get-VM for each individual guest will clobber your vCenter more than doing it for all the guests in one go.
But the following should put a little bit less strain on the vCenter
# Add in the VI Toolkit goodness
if ( (Get-PSSnapin -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) -eq $null )
{
Add-PSsnapin VMware.VimAutomation.Core
}
# Connect to the vCenter server(s)
$vcserver = connect-VIServer "<Your vCenter Server>"
# get the vmware tools version for each VM
get-vm |%{
$_ | Select Name, @{Name="ToolsVersion"; Expression={$_.Extensiondata.config.tools.toolsVersion}}
sleep 1
}
# Disconnect from the vCenter server(s)
disconnect-viserver $vcserver -Confirm:$False
Instead of the Get-View cmdlet, the script uses the Extensiondata property.
This will still cause a call to the vCenter, but will require less data to be returned, so less traffic from the vCenter.
And after each Select the script pauses for 1 second.
If you don't think that is needed, just remove that line.
An even better method would be to use the New-VIProperty cmdlet.
Something like this
New-VIProperty -Name ToolsVersion -ObjectType VirtualMachine `
-ValueFromExtensionProperty 'config.tools.ToolsVersion' `
-Force
# Add in the VI Toolkit goodness
if ( (Get-PSSnapin -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue) -eq $null )
{
Add-PSsnapin VMware.VimAutomation.Core
}
# Connect to the vCenter server(s)
$vcserver = connect-VIServer "<Your vCenter Server>"
# get the vmware tools version for each VM
get-vm |%{
$_ | Select Name, ToolsVersion
sleep 1
}
# Disconnect from the vCenter server(s)
disconnect-viserver $vcserver -Confirm:$False
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hello, LucD-
Looks like there needs to be one additional item in the Select portion of each of those methods. Since the Select is inside of a Foreach-Object loop, it is not receiving any object from a pipeline, so we need to specify the InputObject like:
Select -InputObject $_ Name, @{Name="ToolsVersion"; Expression={$_.Extensiondata.config.tools.toolsVersion}}
and
Select -InputObject $_ Name, ToolsVersion
,respectively. I noticed that as I was trying to think of another way to optimize this for lowest impact to vCenter (as requested) and for highest speed, and it was not working for me as written.
Then, as I tested, I wondered if the Sleep in the Foreach-Object loop is doing anything to lessen the impact on the vCenter server. The query has already been executed at that point, and the object being reported about is already in the client's PowerShell session, is it not? That is, after the initial Get-VM, there is no more communication with the vCenter server during the Select, right? If so, the Sleep is not affecting the vCenter load.
As for another way to try to help lessen the impact on vCenter, I wrote the info-gathering portion of the script using Get-View instead of Get-VM and New-VIProperty, as such:
...
## get the VMware Tools version for each VM
Get-View -ViewType VirtualMachine -Property Name,Config.Tools.ToolsVersion,Config.Template -Filter @{"Config.Template" = "false"} | Select Name, @{n="ToolsVersion"; e={$_.Config.Tools.ToolsVersion}}
...
Basically, that is your first method, but using Get-View instead of Get-VM, and with no Sleep. For about 2600 VMs that took about 11 seconds. The shortened run time should help lower impact, shouldn't it?
Message was edited by: mattboren -- added summary after "new" code snippet
Hi Matt,
you don't need to retrieve the Config.Template value in the Get-View properties. This will make the script faster. And we go for maximum speed, don't we.
Get-View -ViewType VirtualMachine -Property Name,Config.Tools.ToolsVersion -Filter @{ "Config.Template" = "False"} | ` Select-Object Name,@{N="ToolsVersion"; E={$_.Config.Tools.ToolsVersion}}
This script runs in my environment with about 500 virtual machines in 1.7 seconds. So I would not wurry about that.
Regards, Robert
Message was edited by: RvdNieuwendijk
I'm not on a computer with PowerShell at the moment, but if you don't gather the .Config.Template property in the Get-View statement, how can you filter on it? Seems like it may always return $false ($null) to me and therefore gather templates as well. Of course, I'd argue why we're excluding templates in the first place since they could have VMware Tools installed and out-of-date too.
Hi Allen,
the Get-View cmdlet does the filtering before the selection is made. You can easily test this with the following two commands, that both give the same result:
Get-View -ViewType VirtualMachine -Filter @{"Config.Template" = "False"} | Measure-Object Get-View -ViewType VirtualMachine -Property Name -Filter @{"Config.Template" = "False"} | Measure-Object
This is why you dont have to specify Config.Template in the property list.
I must agree though that it makes sense to also retrieve the tools version for templates as templates need to be updated some times as well. In this case the script will be:
Get-View -ViewType VirtualMachine -Property Name,Config.Tools.ToolsVersion | ` Select-Object Name,@{N="ToolsVersion"; E={$_.Config.Tools.ToolsVersion}}
Regards, Robert
Hello, Robert-
Thanks for pointing out that we need not retrieve the property that we are filtering on (unless using that property later on). I was surely slowing things down with retrieving the extra property unnecessarily.
Yes, max speed!