Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$? is not set to $False even command fails #18343

Closed
5 tasks done
sumit-kakadiya opened this issue Oct 21, 2022 · 24 comments
Closed
5 tasks done

$? is not set to $False even command fails #18343

sumit-kakadiya opened this issue Oct 21, 2022 · 24 comments
Labels
Needs-Triage The issue is new and needs to be triaged by a work group. Resolution-No Activity Issue has had no activity for 6 months or more WG-Engine core PowerShell engine, interpreter, and runtime

Comments

@sumit-kakadiya
Copy link

Prerequisites

Steps to reproduce

facing issue in version: Powershell version powershell-7.2 and on powershell-7.1.3
OS: centos 7
module used : ExchangeOnlineManagement
Issue: I connected o365 via powershell using application. I connected succesfully. I tried to fetch any connector exists or not.
That gets failed. But "$?" was not set to False. It always remains True. Earlier it was set to False in such a case.
Same issue I faced when I create any connector. IF connector creations fails, "$?" remains True instead of False.

In below code sample:

  1. connector1 does not exist in my o365 exchange.
  2. "myrule" as not created as account has reached limit to no. of rules already.

code sample:
$EncPassword = ConvertTo-SecureString -String 'passowd' -AsPlainText -Force
Connect-ExchangeOnline -AppId 'appid of mine' -CertificateFilePath '/home/cert.pfx' -CertificatePassword $EncPassword -Organization 'myorgdomain.onmicrosoft.com'
write-host "connected"
Get-InboundConnector 'connector1'
if ($? -eq $True)
{
write-host "inbound connector exist"
}
else
{
write-host "inbound connector does not exist"
}
try
{
New-TransportRule -Name 'myrule' -FromScope NotInOrganization -SentToScope InOrganization -Enabled $true -Priority 0 -SetSCL -1
if ($? -eq $True)
{
write-host "inbound rule created"
}
else
{
write-host "inbound rule creation failed"
}
}
catch
{ write-error "This is exception" }

Expected behavior

$? should be set to $False as both commands were actually failed. It was working before few days but suddenly behaviour looks changed.

Expected output:
connected
inbound connector does not exist
inbound rule creation failed

Actual behavior

$? always set to $True even both commands were actually failed. It was working before few days but suddenly behaviour looks changed.

actual output:
connected
inbound connector exist
inbound rule created

Error details

No response

Environment data

actual output:
connected
inbound connector exist
inbound rule created

Visuals

No response

@sumit-kakadiya sumit-kakadiya added the Needs-Triage The issue is new and needs to be triaged by a work group. label Oct 21, 2022
@jhoneill
Copy link

jhoneill commented Oct 21, 2022

The value of erroractionPreference and what happens inside the command being called will impact $?

function one {
[CmdletBinding()]
param()
1/0
"This line runs"
}

PS>  one
RuntimeException:
Line |
   4 |  1/0
     |  ~~~
     | Attempted to divide by zero.
This line runs

PS>  $?
True

There was an error but the command still ran to completion - this is the test for "succeeded" - setting error action prevents it running to completion.

PS>  one -ErrorAction stop
one: Attempted to divide by zero.

PS>  $?
False

"Did what I wanted", "Ran without raising any error", and "Succeeded" are not not the same, and the difference is a surprise sometimes.

@mklement0
Copy link
Contributor

If I understand correctly, what sets $? to false is any error record being written to the caller's error stream - which can be a non-terminating error (Get-Item NoSuch) or a statement-terminating error (Get-Item -NoSuch).
(As such $? only ever tells you that some error occurred, not whether the command failed entirely or should still be considered successful overall.)

However, for commands written in PowerShell, statement-terminating errors or Write-Error calls inside them do not cause $? to be set to $false. The only way to currently achieve that is by making your script or function an advanced one and to use $PSCmdlet.WriteError() (non-terminating error) or $PSCmdlet.ThrowTerminatingError() (statement-terminating error, from the caller's perspective).

That Write-Error currently doesn't set $? is unfortunate, and a known problem:

Additionally, the ability for scripts and function to set $? explicitly has been green-lighted a while back, but isn't yet implemented (a new public API to be surfaced via a new cmdlet):

Therefore, $? in your code should only be $false if BOTH of the following conditions are met:

  • The preceding command emitted (at least one) error.
  • The command is implemented as a binary cmdlet OR it is implemented as an advanced function and uses $PSCmdlet.WriteError() and $PSCmdlet.ThrowTerminatingError() to emit its error.

@jhoneill
Copy link

for commands written in PowerShell, statement-terminating errors or Write-Error calls inside them do not cause $? to be set to $false. The only way to currently achieve that is by making your script or function an advanced one and to use $PSCmdlet.WriteError() (non-terminating error) or $PSCmdlet.ThrowTerminatingError() (statement-terminating error, from the caller's perspective).

@mklement0 throw works, and if error action preference is set to stop other errors act like throw.

PS>  function two {"a"; throw; b;}

PS>  two
a
Exception: ScriptHalted

PS>  $?
False

PS>

Using my other example

function one {
[CmdletBinding()]
param()
1/0
#  $? will now be false
"This line runs"
#  $? will now be true because the string was output
}

PS>  one
RuntimeException:
Line |
   4 |  1/0
     |  ~~~
     | Attempted to divide by zero.
This line runs

PS>  $?
True      # even if the error is the last line the function, it is still true  

divide by zero is a terminating error, but when ErrorActionPreference is "continue" it is considered to have been handled after printing it. So the function exits normally and $? says "true"

@mklement0
Copy link
Contributor

@jhoneill

Quick terminology note: There are two types of terminating errors:

  • A statement-terminating error (pipeline-terminating) occurs in an expression such as 1 / 0, an exception thrown by a .NET method, an reported by a compiled cmdlet with .ThrowTerminatingError() (which, as noted, you can also do in PowerShell code with $PSCmdlt.ThrowTerminatingError(), but it is cumbersome and rarely done in practice).

    • As the name implies, the scope of what is terminated by default is the current statement , meaning that execution continues with the next statement.
  • A script-terminating error (runspace-terminating, fatal) throw by default produces ; you can promote non-terminating errors to script-terminating ones with -ErrorAction Stop.

    • As the name (imperfectly) implies, the scope of what is terminated by default is the current script - at least - but actually the entire runspace the script and its callers). (In an earlier discussion, it was decided that "script" was good enough, and easier to understand than "runspace").

    • You can also promote non-terminating errors to script-terminating ones with -ErrorAction Stop. You can additionally promote statement-terminating ones to script-terminating ones with $ErrorActionPreference = 'Stop.

This terminology isn't official but it's useful for making sense of what PowerShell does, and I've used it here and on Stack Overflow. (The names could be revisited, should they became part of the official docs; speaking of:
A while back I've attempted a comprehensive overview of PowerShell's error handling: Our Error Handing, Ourselves)

@mklement0
Copy link
Contributor

@jhoneill, as for your examples:

Your throw example:

Inside a script or function there's no point in combining throw with $?,
because throw either terminates the runspace, so no further code gets to execute, or you must use try / catch, in which case the fact that the catch block is triggered by definition means that an error occured.

(Interactively, throw fortunately does not terminate the entire session, which is what your example relies on)


Your 1 / 0 example:

What $? is inside a script or function is irrelevant to the caller.

That is, whether or not you follow 1 / 0 with another statement that function-internally resets $? before returning makes no difference:

function foo { 1 / 0 }; foo; $? # -> $true

@SteveL-MSFT
Copy link
Member

@sumit-kakadiya so for your original issue, does setting $ErrorActionPreference = 'Stop' address your issue? It seems that the generated proxy functions do not generate a terminating error such that $? gets set.

@mklement0
Copy link
Contributor

@SteveL-MSFT:

Switching to -ErrorAction Stop isn't a general solution, as with multiple inputs you may want to continue processing of the remaining inputs, even if an earlier one resulted in a non-terminating error, and check $? afterwards.

Also, -ErrorAction Stop could only be handled with a try / catch - a directly following if ($? -eq $true) would not get to execute.

Unless there is truly a bug here, the fact hat if ($? -eq $true) did get to execute and was $true implies one of two things:

  • No error was emitted.
  • A non-terminating error was emitted, but it didn't cause $? to be set to $false. (Statement-terminating errors always set $? to $false; functions can only emit such errors via $PSCmdlet.ThrowTerminatingError()).
    • As discussed, this can be the case for functions that use Write-Error (rather than $PSCmdlet.WriteError()) to emit non-terminating errors.

You mention proxy functions: do they use Write-Error? Normally, proxy function, i.e. ones that use a steppable pipeline, do set $? to $false for relayed non-terminating errors, at least if the command being proxied is a binary cmdlet.

Is there an aspect we're not considering, such as CDXML / implicit remoting?

@SteveL-MSFT
Copy link
Member

@mklement0 since this is ExchangeOnline, it's using implicit remoting so proxy functions are generated locally, hence was looking for a workaround in the interim.

@mklement0
Copy link
Contributor

mklement0 commented Oct 25, 2022

Thanks, @SteveL-MSFT, so just to clarify:

Auto-generated functions created in the context of implicit remoting have the same problem that local functions that use Write-Error do, i.e. they do not properly set $? to $false for the caller, if (at least one) non-terminating error is emitted?

If (distant) memory serves, the only way to get implicit remoting functions to generate a terminating error is to set $ErrorActionPreference in the global scope, otherwise the module in which the functions run doesn't see it: $global:ErrorActionPreference = 'Stop'; saving and restoring the previous global setting is advisable.

However, this makes errors script-terminating ones, which can therefore only be handled with try / catch, not via $?

@jhoneill
Copy link

TBH I think as a way of testing whether ANY command had an error $? is flawed. It indicates "ran to completion" rather than "success", and try {foo} catch {bar} is more reliable , though it sometimes needs -erroraction Style wise we can see "I'm going to run some code and do something if there is an error" as soon as we see try but

foo
if (-not $?) {bar}

Requires us to think back to foo when our brains fill in the $? means "previous-ran-to-completion" The behaviour of $? making us write clearer, code which isn't actually any more typing isn't a bad thing.

@mklement0
Copy link
Contributor

@jhoneill, yeah, $? is only a very abstract way to test if some error occurred.
In fact, it does not necessarily indicate "ran to completion", given that a statement-terminating error also sets it to $false:

Get-Item -NoSuchParameter  # a statement-terminating error reported by the parameter binder.
$? # -> $false

$? can be handy as a shortcut for $LASTEXITCODE -eq 0 when calling external programs (but a bug relating to 2> redirections in Windows PowerShell makes that unreliable).

$? is now indirectly useful, as its value in effect is the basis of the pipeline-chain operators, && and ||:

Get-Item NoSuchFile || 'dang!'   # with non-terminating error -> 'dang!' prints (too)
Get-Item -NoSuchParameter || 'dang!'  # with statement-terminating error -> 'dang!' prints (too)
# Unfortunately, does NOT work with functions that use Write-Error, as discussed
function foo { Write-Error 'non-terminating error' }; foo || 'dang!'  # !! 'dang!' does NOT print

To distinguish between non-terminating and terminating errors (whether statement- or script-terminating), you need try / catch:

# With non-terminating error -> error prints, try / catch is IGNORED
try { Get-Item NoSuchFile } catch { 'I AM NEVER CALLED' }   
# With terminating errors -> no error output, catch block is called.
try { Get-Item -NoSuchParameter } catch { 'CAUGHT!' }  # statement-terminating error - 'CAUGHT!' prints
try { throw 'A fit' } catch { 'CAUGHT!' }  # script-terminating error - 'CAUGHT!' prints

As an aside:

@jhoneill
Copy link

distinguish between non-terminating and terminating errors (whether statement- or script-terminating), you need try / catch:

# With non-terminating error -> error prints, try / catch is IGNORED
try { Get-Item NoSuchFile } catch { 'I AM NEVER CALLED' }   
# With terminating errors -> no error output, catch block is called.
try { Get-Item -NoSuchParameter } catch { 'CAUGHT!' }  # statement-terminating error - 'CAUGHT!' prints
try { throw 'A fit' } catch { 'CAUGHT!' }  # script-terminating error - 'CAUGHT!' prints

It gets complicated because we have

  • non-terminating which just write a message to the error channel but don't terminate and can't be caught. Since the next step runs the $? will end up as true.
  • "Statement terminating" which will normally be handled according to the value of $errorActionPreference in force (which may be locally set by -errorAction). The terminating error is treated as "caught" simply by printing if the value is continue or not even printing it if it is silently continue.
  • "script terminating" one of the terminating commands - which won't be treated as caught simply by printing the message.
  • The powershell throw statement. Can be script-terminating, but if error-action is set to silently continue is considered to be handled.
    image

@mklement0
Copy link
Contributor

mklement0 commented Oct 27, 2022

My examples assume the default value for $ErrorActionPreference, 'Continue'

Since the next step runs the $? will end up as true.

Immediately after a cmdlet call that produced at least one non-terminating error (error records written to the error stream), $? is $false; the try / catch enclosure doesn't change that:

try { Get-Item NoSuchFile } catch { 'I AM NEVER CALLED' }
$? # -> $false

will normally be handled according to the value of $errorActionPreference in force (which may be locally set by -errorAction)

$ErrorActionPreference and -ErrorAction are NOT equivalent, which is highly unfortunate: the former acts on all error types (as you demonstrate with throw), the latter only on non-terminating ones.

Resolving this asymmetry is being considered, but it would be a substantial breaking change:

"script terminating" one of the terminating commands - which won't be treated as caught simply by printing the message.

I don't understand.

@jhoneill
Copy link

$ErrorActionPreference and -ErrorAction are NOT equivalent, which is highly unfortunate: the former acts on all error types (as you demonstrate with throw), the latter only on non-terminating ones.

No, -ErrorAction definitely changes the behaviour for terminating errors.

Function Get-Tangent {
     [cmdletbinding()]
     param ($a)
     $t = [math]::Tan($a)
     $t
     Write-Verbose "tan of $a  is $t"
}

PS>  try {Get-Tangent "hello" -verbose }  catch {"Problem finding tangent"}  #   terminating error catch works
Problem finding tangent   

PS>  Get-Tangent "hello" -verbose    # Error action continue verbose line runs 
MethodException:
Line |
   4 |      $t = [math]::Tan($a)
     |      ~~~~~~~~~~~~~~~~~~~~
     | Cannot convert argument "a", with value: "hello", for "Tan" to type "System.Double": "Cannot convert value "hello" ...
VERBOSE: tan of hello  is                     

PS>  Get-Tangent "hello" -verbose  -ea Stop   # terminating error is no longer handled by print and continue
Get-Tangent: Cannot convert argument "a", with value: "hello", for "Tan" to type "System.Double": "Cannot convert value "hello" 
...

And for throw

 function throwSomething {
 [cmdletbinding()]
 param()
 throw "something"
 "This should not run"
}

PS>  throwSomething
Exception:
Line |
   4 |  throw "something"
     |  ~~~~~~~~~~~~~~~~~
     | something

PS>  throwSomething -ErrorAction SilentlyContinue
This should not run

Which is why I advise people to follow throw with return.

"script terminating" one of the terminating commands - which won't be treated as caught simply by printing the message.

I don't understand.

OK. You have an old fashioned batch file. In it you have ping with invalid parameters. But the next line of the batch file runs. Even though ping terminated unless the next line is "check what happened and abort if ping failed" the rest of the script runs. So here there is no such thing as a script terminating error. An error might terminate a command, but it can't stop the batch file that called it.

In a C# program you might have the equivalent of [int]::Parse($s) if s contains "one" this will cause a terminating error, the C# program can catch the error, but if it does not the program exits with a run time failure. So all terminating errors are the same - if they are not caught errors exit the program there and then.

PowerShell has something different again.
[int]::Parse($s) is still a terminating error. We can still catch it, it's not just information going to the error channel.
$errorActionPreference (whether it is a global variable or set via the common parameter) decides whether and how that error will be trapped. Continue is "Print-message resume-next". And its value in different scopes can change behaviour.

 Function Get-Tangent {
    [cmdletbinding()]
    param ($a)
     $ErrorActionPreference = "stop"
    $t = [math]::Tan($a)
     $t
    Write-Verbose "tan of $a  is $t"
}
  
>  $ErrorActionPreference = "continue"

PS>  get-Tangent "hello" -verbose  ; "boo"
Get-Tangent: Cannot convert argument "a", with value: "hello", for "Tan" to type "System.Double": "Cannot convert value "hello" to type "System.Double". Error: "The input string 'hello' was not in a correct format.""
boo

Having action preference set to stop causes the function to exit without writing the verbose message, but when the message bubbles up to the command line where action is continue, it is printed and the next command runs.

This is what I mean by printing the message is a treated as catching it

But write-error with -ea stop or erroractionpreference set the next command doesn't run

PS>  function one {
>> write-error "Stop" -ea stop
>> "this won't run"
>> }


PS>  one  ; "two"
one: Stop

This makes write error return a pipeline terminating error, we can only catch it...

@mklement0
Copy link
Contributor

mklement0 commented Oct 27, 2022

-ErrorAction Stop has no effect on your example:

# Prints the error message and continues. [UPDATE: No quite] Omitting -ErrorAction Stop behaves the same.
Get-Tangent "hello" -verbose -ErrorAction Stop; 'after'

# As opposed to (prints "caught!" only, 'after' doesn't get to execute):
try { Get-Tangent "hello" -verbose -ErrorAction Stop; 'after' } catch { 'caught!' }

# Via $ErrorActionPreference  = 'Stop' - but UNLIKE with -ErrorAction Stop - the statement-terminating
# error becomes a script-terminating one, so 'after' doesn't get to execute.
& {
  $ErrorActionPreference = 'Stop'
  Get-Tangent "hello" -verbose; 'after'
}

@mklement0
Copy link
Contributor

mklement0 commented Oct 27, 2022

As for the rest of your previous comment: no argument there, but it also drives home the need for specific terms for the two kinds of terminating errors that can occur in PowerShell, based on the what the unit of execution is that they terminate.

[int]::Parse($s) is still a terminating error.

I'm calling this a statement-terminating error, because (by default) it terminates just that statement, and continues execution.

By contrast, throw creates a script-terminating error (not a precise term, as discussed; perhaps fatal would be more descriptive, without having to get too technical about what the unit of executions).

It's interesting to note that binary cmdlets cannot themselves create such errors; .ThrowTerminatingError() is (by default) a statement-terminating error.

@jhoneill
Copy link

Lets out big sigh

# Prints the error message and continues. Omitting -ErrorAction Stop behaves the same.
Get-Tangent "hello" -verbose -ErrorAction Stop; 'after'

No it doesn't
image

As far as I can tell -ErrorAction x / warningAction x, -verbose , and -confirm does is to set the value of the preference variable in the scope of that command.

-ErrorAction stop in the function's scope causes the function to exit as soon as it hits an error, but outside the function where the value of ErrorActionPreference is different (continue), the error is printed and execution continues.

And it doesn't matter whether $errorActionPreference is set by specifying -ErrrorAction as above or as variable as below
image

What I can't figure out is why this varies

image

And if you know I'd love to hear.

The rest as you say we agree on. Throw is law unto itself. It will create a script / pipeline terminating error UNLESS the local scope has error action = Silently continue. In which case it continues silently. This is multiple kinds of wrong, but probably too embedded to change. I'm not sure that anyone would say ALL of these are consistent
image

@mklement0
Copy link
Contributor

mklement0 commented Oct 27, 2022

Yes, good point, I missed one aspect:

An uncaught statement-terminating error (exception) inside a command that happens to be implemented as a PowerShell script or function, is susceptible to -ErrorAction Stop - indeed because -ErrorAction Stop is translated into a function-local $ErrorActionPreference = 'Stop' variable that then promotes any error caused inside the function to what would normally become a script-terminating one, but in the context of an ADVANCED function turns into a statement-terminating one:

# !! 'after' still prints
& { [CmdletBinding()]param() $ErrorActionPreference = 'Stop'; 1 / 0 }; 'after'

# !! Ditto - ErrorAction Stop was NOT effective at the *command level*
& { [CmdletBinding()]param() 1 / 0 } -ErrorAction Stop; 'after'

# !! A SIMPLE function, by contrast, does create a *script*-terminating error: 'after' does NOT print.
& { param() $ErrorActionPreference = 'Stop'; 1 / 0 }; 'after'

But that is an implementation detail of the command, and, strictly speaking, a statement-terminating error that happens to occur inside a function is not the same as a deliberately emitted statement-terminating error, which requires .ThrowTerminatingError().

It fits into the larger theme of cmdlet-like commands implemented in PowerShell not behaving the same as binary cmdlets, as is the case with Write-Error's non-impact on $?

However:

  • Your example isn't susceptible to -ErrorAction Stop in the way that that parameter is intended and is therefore not effective:

    • It only aborts the internal execution of the PowerShell-implemented command (due to an implementation detail), but does not abort execution overall (i.e. no script-terminating / fatal error occurs).
  • By contrast, the subtlety wouldn't even arise with a genuine statement-terminating error, as emitted via .ThrowTerminatingError(), given that it aborts the internal processing of the command right there and then by design.

In short:

  • -ErrorAction Stop is ineffective with respect to statement-terminating errors at the command level,
  • but it can affect when a command implemented in PowerShell aborts processing internally, which is unfortunate.

@mklement0
Copy link
Contributor

As for throw: Yes, it is the only way to explicitly create a script-terminating (fatal) error (and therefore not available to binary cmdlets), but you also get one:

  • with $ErrorActionPreference = 'Stop', with any error (with the exception of internal use in advanced functions).
  • with -ErrorAction Stop, with non-terminating errors.

(And, yes, you can silence / ignore even script-terminating errors with $ErrorActionPreference = 'SilentlyContinue' or $ErrorActionPreference = 'Ignore').

@mklement0
Copy link
Contributor

The bottom line with respect to authoring advanced functions or scripts is:
If you want them to be well-behaved in terms of error handling (on par with binary cmdlets):

  • Only ever use $PSCmdlet.WriteError() and $PSCmdlet.ThrowTerminatingError() to report errors (non-terminating and statement-terminating ones, respectively).

    • This ensures that $? is set correctly (in the caller's scope).
  • Silence or catch any errors that may result from calls to others commands in the implementation, and translate them into one of the above calls, as appropriate.

    • Failure to do so can make your function / script subject to premature termination when invoked with -ErrorAction Stop.

Note that while you're still free to use throw in such a function in order to emit a script-terminating (fatal) error, this would amount to behavior that diverges from that of a binary cmdlet (which cannot emit such errors).


Here's a sample function that demonstrates the necessary techniques:

Function Get-Foo {

  [CmdletBinding()]
  param(
    [string] $Path = '/',
    [string] $NumString = '0'
  )

  # Relay any non-terminating errors from PowerShell-native commands via
  # $PSCmdlet.WriteError(), and any terminating error (including exceptions
  # from expressions / .NET method calls) via $PSCmdlet.ThrowTerminatingError()

  try {

    # Stderr output need not necessarily be silenced - it isn't 
    # affected by -ErrorAction Stop / $ErrorActionPreference = 'Stop'
    & ($IsWindows ? 'cmd' : 'sh') ($IsWindows ? '/c' : '-c') 'echo stderr output >&2'

    # Handle *non-terminating* errors, as happens when $Path doesn't exist.
    # NOTE: 
    #  * If you don't care about any errors, use just -ErrorAction Ignore
    #  * 2>$null does NOT work, as it would abort processing right away
    #    when invoked with -ErrorAction Stop
    # Any cmdlet call that results in *statement-terminating* error would be 
    # handled in the `catch` block.
    (Get-Item $Path -ErrorVariable errs -ErrorAction SilentlyContinue).FullName
    # If errors were captured, relay them via $PSCmdlet.WriteError()
    if ($errs) {
      foreach ($err in $errs) { $PSCmdlet.WriteError($err) }
    }

    # Handle a potential terminating error.
    # If $NumString can't be parsed as an integer, the
    # resulting exception amounts to a statement-terminating error,
    # which is handled in the `catch` block.
    [int]::Parse($NumString)
    
  }
  catch {
    # Relay as a statement-terminating error.
    $PSCmdlet.ThrowTerminatingError($_)
    # Note: To emit a *script*-terminating error instead, use:
    #  throw $_
  }

  'Done.'

}

Some sample calls:

# No errors.
PS> Get-Foo; $?
stderr output
/
0
Done.
True
# Non-terminating error - note that $? is $False, function runs to completion.
PS> Get-Foo NoSuchFile; $?
stderr output
/
0
Done.
False
# Statement-terminating error - note that $? is $False and 'Done' doesn't get to print.
PS> Get-Foo / NotANumber; $?
stderr output
/
Get-Foo: Exception calling "Parse" with "1" argument(s): "The input string 'NotANumber' was not in a correct format."
False
# Both types of errors - note that $? is $False and 'Done' doesn't get to print.
PS> Get-Foo NoSuchFile NotANumber; $?
stderr output
Get-Foo: Cannot find path '/Users/mklement/Desktop/pg/NoSuchFile' because it does not exist.
Get-Foo: Exception calling "Parse" with "1" argument(s): "The input string 'NotANumber' was not in a correct format."
False
# Effect of -ErrorAction Stop on a *non-terminating* error:
#  Becomes *script*-terminating (fatal):
#  * Instantly aborts the function-internal processing.
#  * $? result does not get to print, because execution was aborted overall.
PS> Get-Foo NoSuchFile -ErrorAction Stop; $?
stderr output
Get-Foo: Cannot find path '/Users/mklement/Desktop/pg/NoSuchFile' because it does not exist.
# Effect of -ErrorAction Stop on a *statement-terminating* error:
#  NO effect - $? still gets to print - execution continues.
PS> Get-Foo / NotANumber -ErrorAction Stop; $?
stderr output
/
Get-Foo: Exception calling "Parse" with "1" argument(s): "The input string 'NotANumber' was not in a correct format."
False

@SeeminglyScience SeeminglyScience added the WG-Engine core PowerShell engine, interpreter, and runtime label Oct 28, 2022
Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

1 similar comment
Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

@microsoft-github-policy-service microsoft-github-policy-service bot added Resolution-No Activity Issue has had no activity for 6 months or more labels Nov 15, 2023
Copy link
Contributor

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

Copy link
Contributor

This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs-Triage The issue is new and needs to be triaged by a work group. Resolution-No Activity Issue has had no activity for 6 months or more WG-Engine core PowerShell engine, interpreter, and runtime
Projects
None yet
Development

No branches or pull requests

5 participants