Powershell 从一个函数到另一个函数的内部管道
我有一个模块,它有以下两个功能,几乎相同:Powershell 从一个函数到另一个函数的内部管道,powershell,Powershell,我有一个模块,它有以下两个功能,几乎相同: <# .SYNOPSIS Retrieves a VApp from VCloud. #> Function Get-VApp { [CmdletBinding()] [OutputType([System.Xml.XmlElement])] Param( [Parameter(Mandatory = $true)] [System.Xml.XmlElement] $S
<#
.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
{
#
}
}
但很明显,管道把事情搞砸了。为了提高效率,我不会多次调用Begin块中的代码,我希望找到一种方法,在不必批处理记录的情况下“很好地”处理管道。该类旨在包装启用管道的命令,而不会破坏管道支持
你甚至不需要知道如何设置它,它将生成脚手架
因此,让我们首先为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()
调用:
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
}
}
}
为什么需要
ForEach对象
调用?要明确。这看起来就像我要找的。我到家后去看看。PowerShell的最低版本是什么?好的-我已经尝试了代码,但问题是内部函数将其输出直接返回到外部函数的管道,而Process()函数的输出是一个空数组。@MarkBertenshaw我还不完全清楚这是什么意思。你看到了什么影响?有错误吗?我对此做了更多的研究,我还没有找到一个不使用上述锅炉板代码的SteppablePipeline示例。在我看到的所有示例中,其目的基本上是重新定义现有命令,并且进程块中没有条件分支。我想做的唯一方法是通过脚本级变量将输出发送回。这是一种糟糕的方法,因为现在我必须检测如何调用内部函数,并根据是通过外部函数调用还是直接调用来进行不同的处理。在阅读了一些糟糕的文档和大量实验后,我发现缺少的信息是Begin()方法应给定一个布尔参数。特别是,该值应为$MyInvocation.ExpectingInput。这可以处理通过管道或指定参数获取值的外部函数。
$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)
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
}
}
}