Reputation: 155
I am trying to make a Windows batch file (the main script) redirect all of it's output to a file while still displaying it on the screen. I cannot change all the code that calls the main script - I need to change the main script itself.
I have a solution that requires "bootstrapping" the main script by calling it again from another bat file (tee_start.bat). What I'm sure I want to avoid is refactoring all the other scripts that call main.bat to use the tee command - it will be a much smaller, safer change if I can put some new code in main.bat.
Is there a way to do this that does not involve restarting the main file as I am doing below? For example, is there a cmd.exe or powershell.exe command that says "Take my current STDOUT and tee it" - or does tee somehow support this behavior and I missed it? Or, alternatively, should I settle for what I have implemented as the least invasive method?
I have implemented a solution as follows:
main.bat
REM this is an example of bootstrap mode - it will restart this main script with all output logged
call tee_start.bat %~dpnx0 %*
echo This output should appear both in the screen console and in a log file
tee_start.bat
REM in order to bootstrap the output redirection - this script gets called twice - once to initialize logging with powershell tee command
REM second time, it just echoes log information and returns without doing anything
if x%LOG_FILE% neq x (
echo Bootstrapped Process: %1%
echo Escaped Arguments: %ADDL_ARGS%
echo Log File: %LOG_FILE%
goto :EOF
)
set ADDL_ARGS=
:loop_start
shift
if x%1 == x goto :after_loop
REM preserve argument structure (quoted or not) from the input
set ADDL_ARGS=%ADDL_ARGS% \"%~1\"
goto loop_start
:after_loop
SET LOG_FILE=/path/to/some/logfile.log
powershell "%1% %ADDL_ARGS% 2>&1 | tee -Append %LOG_FILE%"
Upvotes: 2
Views: 448
Reputation: 437111
I suggest the following approach, which makes do without the aux. tee_start.bat
file:
main.bat
content (outputs to log.txt
in the current folder; adjust as needed):
@echo off & setlocal
if defined LOGFILE goto :DO_IT
set "LOGFILE=log.txt"
:: Reinvoke with teeing
"%~f0" %* 2>&1 | powershell -NoProfile -Command "$input | Tee-Object -FilePath \"%LOGFILE%\"; \"[output captured in: %LOGFILE%]\""
exit /b
:DO_IT
:: Sample output
echo [args: %*]
echo to stdout
echo to stderr >&2
echo [done]
Tee-Object
uses a fixed character encoding, which is notably "Unicode" (UTF-16LE) in Windows PowerShell (powershell.exe
), and (BOM-less UTF-8) in PowerShell (Core) 7+ (pwsh.exe
).Upvotes: 4