我有一个具有以下两个功能的模块,它们几乎是相同的:
<#
.SYNOPSIS
Retrieves a VApp from VCloud.
#>
Function Get-VApp
{
[CmdletBinding()]
[OutputType([System.Xml.XmlElement])]
Param(
[Parameter(Mandatory = $true)]
[System.Xml.XmlElement] $Session,
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string[]] $VAppName
)
Begin {
[System.Xml.XmlElement] $queryList = $Session.GetQueryList();
[System.Xml.XmlElement[]] $vAppRecords = $queryList.GetVAppsByRecords().VAppRecord;
}
Process {
ForEach ($VAN in $VAppName)
{
$vAppRecords |
Where-Object { $_.name -eq $VAN } |
ForEach-Object { $_.Get(); }
}
}
End
{
#
}
}
和
<#
.SYNOPSIS
Retrieves a VAppRecord from VCloud.
#>
Function Get-VAppRecord
{
[CmdletBinding()]
[OutputType([System.Xml.XmlElement])]
Param(
[Parameter(Mandatory = $true)]
[System.Xml.XmlElement] $Session,
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string[]] $VAppName
)
Begin {
[System.Xml.XmlElement] $queryList = $Session.GetQueryList();
[System.Xml.XmlElement[]] $vAppRecords = $queryList.GetVAppsByRecords().VAppRecord;
}
Process {
ForEach ($VAN in $VAppName)
{
$vAppRecords |
Where-Object { $_.name -eq $VAN } |
ForEach-Object { $_; }
}
}
End
{
#
}
}
本质上,Get-VApp类似于Get-VAppRecord,除了前者在返回的对象上调用Get()方法。这似乎很浪费。如果我不打扰管道,那将很容易:
Function Get-VApp
{
[CmdletBinding()]
[OutputType([System.Xml.XmlElement])]
Param(
[Parameter(Mandatory = $true)]
[System.Xml.XmlElement] $Session,
[Parameter(Mandatory = $true)]
[string[]] $VAppName
)
Get-VAppRecord $Session $VAppName |
ForEach-Object {
$_.Get();
}
}
但是很明显,管道把事情搞砸了。为了提高效率,我没有多次调用Begin块中的代码,我想找到一种方法来“与管道打好”而不必分批记录。
答案 0 :(得分:2)
SteppablePipeline
类旨在包装启用了管道的命令,而不会弄乱它们对管道的支持。
您甚至不需要知道如何设置它,ProxyCommand.Create()
会为其生成支架!
因此,我们首先为Get-VAppRecord
创建代理功能:
$GetVAppRecordCommand = Get-Command Get-VAppRecord
$GetVAppRecordCommandMetadata = [System.Management.Automation.CommandMetadata]::new($GetVAppRecordCommand)
# returns the body of the new proxy functions
[System.Management.Automation.ProxyCommand]::Create($GetVAppRecordCommandMetadata)
...,然后我们只需要在其Get()
块中添加process
调用:
function Get-VApp {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true, Position=0)]
[System.Xml.XmlElement]
${Session},
[Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true)]
[string[]]
${VAppName})
begin
{
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Get-VAppRecord', [System.Management.Automation.CommandTypes]::Function)
$scriptCmd = {& $wrappedCmd @PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline()
$steppablePipeline.Begin($MyInvocation.ExpectingInput) # Many examples use $PSCmdlet; however setting this ensures that $steppablePipeline.Process() returns the output of the inner function.
} catch {
throw
}
}
process
{
try {
$steppablePipeline.Process($_) |ForEach-Object {
# call Get() on the record
$_.Get()
}
} catch {
throw
}
}
end
{
try {
$steppablePipeline.End()
} catch {
throw
}
}
}