1

I want to capture and log all output (redirecting stderr) from Invoke-Expression calls, but by doing that any exception that would normally be thrown seems to be swallowed.

Assuming c:\temp\test already exists this command will throw an exception:

PS U:\> $cmd = "mkdir c:\temp\test"
PS U:\> $output = Invoke-Expression $cmd
New-Item : Item with specified name C:\temp\test already exists.
At line:38 char:24
+         $scriptCmd = {& <<<<  $wrappedCmd -Type Directory @PSBoundParameters }
    + CategoryInfo          : ResourceExists: (C:\temp\test:String) [New-Item], IOException
    + FullyQualifiedErrorId : DirectoryExist,Microsoft.PowerShell.Commands.NewItemCommand

But, if I redirect stderr, then nothing happens:

PS U:\> $cmd = "mkdir c:\temp\test 2>&1"
PS U:\> $output = Invoke-Expression $cmd
PS U:\>

This is a simplified example, and I'm using Invoke-Expression in a function for many types of calls, and logging the output. So it is not just a matter of making this call work.

Furthermore not capturing the output will also throw the exception correctly:

PS U:\> $cmd = "mkdir c:\temp\test 2>&1"
PS U:\> Invoke-Expression $cmd
New-Item : Item with specified name C:\temp\test already exists.
At line:38 char:24
+         $scriptCmd = {& <<<<  $wrappedCmd -Type Directory @PSBoundParameters }
    + CategoryInfo          : ResourceExists: (C:\temp\test:String) [New-Item], IOException
    + FullyQualifiedErrorId : DirectoryExist,Microsoft.PowerShell.Commands.NewItemCommand

I see that $Error actually contains the exception, but I don't know if I can be sure that it contains only errors related to the Invoke-Expression call.

But the question stands. How can I capture all output (including stderr) from Invoke-Expression, and still get exceptions thrown?

Rassi
  • 1,612
  • 14
  • 21
  • Related http://stackoverflow.com/questions/10666101/powershell-lastexitcode-0-but-false-redirecting-stderr-to-stdout-gives-nat – Rassi Jun 21 '13 at 07:38

1 Answers1

2

$Error is an array that buffers errors. The most recent error is stored in $error[0]. You could use this in combination with $LASTEXITCODE and $?

For your case I think -ErrorVariable is more appropriate. It is a common variable. See get-help about_commonparameters for more information. The syntax is -ErrorVariable [+]<variable-name>. For example, the following command creates the $e variable and then stores any errors from Invoke-Expression in it:

Invoke-Expression $cmd -ErrorVariable e

Note that $e can contain more than one error.

So, to answer your question about how to capture all output, and still show errors:

$output = Invoke-Expression $cmd -ErrorVariable e
Davor Josipovic
  • 5,296
  • 1
  • 39
  • 57
  • Sorry, this does not work. $e is empty when running this $output = iex "mkdir c:\temp\test 2>&1" -ErrorVariable e – Rassi Jun 21 '13 at 06:20
  • $? is true after the command has been run, but $LASTEXITCODE at least shows something. – Rassi Jun 21 '13 at 06:35
  • `$e` is empty because you are redirecting your `STDERR` to `STDOUT`! – Davor Josipovic Jun 21 '13 at 08:09
  • Redirecting STDERR is very much a core part of my question, and your answer stated that using ErrorVariable would allow me to get errors as well as capture all output. – Rassi Jun 21 '13 at 08:48
  • 1
    With `$output = iex "mkdir c:\temp\test -ErrorVariable e`, `STDOUT` is captured in `$output`, `STDERR` is captured in `$e` and at the same time the exception is thrown. I thought that was your initial question. If you also want to redirect the errors to `$output`, then do `$output += $e` after invocation. – Davor Josipovic Jun 21 '13 at 15:25
  • Thank you. That works great. I didn't understand that I could do without stderr redirection. – Rassi Jun 24 '13 at 07:00