Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect two or more Powershell streams other than output stream to the same file

In Powershell, we can combine the standard output stream with any other stream and then redirect (write) the result to the same file.

Examples:

Powershell -File "C:\myscript.ps1" 2>&1> "C:\log.txt"  
Powershell -File "C:\myscript.ps1" 3>&2>&1> "C:\log.txt"

Suppose I use Write-Error and Write-Warning statements in myscript.ps1 and I want to write only the errors and the warnings to the same file.

Note: if I am not mistaken, 1 is the output stream, 2 is the error stream and 3 the warning stream.

My first logical try was then to use 3>&2> - if combining 1 and 2 works, why would not 3 and 2 ? See below:

Powershell -File "C:\myscript.ps1" 3>&2> "C:\log.txt"

However, 3>&2> does not work as a valid redirect operator.

I could get around trying:

Powershell -File "C:\myscript.ps1" 3>"C:\warninglog.txt" 2>"C:\errorlog.txt"
but I really want to write to the same file.

If I try to run:

Powershell -File "C:\myscript.ps1" 3>"C:\log.txt" 2>"C:\log.txt" 

it seems the error stream (2) never gets written to log.txt because file is locked by the warning stream.

Is there a way to combine two (or more) output streams into a single stream and redirect the result to the same file ?

like image 589
Kano Chodapra Avatar asked Jun 18 '15 04:06

Kano Chodapra


2 Answers

The verbose, warning, and debug streams are merged into STDOUT when you run PowerShell scripts via

powershell -File "C:\myscript.ps1"

so you can't redirect them separately anymore. Only the error stream is different, since it seems to go to both STDOUT and STDERR, where it can be redirected by 1> as well as 2>.

Demonstration:

C:\>type test.ps1
$DebugPreference = "Continue"
$VerbosePreference = "Continue"
Write-Output "Output message"
Write-Error "Error message"
Write-Verbose "Verbose message"
Write-Warning "Warning message"
Write-Debug "Debug message"

C:\>powershell -File .\test.ps1
Output message
C:\test.ps1 : Error message
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,test.ps1

VERBOSE: Verbose message
WARNING: Warning message
DEBUG: Debug message

C:\>powershell -File .\test.ps1 2>nul 3>nul 4>nul 5>nul
Output message
VERBOSE: Verbose message
WARNING: Warning message
DEBUG: Debug message

C:\>powershell -File .\test.ps1 1>nul

C:\>_

If you want to redirect the verbose, warning, or debug stream separately you must use -Command instead of -File and do the redirection within PowerShell:

C:\>powershell -Command ".\test.ps1 2>$null 3>$null 5>$null"
Output message
VERBOSE: Verbose message

However, while in CMD you can redirect any handle to any other handle (3>&2, 1>&5, ...), PowerShell redirection only supports redirection to either a file (3>C:\out.txt) or the success output stream (3>&1). Trying to redirect to any other stream will throw an error:

C:\>powershell -Command ".\test.ps1 2>out.txt 3>&2"
At line:1 char:22
+ .\test.ps1 2>out.txt 3>&2
+                      ~~~~
The '3>&2' operator is reserved for future use.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : RedirectionNotSupported

as will redirecting different streams to the same file:

C:\>powershell -Command ".\test.ps1 2>out.txt 3>>out.txt"
out-file : The process cannot access the file 'C:\out.txt' because it is being
used by another process.
At line:1 char:1
+ .\test.ps1 2>out.txt 3>>out.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (:) [Out-File], IOException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand

If merging warning and success output is an option for you, you could do something like this:

powershell -Command ".\test.ps1 >out.txt 3>&1 2>error.log"

or like this:

powershell -Command ".\test.ps1 >out.txt 3>&1 2>&1"

or (redirecting all streams) like this:

powershell -Command ".\test.ps1 *>out.txt"

Otherwise the only option I see is to redirect to different files:

powershell -Command ".\test.ps1 3>warning.log 2>error.log"
like image 162
Ansgar Wiechers Avatar answered Sep 30 '22 13:09

Ansgar Wiechers


You can redirect the error and warning stream to the output stream separately so instead of doing this

  3>&2>&1

you should be doing this

  3>&1 2>&1

Adapted from Understanding streams

function Write-Messages
{
    Write-Host "Host message"
    Write-Output "Output message"
    Write-Verbose "Verbose message"
    Write-Warning "Warning message"
    Write-Error "Error message"
    Write-Debug "Debug message"
}

$DebugPreference = "Continue"
$VerbosePreference = "Continue"

Write-Messages 3>&1 2>&1 > $env:TEMP\test.txt

Applied to your example, this would become

Powershell -File "C:\myscript.ps1" 3>&1 2>&1> "C:\log.txt"

or you can redirect all streams to your file

Powershell -File "C:\myscript.ps1" *> "C:\log.txt"
like image 27
Lieven Keersmaekers Avatar answered Sep 30 '22 12:09

Lieven Keersmaekers