This is going to be a short post because I’m only reiterating what another blogger has already written . I’m reiterating here because more people should understand this.

If you’ve written any amount of powershell, you probably know that Throw does not behave the way that one would expect. James’ post has finally clarified something that has gotten me many times, and I always figured out a way around it, but never understood exactly what was happening.

When you call a function, and you pass that function -ErrorAction SilentlyContinue, or when you set $ErrorActionPreference to 'SilentlyContinue', both of which are actually necessary in some cases, Powershell continues in the case of reaching a Throw in the called function. This is completey unexpected behavior! Apparently the authors of Powershell had different expectations about what -ErrorAction’s purpose was compared to how it ends up used. The caller is likely expecting the execution of their code to SilentlyContinue, but it’s highly unlikely that the’re asking the called function to abandon all error handling…

The answer is very very simple. If you’re writing a function and you’re intending on the use of Throw giving the consumer more control over error handling (you should), always follow that Throw with a Return. This forces Powershell to use Throw the way that all other languages (to my knowledge) use Throw, by always returning from the current function scope, regardless of the actions of the consumer.

Examples:

Function New-Something {
  # ... code here that takes some action

  If ($undesiredThing) {
    Throw "An undesirable thing has occurred"; Return
  }

  # ... code that you don't want to run when the error state has occurred
}

This way, the consumer can use your function and your code will still behave the way you expect it to whether your consumer decides to SilentlyContinue or not.

If you truly intend on giving your consumer the ability to disable error handling within your function, there are more intentional and communicative ways to do it, such as something like a -DisableUndesiredThingChecking switch, like this:

Function New-Something {
  param(
    [switch]
    $DisableUndesiredThingChecking
  )

  # ... code here that takes some action

  If ($undesiredThing -and !$DisableUndesiredThingChecking) {
    Throw "An undesirable thing has occurred"; Return
  }

  # ... code that you don't want to run when the error state has occurred
}