Reputation: 3042
According to documentation, PS 7 has introduced pipeline chaining operators such as ||
and &&
.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_pipeline_chain_operators?view=powershell-7
And you should be able to do C#-style short circuiting operations like:
Write-Error 'Bad' && Write-Output 'Second'
The above examples work. And the documentation says that the pipeline chaining operators use two fields (unsure how that works precisely): $?
and $LASTEXITCODE
How do I apply these to my own functions?
For example:
function yes() {
echo 'called yes'
return $True
}
function no() {
echo 'called no'
return $False
}
I feel like I should be able to run the following no && yes
and see the following output
called no
False
but instead I see
called no
False
called yes
True
So how do I develop functions in such a way that I can use pipeline chaining and short circuiting?
edit: the only way I can figure out right now to construct a custom function that will short circuit an &&
is to make it throw
, but that doesn't seem too useful in the general case.
Upvotes: 2
Views: 128
Reputation: 437080
&&
and ||
solely operate on the success status of a command, as reflected in the automatic $?
variable (as you state) - which is unrelated to what a command outputs (returns).
Functions and scripts report $?
as $true
, unless explicit action is taken; that is, even if commands used inside the script / function fail, $?
is still $true
when the script / function exits.
Unfortunately, as of PowerShell 7.0, there is no direct way for a function to directly set $?
to $false
, although the plan is to add such a feature - see this GitHub isssue.
In a script, using exit
with a nonzero exit code is effective, however (this causes $LASTEXITCODE
to reflect the exit code, and the PowerShell engine sets $?
to $false
if the exit code is nonzero - this is also how it works when you call external programs).
For now, there's only the following suboptimal workaround for functions; it is suboptimal in that it invariably emits an error message:
function no {
# Make the function an advanced one, so that $PSCmdlet.WriteError()
# can be called.
[CmdletBinding()]
param()
# Call $PSCmdlet.WriteError() with a dummy error, which
# sets $? to $false in the caller's scope.
# By default, this dummy error prints and is recorded in the $Error
# collection; you can use -ErrorAction Ignore on invocation to suppress
# that.
$PSCmdlet.WriteError(
[System.Management.Automation.ErrorRecord]::new(
[exception]::new(), # the underlying exception
'dummy', # the error ID
'NotSpecified', # the error category
$null) # the object the error relates to
)
}
Function no
now sets $?
to false, which triggers a ||
branch; -EA Ignore
(-ErrorAction Ignore
) is used to silence the dummy error.
PS> no -EA Ignore || 'no!'
no!
Upvotes: 1