Repository navigation
Description
Summary of the new feature / enhancement
Given following function to get frist item matching the given pattern:
function first {
param (
[Parameter(ValueFromPipeline)]
[psobject]$InputObject,
[Parameter(Position = 1, Mandatory)]
[scriptblock]$Selector
)
process {
if ($Selector.InvokeWithContext($null, [psvariable]::new('_', $_))) {
$_
# I need termination here when it found first match
}
}
}
1..10 | first { $_ % 2 -eq 0 } # expected: 2I would expect it terminate the process when it found a match, we have following possible workarounds:
return: aka continute forprocessbut it will keep spinning for rest of the reduandant itemsbreak: not sure about its semantic, it can early break theprocessbut has the following problem:
function first {
param (
[Parameter(ValueFromPipeline)]
[psobject]$InputObject,
[Parameter(Position = 1)]
[psobject]$Selector = 1
)
process {
if ($Selector.InvokeWithContext($null, [psvariable]::new('_', $_))) {
$_
break
}
}
}
1..10 | first { $_ % 2 -eq 0 } | select -f 1 # 2
1..10 | first { $_ % 2 -eq 0 } | measure # noneFor certain cmdlet like measure, it can't receive the items from first using break? While select works fine. Should it be considered as bug?
Given another function collect that collect everything from pipeline and return in end block, also reproduces the problem.
So looks like break not only breaks the process, it also skip the end block evaluation?
function collect {
begin {
$foo = [System.Collections.Generic.List[object]]@()
}
process {
$foo.Add($_)
}
end {
$foo
}
}
1..10 | first { $_ % 2 -eq 0 } | collect # noneProposed technical implementation details (optional)
Adding new keyword can be unnecessary, simply add a new method $PSCmlet.Break() or something should be sufficient.
Or just make break to eval end block as well(potentially breaking change), if I understand the problem correctly.
Activity
iRon7 commentedon May 3, 2026
Duplicate with #3821?
jhoneill commentedon May 3, 2026
I think this nearly the same but there's an end block difference.
Normally people ask for "Can I stop an expensive process earlier in the pipeline, in the same the way that
select-objectdoes to avoid a long wait here.That runs cleanly but it stops the end block running. This is "Stop" process and still run the end-block. Not sure how well that works when the end block can send objects to the pipeline (e.g. sort-object) the main purpose of stop is to prevent objects being sent.
iRon7 commentedon May 4, 2026
The way I see it, for where the propose possibly deviates from #3821: you could simply append
| Select-Object -First 1to the selection filter knowing that Select-Object by itself actually affects the upstream commands and where theendblocks downstream aren't affected:TobiasPSP commentedon May 20, 2026
I would suggest we implement it with the existing architecture in mind:
So in essence, use the existing mechanisms implemented for features like
Select-Object -First 1(throwing a special exception - PipelineStoppedException - that travels upstream and terminates all upstream cmdlets gracefully).Meanwhile, you can use the
Stop-Pipelineimplementation from above as a workaround.SteveL-MSFT commentedon May 20, 2026
Dupe of #3821
x5i4k4 commentedon May 21, 2026
Dr. Tobias Weltner (@TobiasPSP) well it indeed resolves the special case of
breakinForEach-Object, but it still skipsendblock evaluation which is the feature I actually wantx5i4k4 commentedon May 21, 2026
I think my issue is more about whether
endblock should be executed onbreak, while #3821 is more about the propagation of the termination, I knowendis also mentioned on that propasal, I just don't see people discussing much aboutendthere.TobiasPSP commentedon May 21, 2026
Got it. So you want the end block to behave like „finally“ in „try“? Interestingly, I assumed it would execute „end“ as part of gracefully breaking.
microsoft-github-policy-service commentedon May 22, 2026
This issue has been marked as duplicate and has not had any activity for 1 day. It has been closed for housekeeping purposes.