Can someone please explain this
$vmname = get-vm vm
get-view -id $vmname.id
--------------------------------------------------------------------------------------------------------------------------
Capability : VMware.Vim.VirtualMachineCapability
Config : VMware.Vim.VirtualMachineConfigInfo
Layout : VMware.Vim.VirtualMachineFileLayout
LayoutEx : VMware.Vim.VirtualMachineFileLayoutEx
Storage : VMware.Vim.VirtualMachineStorageInfo
EnvironmentBrowser : EnvironmentBrowser-envbrowser-56698
ResourcePool : ResourcePool-resgroup-56694
ParentVApp :
ResourceConfig : VMware.Vim.ResourceConfigSpec
Runtime : VMware.Vim.VirtualMachineRuntimeInfo
Guest : VMware.Vim.GuestInfo
Summary : VMware.Vim.VirtualMachineSummary
Datastore : {Datastore-datastore-56696}
Network : {Network-network-386}
Snapshot :
RootSnapshot : {}
GuestHeartbeatStatus : gray
LinkedView :
Parent : Folder-group-v395
CustomValue : {}
OverallStatus : green
ConfigStatus : green
ConfigIssue : {}
EffectiveRole : {-1}
Permission : {}
Name : aus-test
DisabledMethod : {MakePrimaryVM_Task, TerminateFaultTolerantVM_Task, RevertToCurrentSnapshot_Task,
RemoveAllSnapshots_Task...}
RecentTask : {}
DeclaredAlarmState : {alarm-10.vm-56698, alarm-11.vm-56698, alarm-2.vm-56698, alarm-23.vm-56698...}
TriggeredAlarmState : {}
AlarmActionsEnabled : True
Tag : {}
Value : {}
AvailableField : {}
MoRef : VirtualMachine-vm-56698
Client : VMware.Vim.VimClientImpl
-----------------------------------------------------------------------------------------------------------------------------------
but
get-view -viewtype virtualmachine -filter @{"name" = $vmname}
PS C:\Users\tkw\scripts> get-view -ViewType virtualmachine -filter @{"name" = $vmname}
get-view : 9/20/2015 9:00:13 AM Get-View Invalid object specified for the Filter parameter - 'Hashtable{String,
VirtualMachineImpl}'. Filter accepts objects of type 'Hashtable{String, String}'.
At line:1 char:1
+ get-view -ViewType virtualmachine -filter @{"name" = $vmname}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (System.Collections.Hashtable:Hashtable) [Get-View], VimException
+ FullyQualifiedErrorId : Core_GetVIView_TryGetFilterParam_InvalidValue,VMware.VimAutomation.ViCore.Cmdlets.Commands.Do
tNetInterop.GetVIView
any idea?
Hello, tdubb123-
Sure. While you could use a Foreach-Object scriptblock to call Get-View for every VM in the cluster, since everyone likes faster things, you can use just one Get-View call. Like:
## get the VMs in the given cluster, put them in a variable, then get the Views
$vms = Get-Cluster $cluster | Get-VM
Get-View -Id $vms.Id
And, you don't really need to store the VirtualMachineImpl objects from Get-VM in a variable -- you can just get their ID properties and use those directly for Get-View, like:
## just get the Views of the IDs of the VMs in the given cluster
Get-View -Id (Get-Cluster $cluster | Get-VM).Id
But, since speed is often of concern, especially as the virtual inventory is larger, getting away from the Get-VM call altogether will be of great value. Get-View has a -SearchRoot parameter that allows you to specify the inventory location to use as the root of the search, like:
## get the VirtualMachine Views at the given search root
Get-View -ViewType VirtualMachine -SearchRoot (Get-Cluster $cluster).Id
And, to keep things efficient, since you likely will only want to use a few choice properties of the VirtualMachine View objects, you can further speed things along by specifying just those properties that you want to retrieve from the vCenter server, keeping memory usage in your PowerShell session lower, too. Like:
## get the VirtualMachine Views at the given search root, retrieving just the select few properties
Get-View -ViewType VirtualMachine -Property Name, Config.Hardware -SearchRoot (Get-Cluster $cluster).Id
A bit more involved to write, so you might chose the first couple of examples when issuing the commands interactively. But, if you are writing a script where you care more about the run duration, or have a huge environment (or both), the last example is the winner.
How does those do for you?
ok what is the difference here?
get-view -viewtype virtualmachine -filter @{"name" = "$vmname"}
and
get-view -id $vmname.id
Hello, tdubb123-
The issue is with the value that you are providing for the "Name" key in the -Filter hashtable in the Get-View call -- the value should be a string, but you are using a VirtualMachineImpl object. The error that you are getting:
Invalid object specified for the Filter parameter - 'Hashtable{String,VirtualMachineImpl}'. Filter accepts objects of type 'Hashtable{String, String}'
tries to point that out. That is to say, $vmname is not a String -- it is the entire VirtualMachineImpl object returned from Get-VM. So, to use that variable in the Filter in the Get-View call, you would need to access the .Name property of the variable. Like:
Get-View -ViewType VirtualMachine -Filter @{"Name" = $vmname.Name}
And, maybe to help avoid such confusion, naming that variable "$vm" or the likes would be better, since the contents of the variable are not just the VM's name, but the whole VM object.
That work for you?
Hello-
Here you got around the "supplying a VirtualMachineImpl as the value to the Name key in the Get-View Filter" by getting the String value of $vmname. Again, $vmname in your example is a VirtualMachineImpl object. So, if you look at the contents of that variable, you should see a full virtual machine object, like:
Name PowerState Num CPUs MemoryGB ---- ---------- -------- -------- myVM0 PoweredOff 1 1.000
But, by adding quotes around the variable, you are creating a string, and the .ToString() method of the $vmname variable is invoked, which results in just the String value that is the name of the VM. That set of quotes around $vmname in the Filter hashtable is the difference between this post and your original post, and the reason why both of your examples in this "what is the difference here" post work.
As for what is the difference:
Another difference: the first example might get more than one VirtualMachine object, whereas the second example should get exactly one VirtualMachine object (assuming that you are connected to only one vCenter, and that a VirtualMachine with that ID still exists).
The reason that the first example might return multiple VirtualMachine objects is that the filter is using regular expression matching on the name pattern that you supplied as a value to the "Name" key. So, the regular expression of "myVM0" matches, of course, "myVM0", but also matches "myVM01", "myVM0_old", "do_not_use_this_vm_myVM0", and so on.
Make sense?
Hi Matt
Thanks for your detailed explanation. It does makes sense.
I have another example.
$vms = get-cluster AUS | get-vm
output gives this
PS C:\Users\tkw\scripts> get-cluster AUS | get-vm
Name PowerState Num CPUs MemoryGB
---- ---------- -------- --------
aus-dc (2) PoweredOn 1 4.000
aus-dfs (2) PoweredOn 2 4.000
aus-w7 PoweredOn 1 2.000
astris2 (2) PoweredOn 2 3.996
aus-svcs (2) PoweredOn 1 4.000
aus-test PoweredOn 2 4.000
----------------------------------------------------------------------------------------------
but
foreach ($vmname in $vms) {
get-view -viewtype virtualmachine -filter @{"name" = $vmname.name
}
gives only output of 2 vms
Capability : VMware.Vim.VirtualMachineCapability
Config : VMware.Vim.VirtualMachineConfigInfo
Layout : VMware.Vim.VirtualMachineFileLayout
LayoutEx : VMware.Vim.VirtualMachineFileLayoutEx
Storage : VMware.Vim.VirtualMachineStorageInfo
EnvironmentBrowser : EnvironmentBrowser-envbrowser-56705
ResourcePool : ResourcePool-resgroup-56694
ParentVApp :
ResourceConfig : VMware.Vim.ResourceConfigSpec
Runtime : VMware.Vim.VirtualMachineRuntimeInfo
Guest : VMware.Vim.GuestInfo
Summary : VMware.Vim.VirtualMachineSummary
Datastore : {Datastore-datastore-56696}
Network : {Network-network-386}
Snapshot :
RootSnapshot : {}
GuestHeartbeatStatus : green
LinkedView :
Parent : Folder-group-v395
CustomValue : {}
OverallStatus : green
ConfigStatus : green
ConfigIssue : {}
EffectiveRole : {-1}
Permission : {}
Name : aus-w7
DisabledMethod : {Destroy_Task, UnregisterVM, RevertToCurrentSnapshot_Task, RemoveAllSnapshots_Task...}
RecentTask : {Task-task-132122}
DeclaredAlarmState : {alarm-10.vm-56705, alarm-11.vm-56705, alarm-2.vm-56705, alarm-23.vm-56705...}
TriggeredAlarmState : {}
AlarmActionsEnabled : True
Tag : {}
Value : {}
AvailableField : {}
MoRef : VirtualMachine-vm-56705
Client : VMware.Vim.VimClientImpl
Capability : VMware.Vim.VirtualMachineCapability
Config : VMware.Vim.VirtualMachineConfigInfo
Layout : VMware.Vim.VirtualMachineFileLayout
LayoutEx : VMware.Vim.VirtualMachineFileLayoutEx
Storage : VMware.Vim.VirtualMachineStorageInfo
EnvironmentBrowser : EnvironmentBrowser-envbrowser-56698
ResourcePool : ResourcePool-resgroup-56694
ParentVApp :
ResourceConfig : VMware.Vim.ResourceConfigSpec
Runtime : VMware.Vim.VirtualMachineRuntimeInfo
Guest : VMware.Vim.GuestInfo
Summary : VMware.Vim.VirtualMachineSummary
Datastore : {Datastore-datastore-56696}
Network : {Network-network-386}
Snapshot :
RootSnapshot : {}
GuestHeartbeatStatus : green
LinkedView :
Parent : Folder-group-v395
CustomValue : {}
OverallStatus : green
ConfigStatus : green
ConfigIssue : {}
EffectiveRole : {-1}
Permission : {}
Name : aus-test
DisabledMethod : {Destroy_Task, UnregisterVM, RevertToCurrentSnapshot_Task, RemoveAllSnapshots_Task...}
RecentTask : {Task-task-132120}
DeclaredAlarmState : {alarm-10.vm-56698, alarm-11.vm-56698, alarm-2.vm-56698, alarm-23.vm-56698...}
TriggeredAlarmState : {}
AlarmActionsEnabled : True
Tag : {}
Value : {}
AvailableField : {}
MoRef : VirtualMachine-vm-56698
Client : VMware.Vim.VimClientImpl
any idea why?
whereas if I used
get-view -id $vmname.id
it gives output of all 6 vms. is this because of the the "-filter" switch?
can you help with this?
$vms = get-cluster $cluster | get-vm
$vms | % {
$vmname = $_.name
$vmview = get-view -id $vmname
how do I get a get-view of these vms ?
Hello-
Good.
As for why using -Filter for Name only returns four of those six VMs: this is because of the fact that the value for the Name key is a regular expression pattern, and that some of your VMs have characters that mean something different in the context of a regular expression. Specifically, the parenthesis are grouping construct characters in the regular expression context. You can read about such things at MSDN Regular Expression Reference.
You can see the behavior in the example:
PS C:\> "aus-dc (2)" -match "aus-dc (2)" False
So, if you wanted to actually match by name, then you could escape those special characters in the string manually, or use the Escape() static method of the System.Text.RegularExpressions.Regex .NET class. The behavior is then probably more like what you are expecting:
PS C:\> "aus-dc (2)" -match [Regex]::Escape("aus-dc (2)") True
Adding the [Regex]::Escape() in the Filter like "...-Filter @{'Name' = [Regex]::Escape($vmname.name)}" would get closer to the behavior that you are expecting (but, again, the regular expression that you are using may match longer strings that contain the pattern that you are specifying).
There are other, more precise ways to get the View objects. I'll reply to your latest post here with more info on that.
Hello, tdubb123-
Sure. While you could use a Foreach-Object scriptblock to call Get-View for every VM in the cluster, since everyone likes faster things, you can use just one Get-View call. Like:
## get the VMs in the given cluster, put them in a variable, then get the Views
$vms = Get-Cluster $cluster | Get-VM
Get-View -Id $vms.Id
And, you don't really need to store the VirtualMachineImpl objects from Get-VM in a variable -- you can just get their ID properties and use those directly for Get-View, like:
## just get the Views of the IDs of the VMs in the given cluster
Get-View -Id (Get-Cluster $cluster | Get-VM).Id
But, since speed is often of concern, especially as the virtual inventory is larger, getting away from the Get-VM call altogether will be of great value. Get-View has a -SearchRoot parameter that allows you to specify the inventory location to use as the root of the search, like:
## get the VirtualMachine Views at the given search root
Get-View -ViewType VirtualMachine -SearchRoot (Get-Cluster $cluster).Id
And, to keep things efficient, since you likely will only want to use a few choice properties of the VirtualMachine View objects, you can further speed things along by specifying just those properties that you want to retrieve from the vCenter server, keeping memory usage in your PowerShell session lower, too. Like:
## get the VirtualMachine Views at the given search root, retrieving just the select few properties
Get-View -ViewType VirtualMachine -Property Name, Config.Hardware -SearchRoot (Get-Cluster $cluster).Id
A bit more involved to write, so you might chose the first couple of examples when issuing the commands interactively. But, if you are writing a script where you care more about the run duration, or have a huge environment (or both), the last example is the winner.
How does those do for you?
Hi Matt
makes sense. thanks. great explanation. very much appreciated.
is there a difference here
$vms = get-cluster | get-pvm
$vms | %{
or
foreach ($vm in $vms) {
thanks
Hello, tdubb123-
Great, glad to hear it.
As for the difference: the first way is using the Foreach-Object cmdlet (its alias, "%"), whereas the second uses the PowerShell foreach loop. While you can achieve similar (the same?) things with each construct, they do differ in things like efficiency and speed, and in the way that they emit objects. The Foreach-Object cmdlet will place resulting objects on the pipeline for further consumption, whereas the foreach statement does not.
Boe Prox made an informative post on the Hey, Scripting Guy! Blog: Getting to Know ForEach and ForEach-Object. That gets into the topics of speed, pipeline, and more. Give that a look see for some deeper info on the topic.