1

We use the below function in one of our PowerShell scripts. Can someone explain what "2>&1" means here? Is there any equivalent full cmdlet to replace this value?

function InvExp {
    param (
        [string]$cmd
    )
        $er = (invoke-expression $cmd) 2>&1
        if($er.Exception){
            throw $er.Exception
        }
} 
POSH Guy
  • 1,798
  • 2
  • 11
  • 15
  • 1
    "Redirect stderr to stdout" or in PowerShell, "Redirect Error Stream to Success Stream", that's what `2>&1` means. And the other way around would be using a `try` / `catch` statement – Santiago Squarzon Jul 06 '22 at 16:20
  • try catch will not work with invoke-expression command. that is the reason we are using this function – POSH Guy Jul 06 '22 at 16:21
  • 1
    not sure what you mean, `try { iex 'asd' } catch { 'hello' }` works perfectly fine – Santiago Squarzon Jul 06 '22 at 16:22
  • 1
    You are essentially turning even non-critical errors of `$cmd` such as produced by `Write-Error`, into exceptions, but the way you are doing it, you are losing PowerShell-specific error information from the error record `$er`, such as the script stacktrace. – zett42 Jul 06 '22 at 16:43
  • @SantiagoSquarzon.. Please check below command try { iex -Command "Get-Process test" } catch { 'hello' } – POSH Guy Jul 06 '22 at 17:57
  • I see what you mean, easiest way I could imagine to get around this would be: `try { & {[CmdletBinding()]param() iex -Command "Get-Process test" } -EA 1 } catch { 'hello' }` – Santiago Squarzon Jul 06 '22 at 18:02
  • Or try catch the invocation of your function instead Or, if you're going to invoke and actual cmdlet don't use `Invoke-Expression`, tbh don't see the point of your function in a real world example – Santiago Squarzon Jul 06 '22 at 18:21
  • @SantiagoSquarzon... get-process cmdlet works.. But this cmdlet does not works... try { & {[CmdletBinding()]param() invoke-expression -Command "Get-CsOnlineUser wrongsip@test.com" } -EA 1 } catch { write-host test} – POSH Guy Jul 06 '22 at 18:35
  • 2
    I'm sorry I don't really see the point of a function that is used to invoke an expression that invokes a cmdlet. Besides, if you're passing an expression that contains the invocation of a cmdlet you could mind as well add `-EA 1` to the cmdlet invocation itself: `try { iex "Get-CsOnlineUser wrongsip@test.com -EA 1" } catch { 'something' }` – Santiago Squarzon Jul 06 '22 at 18:38

1 Answers1

1

As Santiago Squarzon notes, 2>&1 is a redirection (>) that redirects output stream number 2 (the error stream) into (&) stream number 1 (the success stream).

  • When calling external programs, 2 in redirections refers to such a program's stderr output, and 1 (the default stream) to its stdout output.

What your function in effect does is to promote any error - irrespective of whether it is a non-terminating or a (statement-)terminating error - to a fatal error (script-terminating aka runspace-terminating error).

However, I propose a simpler implementation, which also avoids the use of Invoke-Expression, which is generally to be avoided, by instead requiring that a script block ({ ... }) rather than a string be passed as an argument:

function Assert-NoError {
  param(
    [scriptblock] $cmd
  )
  $ErrorActionPreference = 'Stop'
  . $cmd
}

You would then invoke the function as follows, for example:

Assert-NoError { Get-Process test }

Note:

  • $ErrorActionPreference = 'Stop' creates a local instance of the the $ErrorActionPreference preference variable, and by setting it to Stop ensures that any error results in a fatal error by default.

  • The above implementation has the added advantage that any success output that precedes an error is output before execution is aborted.

mklement0
  • 382,024
  • 64
  • 607
  • 775