I expect that the return from the function statement (begin, process, end) should also terminate all its statements, but this does not happen.
I have a test function like this:
function test($a) {
begin {
Write-Host 'begin ' -NoNewline
if ($a -like '*begin*') { return; }
}
process {
Write-Host 'process ' -NoNewline
if ($a -like '*process*') { return; }
}
end {
Write-Host 'end' -NoNewline
if ($a -like '*end*') { return; }
}
}
And when I run it this way:
'begin', 'process', 'end' | ForEach-Object {
Write-Host "Try exit in $_ :`t" -NoNewline
test $_
Write-Host
}
Then I get a similar result:
Try exit in begin : begin process end
Try exit in process : begin process end
Try exit in end : begin process end
But I would like the output from the function to also terminate its other statements and the output would be like this:
Try exit in begin : begin
Try exit in process : begin process
Try exit in end : begin process end
How can I get it?
I tryed to use break, continue and exit instead of return but it terminated all script..
Your function is an advanced function, and therefore uses begin, process and end blocks.
In a simple (non-advanced) function, in the absence of such blocks, return would indeed instantly exit the function, but from inside these blocks, return just exits that block.
(As an aside: break and continue only apply to loop-like constructs, and exit is meant to exit scripts as a whole, not individual functions).
If you want to exit your advanced function as a whole you have two basic choices:
Throw an error, using a throw statement, which creates a script-terminating error (fatal by default).
To emulate the statement-terminating errors that binary cmdlets emit, you can use the $PSCmdlet.ThrowTerminatingError() method (available to advanced functions such as yours) - by default, execution resumes in the caller's scope afterwards (after printing an error message).
If throw is used but aborting execution overall should be prevented, a caller must enclose the call in a try / catch statement (or, less commonly these days, use a trap statement).
Use a custom [bool] variable that ignores attempts to (re)enter the process / the other blocks.
process block efficiently, it would be helpful to be able to instruct upstream commands that no more input should be provided. However, this isn't an option as of PowerShell 7.4, but has been proposed as a future enhancement in GitHub issue #3821.To illustrate the technique of using a [bool] variable:
function test($a) {
begin {
$done = $false
Write-Host 'begin ' -NoNewline
if ($a -like '*begin*') { $done = $true; return }
}
process {
if ($done) { return }
Write-Host 'process ' -NoNewline
if ($a -like '*process*') { $done = $true; return }
}
end {
if ($done) { return }
Write-Host 'end' -NoNewline
# Retained from your original code, but note that this is redundant:
# The function will exit here either way.
if ($a -like '*end*') { return }
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With