Redirect stderr using Tee-Object (unexpected behavior)

Hi Guys

Hi Guys I am a little bit confused. I have problem with redirect stdout and stderr from python script to text file in PowerShell. I have created example code in python:

script.py


    import sys    
    print("This is standard output")
    print("This is error", file=sys.stderr)

Then I am trying to redirect output and stderr to file like this:

python .\script.py *>&1 | Tee-Object -FilePath out.txt

I am getting all the time error that is not expected. After execute above command I should receive out.txt with two line text. First line: “This is standard output” and second line: “This is error”.
Unfortunately I received below output:

This is standard output
python : This is error
At line:1 char:1
+ python .\test_script.py *>&1 | Tee-Object -FilePath wyjscie.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (This is error:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Can someone point what is wrong with above redirection or generally what I am doing wrong? Using 2>&1 redirection also cause the same error.

Expected output (like in linux systemm using tee command and 2>&1):

This is standard output
This is error

I’m almost wondering if this has more to do with the Python part of it than the Powershell part of it.
I don’t have Python on my Windows machine, but I tried with some other native windows commands and honestly just couldn’t come up with an error inducing scenario off the top of my head.
I pulled up an Ubuntu box really quick with Python3 and Powershell 7 and made a python script just like yours and ran it with *>&1 as well as 2>&1 and either way the second line of text “This is error” showed up red.

The error text you provided:

At line:1 char:1
+ python .\test_script.py *>&1 | Tee-Object -FilePath wyjscie.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (This is error:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Is specifically saying “NativeCommandError” which implies it’s on the python side. But I’m guessing it’s more to do with how the Python script is throwing an error in your Windows environment. I don’t know, i’m not 100% sure here.

Thank You for your effort.

Well, doing the same in CMD under windows I am getting the same reply like in linux:

python .\test_script.py 2>&1 | tee out.txt
This is error
This is standard output

Of course I cannot use Tee-Object under CMD. But if it was a python fault in CMD I would receive the same error like in Powe Shell but I am not.

well it’s not 1 for 1 here. The error message you quoted is a Powershell error message. You would never get that in CMD for obvious reasons, but in Powershell again it seems like Python has thrown a terminating error and Powershell is halting because of that.
I’ll have to double check but if it’s a terminating error I don’t know if it will continue to the pipeline and beyond it might just stop right there.

Ok installed python on a Windows machine so I could replicate this 1:1.


Getting acclimated here it looks like without error stream redirection the python script is only outputting one object to the pipeline, a string. WITH redirection there’s two objects getting sent through the pipeline, one string and one error record.
I think then the confusion might be coming from how Tee-Object in Powershell might differ.
Tee-Object
By default Tee-Object sends the input object to two places; the filepath AND the pipeline. If there is no additional pipe statement then that second output would be standardout, or the console right?

Replicating your initial post:


I get two objects input to Tee-Object (the string “This is standard output” and the Error record), it correctly sends both objects to the filepath AND to the pipeline (output here).
The contents of out.txt look like this:

This is standard output
.\python.exe : This is error
At line:1 char:1
+ .\python.exe C:\temp\test_script.py 2>&1| Tee-Object -FilePath c:\tem ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (This is error:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
 

So i’ve got a 1:1 copy of what was output to the console. I think then that this is working by design and is more of an issue of mixing languages together.
If you simply want to record an error message like “This is an error” you don’t need an actual ErrorRecord object for that you can just pass the text out right?
If you want to deal with the objects themselves you can do something kind of hacky like this:

.\python.exe C:\temp\test_script.py 2>&1| %{if($_.Gettype().name -eq "ErrorRecord"){$_.Exception}else{$_}} | Tee-Object -FilePath c:\temp\out.txt


and out.txt contains:

This is standard output
This is error

What we did there was redirect the error stream from the first execution to standard out, pipe that to % (Foreach-Object) and do a simple comparison:

if ($_.GetType().Name -eq "ErrorRecord") {
    $_.Exception
}

We look at the time of the object with the built-in GetType method, then pull the Name property from there. If it’s an ErrorRecord its name will match. If that logic proves true then on that object we call the Exception property which will be your original text from Python.
Else, we just pass the object on. So basically we shimmed another pipeline inbetween your python and your Tee-Object.

1 Like