This isn't a question, so much as pointing out a current issue with Get-VM. Depending on how you use it to query VM objects (by name only or by location (via pipeline or -Location <object>), you get a different object type. (Note that this only applies to VMs. I didn't observe the same type of issue with other objects, such as VMHosts or Clusters.)
The following was done using VMware.VimAutomation.Core 12.6.0.19601570 on vCenter 7.0.3:
> $VMObjs = Get-VM -Server $VIConnection
> $VMObjs[0].GetType().Name
UniversalVirtualMachineImpl
> $VMObjs[0] | Get-Member
TypeName: VMware.VimAutomation.ViCore.Impl.V1.VM.UniversalVirtualMachineImpl
<snip>
> $VMObjs = Get-VM -Server $VIConnection -Location (Get-VMHost -Server $VIConnection)
> $VMObjs[0].GetType().Name
VirtualMachineImpl
> $VMObjs[0] | Get-Member
TypeName: VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl
<snip>
> $VMObjs = Get-VMHost -Server $VIConnection | Get-VM
> $VMObjs[0].GetType().Name
VirtualMachineImpl
> $VMObjs[0] | Get-Member
TypeName: VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl
<snip>
As such, I would suggest that anyone writing a function that requires a -VM parameter save themselves some frustration and do something like this:
param (
[Parameter (
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
Mandatory = $true
)]
[ValidateScript(
{
$_.GetType().Name -in "VirtualMachineImpl", "UniversalVirtualMachineImpl"
}
)]
[ValidateNotNullOrEmpty()]
[Object[]]$VM
)
Not if you use that type, but have a look at PowerCLI Best Practice: Correct Use of Strong Typing
Following those guidelines, my test function works in both cases.
function Invoke-Test {
param(
[VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]$vm
)
$vm.Name
}
Invoke-Test -VM (Get-VM -Name MyVM)
Invoke-Test -VM (Get-VM -Name MyVM -Location (get-VMHost -Name MyEsx))
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Why the validation script?
You can just define the type, one is a subclass of the other, so you should be fine.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Alas, that is not the case, @LucD
> $VMObjs[0].GetType().Name
VirtualMachineImpl
> function Invoke-TestFunction {
>> [CmdletBinding()]
>>
>> Param (
>> [Parameter (
>> ValueFromPipeline = $true,
>> ValueFromPipelineByPropertyName = $true,
>> Mandatory = $true
>> )]
>> [ValidateNotNullOrEmpty()]
>> [VMware.VimAutomation.ViCore.Impl.V1.VM.UniversalVirtualMachineImpl[]]$VM
>> )
>>
>> process {
>> foreach ($VMObj in $VM) {
>> Write-Output $VMObj.Name
>> }
>> }
>> }
> Invoke-TestFunction -VM $VMObjs
Invoke-TestFunction : Cannot process argument transformation on parameter 'VM'. Cannot convert the
"vCLS-<random chars>" value of type
"VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl" to type
"VMware.VimAutomation.ViCore.Impl.V1.VM.UniversalVirtualMachineImpl".
At line:1 char:25
Not if you use that type, but have a look at PowerCLI Best Practice: Correct Use of Strong Typing
Following those guidelines, my test function works in both cases.
function Invoke-Test {
param(
[VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]$vm
)
$vm.Name
}
Invoke-Test -VM (Get-VM -Name MyVM)
Invoke-Test -VM (Get-VM -Name MyVM -Location (get-VMHost -Name MyEsx))
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
...and yes, the same thing in reverse produces the same error, @LucD
> function Invoke-TestFunction {
>> [CmdletBinding()]
>>
>> Param (
>> [Parameter (
>> ValueFromPipeline = $true,
>> ValueFromPipelineByPropertyName = $true,
>> Mandatory = $true
>> )]
>> [ValidateNotNullOrEmpty()]
>> [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl[]]$VM
>> )
>>
>> process {
>> foreach ($VMObj in $VM) {
>> Write-Output $VMObj.Name
>> }
>> }
>> }
> $VMObjs[0].GetType().Name
UniversalVirtualMachineImpl
> Invoke-TestFunction -VM $VMObjs
Invoke-TestFunction : Cannot process argument transformation on parameter 'VM'. Cannot convert the
"VMNAME" value of type "VMware.VimAutomation.ViCore.Impl.V1.VM.UniversalVirtualMachineImpl"
to type "VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl".
At line:1 char:25
+ Invoke-TestFunction -VM $VMObjs
+ ~~~~~~~
+ CategoryInfo : InvalidData: (:) [Invoke-TestFunction], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Invoke-TestFunction
What version of PowerCLI (VMware.VimAutomation.Core) and PowerShell are you using? While, this could be an issue with Windows PowerShell vs. PowerShell Core, I am a bit concerned that Get-VM produces multiple object types.
Did you read my last reply?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I did, @LucD I just didn't catch that the difference between
VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine
and
VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl
All right. That works. Much cleaner parameter definition.
I note that the linked blog article only discusses VM Objects. I suppose that's fine since this is only an issue for them. In all other cases, just getting the type from Get-Member works just fine. That said, a full list of object types would probably be a good resource to have for folks. (Not suggesting you do it; just musing.)
Thanks for the assist.
Edit: Apparently, VMware has actually provided such a resource already:
https://developer.vmware.com/docs/powercli/latest/products/vmwarevsphereandvsan/all-structures/
That strong type rule works for most objects, replace Impl by Types and drop the Impl suffix.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference