Search code examples
powershellerror-handlingruntime-error

PowerShell, tell a script to output all errors to a text file


I have a PowerShell script that is the startup script for Windows Sandbox and so it runs silently.

Is it possible to put some kind of declaration within a PowerShell script, say at the start of the script, that tells the silently running script to output all of its errors to a text file?

Edit (for Fitzgery's comment): it is not possible for me to use redirection for the script because it is running silently as part of the Windows Sandbox startup. I would like something within the script itself to instruct the running script to output all errors to a text file.


Solution

  • Try the following, which relies on the fact that all errors that occur in a session get recorded in the automatic $Error variable:

    $Error.Clear() # Reset the session's error log so far
    
    try {
    
      # ... your script
    
    } finally {
      # Save all errors that occurred in this script to a file.
      $Error > errors.txt
    }
    

    Caveat:

    • The use of a try statement has a side effect:

      • Your script may terminate prematurely, because any normally only statement-terminating error becomes a script-terminating error and therefore instantly triggers the finally clause; that said, statement-terminating errors aren't common, and it's arguably better to abort execution when they occur (unanticipated).
    • If you were to omit the try statement and simply placed $Error > errors.txt at the end of your script, (non-terminating and) statement-terminating errors would be handled as usual, but the $Error > errors.txt statement would never get to execute if a script-terminating error occurred.


    An alternative solution using trap is side effect-free only if you know your script not to produce script-terminating errors:

    • Script-terminating errors are those explicitly created with throw, or implicitly via -ErrorAction Stop or $ErrorActionPreference = 'Stop'

    • The (rarely used anymore) trap statement allows you to act on errors without stopping execution, namely if you do not use break in the script block you pass to it.

      • While it therefore continues after non-terminating and statement-terminating errors, as during normal execution, it also continues after script-terminating ones.

      • Therefore, the side effect - if you script does create script-terminating errors, is that it may not stop your script when you expect it to.

    # Create or truncate the target file.
    $errLogFile = New-Item errors.txt -Force
    
    # Traps all errors and logs them in the target ffile.
    # Note:
    #  * Using neither `break` or `continue` in the script block
    #    still also prints the error and continues execution.
    #  * CAVEAT: Even *script*-terminating errors then
    #            do NOT abort execution.
    trap { $_ >> $errLogFile }
    
    # ... your script 
    

    Use of Start-Transcript:

    • Start-Transcript is an way to capture all of a script's output, not just errors (that is, output from all of PowerShell's output streams is logged, notably including success output (data) - you get no choice).

    • It must be paired with Stop-Transcript to close the transcript file.

      • If you neglect to call Stop-Transcript, the transcript stays open and continues logging for the remainder of the session.

      • In order to ensure that Stop-Transcript is called, you're faced with the same tradeoffs as above:

        • Calling it in the finally block of a try statement may abort execution prematurely.
        • Use of a trap statement without break may not stop execution when it should.
      • That said, if the execution of your script is the only thing happens in your session - such as in a CLI call with -File - not calling Stop-Transcript won't be a problem, and ensures side effect-free logging - albeit invariably including all of the script's output, as noted.