Puffy_Fluff
Puffy_Fluff

Reputation: 155

Redirect output from a Windows batch file within the script

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

Answers (1)

mklement0
mklement0

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

Related Questions