2

I'm running a server from a batch file and I want the server output to be displayed both on the screen and also written to a log file. I found a way to do this from this answer:

powershell "startmyserver | tee server.log"

The problem is that the pipe causes the first command to run and fully complete before the second command runs. This means I can't monitor my server's stdout while it's actually running, which is what I'm trying to do (I don't want to have to shut down the server just to check the most recent log messages).

For a more simple example I tried pause. Well, pause doesn't exist on Powershell, so I had to run it inside a nested cmd shell:

powershell "cmd /c pause | tee test.txt"

Unsurprisingly, after executing this command I just get a flashing cursor. After a while, I press a key, and then "Press any key to continue" appears and is written to the file at nearly the same time.

What I want to happen is the pipe to stream the stdout line by line to the next command. In other words whenever it encounters an EOL character it should send some output and this should (in my case of tee) cause the text to appear on the screen and simultaneously written to the file. (In fact, I'm even not bothered about whether the text is written to the file line-by-line, it could be written all at the end although that would not be ideal. I just want to be able to see the lines on the screen as they are written.)

Is this possible in Command Prompt and/or Powershell?

  • @PimpJuiceIT I think it does matter with the double quote positions. If you run powershell cmd /c pause | tee "test.txt" you are running tee in your current context. I'm running this from cmd (not ps1) so this command will fail as tee is a Powershell command. if this command worked for you I assume either (a) you have another tee on your system or (b) you ran this from within Powershell. Neither of which are my use case. – Kidburla Nov 1 '18 at 19:10
  • @PimpJuiceIT do you have another example of a command I could use rather than pause? I used pause just for convenience because I didn't want a command that would terminate straight away and therefore make it impossible to tell whether the lines were streamed before the command completed – Kidburla Nov 1 '18 at 22:18
  • Maybe sleep perhaps but it appears you found a working solution so it's all moot now. – Pimp Juice IT Nov 1 '18 at 23:16
1

This problem is explained on Stack Overflow as the fact that the PowerShell Tee-Object doesn't flush the output stream, but only waits for the source to do it, so you get the output at the end of the operation. This is by design.

The workaround proposed in the answer was to use this code:

./program | ForEach-Object {
    Write-Host $_
    $_
} | Set-Content program.log

An alternative formulation to try if the above one didn't work is:

./program | ForEach-Object {
    [Console]::WriteLine($_)
    [Console]::Out.Flush()
    $_
} | Set-Content program.log

So the command would look like :

PowerShell -ExecutionPolicy Unrestricted "startmyserver | ForEach-Object { Write-Host $_; $_} | Set-Content server.log"

In my modest testing the output was generated too fast for me to see if this worked as you specified.

  • Thanks! Do you have any idea how to (a) make this write both stdout and stderr, (b) append to a file that already exists rather than creating a new one? – Kidburla Nov 1 '18 at 23:02
  • 1
    See this post. – harrymc Nov 2 '18 at 8:36
  • Thanks, and I managed to resolve part (b) by using Add-Content rather than Set-Content – Kidburla Nov 2 '18 at 14:26

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.