-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Description
Using the -First $n parameter for Select-Object completely skips the end {} blocks of all cmdlets preceding it in the pipeline.
This can be quite hazardous, e.g., for a cmdlet that access a resource that needs to have that handle properly disposed of (like a file) may not release that handle correctly.
There is no finally {} block available to PS, and the method in which Select-Object terminates the pipeline appears to happen in such a manner that no script-based function can account for; that is, even with a try...finally construct in the cmdlets' process {} blocks it will not kick off in the event that Select-Object is used to prematurely end the pipeline.
Instead, a method should be exposed for Select-Object (and potentially other cmdlets?) to safely terminate the pipeline by ceasing all process steps and kicking off the chain of end {} steps in the pipeline.
Steps to reproduce
(shamelessly pinched from @TimCurwick's fantastic example he posted in the PS Slack)
function test {
[cmdletbinding()]
param(
[Parameter(ValueFromPipeline)]
$X
)
begin {
Write-Host "Begin test"
}
process {
Write-Host "Process test"
$X
}
end {
Write-Host "End test"
}
}
1, 2, 3 | test | test | select -first 2Expected behavior
Begin Test
Begin Test
Process Test
Process Test
1
Process Test
Process Test
2
End Test
End Test
Actual behavior
Begin test
Begin test
Process test
Process test
1
Process test
Process test
2
Environment data
> $PSVersionTable
Name Value
---- -----
PSVersion 6.1.0
PSEdition Core
GitCommitId 6.1.0
OS Microsoft Windows 10.0.17763
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0