Function PowerShell高级函数输出PipelineVariable不';行不通

Function PowerShell高级函数输出PipelineVariable不';行不通,function,powershell,pipeline,cmdlet,Function,Powershell,Pipeline,Cmdlet,我创建了一个高级函数,用于从运行在VMware ESXi上的VM获取mac地址 function Get-MacFromVm { [CmdletBinding(SupportsShouldProcess=$true)] Param( # The name of the VM of which we want to obtain the mac address. [Parameter(Mandatory=$true,

我创建了一个高级函数,用于从运行在VMware ESXi上的VM获取mac地址

function Get-MacFromVm {
    [CmdletBinding(SupportsShouldProcess=$true)]
    Param(
        # The name of the VM of which we want to obtain the mac address.
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true)]
        [string[]]
        $Name
    )

    Begin {}
    Process {
        foreach ($item in $Name) {
            if ($PSCmdlet.ShouldProcess($item, "Getting the mac address")) {
                Get-VM $item -PipelineVariable vm | 
                    Get-NetworkAdapter | 
                    Select-Object @{n="Name"; e={$vm.Name}},
                        @{n="ClientId"; e={$_.MacAddress -replace ":","-"}}
            }
        }  
    }
    End {}
}
到目前为止,一切都很完美。 我可以通过以下任何一种方式使用它,并获得结果

它通过命名参数或作为管道输入接受单个字符串或字符串数组

Get-MacFromVm -Name "playground"
Get-MacFromVm -Name "playground", "DC01"
"playground", "DC01" | Get-MacFromVm
输出是一个
[PSCustomObject]
,有两个属性,一个名称和ClientId

现在,当我想使用
-PipelineVariable
参数将结果链接到多个其他cmdlet时,问题就开始了

通常我应该可以这样使用它:

Get-MacFromVm -Name "playground" -PipelineVariable pv | % {$pv}
但它没有显示任何结果。如果我将
$pv
替换为
$\u
,它确实会显示正确的结果,但我无法在管道链的更远位置使用自动变量2或3 cmdlet

尽管我可以通过使用
-OutVariable
和/或将其拆分为多行来解决这个问题。
我想知道为什么这不起作用,我想知道我在这里遗漏了什么。

我没有使用
-PipelineVariable
参数的经验。因此,我借此机会了解了
-PipelineVariable
参数:

由于我也无法轻松访问虚拟机,因此我模拟了以下功能:

Function Get-MacFromVm {
    [CmdletBinding(SupportsShouldProcess=$true)]
    Param(
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true)]
        [string[]]
        $Name
    )
    Function MacAddress {(1..4 | ForEach {'{0:x2}' -f (Get-Random -Min 0 -Max 255)}) -Join ":"}
    Function Get-VM {[cmdletbinding()] Param ($Name) [pscustomobject]@{Name = $Name; MacAddress = (MacAddress)}}
    ForEach ($Item in $Name) {
        If ($PSCmdlet.ShouldProcess($Item, "Getting the mac address")) {
            Get-VM $item -PipelineVariable vm |
            Select-Object @{n="Name"; e={$vm.Name}}, @{n="ClientId"; e={$_.MacAddress -replace ":","-"}}
        }
    }
}
但我无法重现这个问题:

PS C:\> Get-MacFromVm -Name "playground", "DC01" -PipelineVariable pv | % {$pv}

Name       ClientId
----       --------
playground 3c-23-55-c4
DC01       4f-38-42-a7
所以我想知道这个模拟功能是否也适用于您。
如果是,也许您可以找到与真实VM对象的差异

了解PowerShell,我会质疑是否没有输出或显示任何内容。那么,如果只输出一个属性,会发生什么情况:

Get-MacFromVm -Name "playground" -PipelineVariable pv | % {$pv.Name}
或:

这是否返回“
您不能对空值表达式调用方法。
”错误


2019年10月30日更新

根据评论:

您看不到的原因是,由于未使用
begin
/
进程
/
end
块,您的函数隐式运行在
end
块中,这些脚本块的第一次调用在管道变量中捕获,而不是后续脚本块调用的输出,如果函数具有
进程
块,则会发生这种情况

这意味着正确的模拟应该是:

Function Get-MacFromVm {
    [CmdletBinding(SupportsShouldProcess=$true)]
    Param(
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true)]
        [string[]]
        $Name
    )
    Begin {
        Function MacAddress {(1..4 | ForEach {'{0:x2}' -f (Get-Random -Min 0 -Max 255)}) -Join ":"}
        Function Get-VM {[cmdletbinding()] Param ($Name) [pscustomobject]@{Name = $Name; MacAddress = (MacAddress)}}
    }
    Process {
        ForEach ($Item in $Name) {
            If ($PSCmdlet.ShouldProcess($Item, "Getting the mac address")) {
                Get-VM $item -PipelineVariable vm |
                Select-Object @{n="Name"; e={$vm.Name}}, @{n="ClientId"; e={$_.MacAddress -replace ":","-"}}
            }
        }
    }
}
对于
PipelineVariable
,它实际上不会给出任何结果:

PS C:\> Get-MacFromVm -Name "playground", "DC01" -PipelineVariable pv | % {$pv}
PS C:\>
而当前项(
$)\uu
)执行以下操作:


您的PowerShell版本是什么?Windows 10上的5.1.15063.483。现在已提交错误报告:使用您修改的代码,它可以正常工作。但就我自己而言,情况并非如此。你最后一个问题的答案是肯定的,我确实得到了
空值
错误。据我所知,我所输出的只是一个对象到管道中,因此VMware cmdlet给出的内容并不重要,它也只是一个对象。
Get VM
命令返回
VMware.vimatomation.ViCore.Impl.V1.Inventory.InventoryItemImpl
基类型的
UniversalVirtualMachineImpl
PS C:\> Get-MacFromVm -Name "playground", "DC01" -PipelineVariable pv | % {$pv}
PS C:\>
PS C:\> Get-MacFromVm -Name "playground", "DC01" -PipelineVariable pv | % {$_}

Name       ClientId
----       --------
playground e7-b5-a0-31
DC01       0f-ed-94-cc