Search code examples
powershellstdoutstderrio-redirection

Suppress NativeCommandError output when redirecting stdout and stderr to separate files


I have the following files:

test.ps1

& e:\test.bat > stdout.txt 2> stderr.txt

test.bat

@echo off
echo write to stdout
echo write to stderr >&2

When I call test.ps1 like this:

powershell -ExecutionPolicy bypass e:\test.ps1

The output files look like this:

stdout.txt

write argument to stdout

stderr.txt

test.bat : write to stderr 
At E:\test.ps1:5 char:1
+ & "$application" "$argument" > $stdout 2> $stderr
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (write to stderr :String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

There is an answer how to prevent the NativeCommandError output from being written to file when redirecting both stdout and stderr to the same file, but how can I achieve that when writing to different files?


Solution

  • To build on the helpful comments:

    • In PowerShell (Core) 7+, your command would work as expected.

    • In Windows PowerShell, unfortunately, stderr lines are implicitly formatted as if they were PowerShell errors when a 2> redirection is involved, resulting in the noisy output you saw.

    The solution is to merge stderr into stdout with 2>&1, and separate the collected lines into stdout and stderr by their type, allowing you to stringify the stderr lines, which PowerShell wraps in [System.Management.Automation.ErrorRecord] instances, via their .ToString() method, which results in their text content only.

    Apart from being cumbersome, this approach requires collecting all output in memory first.

    $stdout, $stderr = (& e:\test.bat 2>&1).Where({ $_ -is [string] }, 'Split')
    
    $stdout > stdout.txt
    $stderr.ForEach('ToString') > stderr.txt