Select-Object 如何在 PowerShell v3 中停止管道? [英] How does Select-Object stop the pipeline in PowerShell v3?
问题描述
在 PowerShell v2 中,以下行:
In PowerShell v2, the following line:
1..3| foreach { Write-Host "Value : $_"; $_ }| select -First 1
会显示:
Value : 1
1
Value : 2
Value : 3
因为所有元素都被推到了管道中.但是,在 v3 中仅显示上述行:
Since all elements were pushed down the pipeline. However, in v3 the above line displays only:
Value : 1
1
管道在 2 和 3 发送到 Foreach-Object
之前停止(注意:Select-Object
的 -Wait
开关允许到达 foreach
块的所有元素).
The pipeline is stopped before 2 and 3 are sent to Foreach-Object
(Note: the -Wait
switch for Select-Object
allows all elements to reach the foreach
block).
Select-Object
如何停止管道,我现在可以从 foreach
或我自己的函数停止管道吗?
How does Select-Object
stop the pipeline, and can I now stop the pipeline from a foreach
or from my own function?
我知道我可以将管道包装在 do...while 循环中并继续离开管道.我还发现在 v3 中我可以做这样的事情(它在 v2 中不起作用):
I know I can wrap a pipeline in a do...while loop and continue out of the pipeline. I have also found that in v3 I can do something like this (it doesn't work in v2):
function Start-Enumerate ($array) {
do{ $array } while($false)
}
Start-Enumerate (1..3)| foreach {if($_ -ge 2){break};$_}; 'V2 Will Not Get Here'
但是 Select-Object
不需要这些技术中的任何一种,所以我希望有一种方法可以从管道中的单个点停止管道.
But Select-Object
doesn't require either of these techniques so I was hoping that there was a way to stop the pipeline from a single point in the pipeline.
推荐答案
在尝试了几种方法后,包括抛出 StopUpstreamCommandsException、ActionPreferenceStopException 和 PipelineClosedException,调用 $PSCmdlet.ThrowTerminatingError 和 $ExecutionContext.Host.Runspace.GetCurrentlyRunningPipeline().stopper.set_IsStopping($true) 我终于发现仅使用 select-object 是唯一不会中止整个脚本(而不是管道)的东西.[请注意,上面提到的一些项目需要访问私有成员,我通过反射访问.]
After trying several methods, including throwing StopUpstreamCommandsException, ActionPreferenceStopException, and PipelineClosedException, calling $PSCmdlet.ThrowTerminatingError and $ExecutionContext.Host.Runspace.GetCurrentlyRunningPipeline().stopper.set_IsStopping($true) I finally found that just utilizing select-object was the only thing that didn't abort the whole script (versus just the pipeline). [Note that some of the items mentioned above require access to private members, which I accessed via reflection.]
# This looks like it should put a zero in the pipeline but on PS 3.0 it doesn't
function stop-pipeline {
$sp = {select-object -f 1}.GetSteppablePipeline($MyInvocation.CommandOrigin)
$sp.Begin($true)
$x = $sp.Process(0) # this call doesn't return
$sp.End()
}
<小时>
根据 OP 的评论遵循新方法.不幸的是,这种方法要复杂得多并且使用私有成员.此外,我不知道这有多强大 - 我只是让 OP 的示例工作并停在那里.所以FWIW:
New method follows based on comment from OP. Unfortunately this method is a lot more complicated and uses private members. Also I don't know how robust this - I just got the OP's example to work and stopped there. So FWIW:
# wh is alias for write-host
# sel is alias for select-object
# The following two use reflection to access private members:
# invoke-method invokes private methods
# select-properties is similar to select-object, but it gets private properties
# Get the system.management.automation assembly
$smaa=[appdomain]::currentdomain.getassemblies()|
? location -like "*system.management.automation*"
# Get the StopUpstreamCommandsException class
$upcet=$smaa.gettypes()| ? name -like "*upstream*"
filter x {
[CmdletBinding()]
param(
[parameter(ValueFromPipeline=$true)]
[object] $inputObject
)
process {
if ($inputObject -ge 5) {
# Create a StopUpstreamCommandsException
$upce = [activator]::CreateInstance($upcet,@($pscmdlet))
$PipelineProcessor=$pscmdlet.CommandRuntime|select-properties PipelineProcessor
$commands = $PipelineProcessor|select-properties commands
$commandProcessor= $commands[0]
$null = $upce.RequestingCommandProcessor|select-properties *
$upce.RequestingCommandProcessor.commandinfo =
$commandProcessor|select-properties commandinfo
$upce.RequestingCommandProcessor.Commandruntime =
$commandProcessor|select-properties commandruntime
$null = $PipelineProcessor|
invoke-method recordfailure @($upce, $commandProcessor.command)
1..($commands.count-1) | % {
$commands[$_] | invoke-method DoComplete
}
wh throwing
throw $upce
}
wh "< $inputObject >"
$inputObject
} # end process
end {
wh in x end
}
} # end filter x
filter y {
[CmdletBinding()]
param(
[parameter(ValueFromPipeline=$true)]
[object] $inputObject
)
process {
$inputObject
}
end {
wh in y end
}
}
1..5| x | y | measure -Sum
通过反射检索 PipelineProcessor 值的 PowerShell 代码:
PowerShell code to retrieve PipelineProcessor value through reflection:
$t_cmdRun = $pscmdlet.CommandRuntime.gettype()
# Get pipelineprocessor value ($pipor)
$bindFlags = [Reflection.BindingFlags]"NonPublic,Instance"
$piporProp = $t_cmdRun.getproperty("PipelineProcessor", $bindFlags )
$pipor=$piporProp.GetValue($PSCmdlet.CommandRuntime,$null)
Powershell 代码通过反射调用方法:
Powershell code to invoke method through reflection:
$proc = (gps)[12] # semi-random process
$methinfo = $proc.gettype().getmethod("GetComIUnknown", $bindFlags)
# Return ComIUnknown as an IntPtr
$comIUnknown = $methinfo.Invoke($proc, @($true))
这篇关于Select-Object 如何在 PowerShell v3 中停止管道?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!