The idea is to prevent duplicate lines of code for those who need to log what they are doing.
See the examples in the code.
Code: Select all
@echo off
prompt $
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION
SETLOCAL
SET RETURNCODE=99
:: Set Smart logging features, eliminating duplicate code.
:: Avoid using in FOR loop functions for now, hoping to remediate.
::
:: Define temporary files
SET "LogFile=LOGFILE.TXT"
IF NOT EXIST "%temp%" MKDIR "%temp%" 1>NUL 2>&1
SET "FTMP=%TEMP%\FTMP.tmp"
:: Clear earlier ftmp because of ntfs streams associated with the file.
del /q /f "%FTMP%" >nul 2>nul
echo.>"%FTMP%"
SET "FCM0=%TEMP%\FCM0.tmp"
:: Clear earlier fcm0 because of ntfs streams associated with the file.
del /q /f "%FCM0%" >nul 2>nul
echo.>"%FCM0%"
:: echo Prompt 1 %PR1%
:: Sends echo to LOG file only. (multiline capture possible)
SET PR1=^>"!ftmp!":1 ^& MORE ^<"!ftmp!":1 ^1^>^>"%LogFile%" ^2^>^>^&^1
:: echo Prompt 2 %PR2%
:: Same as PR1, but now sends echo to console and LOG file. (multiline capture possible)
SET PR2=^>"!ftmp!":2 ^& MORE ^<"!ftmp!":2 ^& MORE ^<"!ftmp!":2 ^1^>^>"%LogFile%" ^2^>^>^&^1
:: echo Prompt 3 %PR3%
:: Sends echo to LOG file with %DATE% and %TIME% stamp only. (one echo per line; NO multiline capture possible.)
SET PR3=^>"!ftmp!":3 ^& ^( SET /P OUT=MORE ^<"!ftmp!":3 ^)^>nul ^& CALL ECHO [%%PDATE%%;%%TIME%%] %%OUT%% ^1^>^>"%LogFile%" ^2^>^>^&^1
:: echo Prompt 4 %PR4%
:: Sends echo to console and LOG file with %DATE% and %TIME% stamp for LOG only. (one echo per line; NO multiline capture possible.)
SET PR4=^>"!ftmp!":4 ^& ^( SET /P OUT=MORE ^<"!ftmp!":4 ^)^>nul ^& MORE ^<"!ftmp!":4 ^& CALL ECHO [%%PDATE%%;%%TIME%%] %%OUT%% ^1^>^>"%LogFile%" ^2^>^>^&^1
:: Invoke commands and log them!
rem echo DIR %TEMP% %CM1%
rem Sends command as date-time stamped to log with [START] label, then invokes it, redirects output to `"!FCM0!":run`, displays the result to LOG only, closes with [END] label.
SET CM1=^>"!FCM0!":1 ^& ^( SET /P OUT=MORE ^<"!FCM0!":1 ^)^>nul ^& CALL :CM1
rem echo DIR %TEMP% %CM2%
rem Sends command as date-time stamped to log with [START] label, then invokes it, redirects output to `"!FCM0!":run`, displays the result to CONSOLE and LOG, closes with [END] label.
SET CM2=^>"!FCM0!":2 ^& ^( SET /P OUT=MORE ^<"!FCM0!":2 ^)^>nul ^& CALL :CM2
rem echo DIR C:\WINDOWS %CM3%
rem Same as CM2, but uses powershell to invoke the command and read/write date-time stamps for each item in the loop to the log.
SET CM3=^>"!FCM0!":3 ^& ^( SET /P OUT=MORE ^<"!FCM0!":3 ^)^>nul ^& CALL :CM3
:: ================================================================================
rem Examples:
(
ECHO.
ECHO Hello World!
ECHO These lines only show up in your log file!
) %PR1%
(
ECHO.
ECHO Hello World again!!
ECHO This line should show in the console and the log file!
) %PR2%
ECHO Start logging for app1.exe %PR3%
ECHO Start logging for app2.exe %PR4%
echo DIR %TEMP% %CM1%
echo DIR %TEMP% %CM2%
echo DIR %WINDIR% %CM3%
goto :END
:: ================================================================================
:: SCRIPT FUNCTIONS BELOW.
:: ================================================================================
:: Script FUNCTION :CM1 ================================================================
:CM1
CALL ECHO [%PDATE%;%TIME%] [START]: %OUT% >>"%LogFile%"
ECHO =====CM1======================================================================== >>"%LogFile%"
CALL %OUT% 1>"%FCM0%" 2>&1
type "%FCM0%" >>"%LogFile%"
ECHO =====CM1======================================================================== >>"%LogFile%"
CALL ECHO [%PDATE%,%TIME%] [END] >>"%LogFile%"
GOTO :EOF
:: Script FUNCTION :CM2 ================================================================
:CM2
CALL ECHO [%PDATE%;%TIME%] [START]: %OUT% >>"%LogFile%"
ECHO =====CM2======================================================================== >>"%LogFile%"
CALL %OUT% 1>"%FCM0%" 2>&1
type "%FCM0%"
type "%FCM0%" >>"%LogFile%"
ECHO =====CM2======================================================================== >>"%LogFile%"
CALL ECHO [%PDATE%,%TIME%] [END] >>"%LogFile%"
GOTO :EOF
:: Script FUNCTION :CM3 ================================================================
:CM3
CALL ECHO [%date%;%time%] [START]: %OUT% >>"%LogFile%"
ECHO =====CM3======================================================================== >>"%LogFile%"
CALL :createPowerShellScript "%out%" "%LogFile%"
start /min /wait /b C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noprofile -noninteractive -ExecutionPolicy ByPass -file "%temp%\cm3.ps1"
SET RETURNCODE=!ERRORLEVEL!
ECHO [RETURN CODE=%RETURNCODE%] %PR2%
CALL ECHO [%date%;%time%] [END] >>"%LogFile%"
GOTO :EOF
:: Private FUNCTION for :CM3 ================================================================
:createPowerShellScript
REM Parameters
REM %1 - Command to execute
REM %2 - Log file to write
set "command=%~1"
set "logFile=%~2"
(
rem echo Set-ItemProperty -Path "Registry::HKEY_CURRENT_USER\Console" -Name "FaceName" -Value "Lucida Console" -Type String
echo . $env:windir\System32\chcp.com 65001
echo '%command%'
echo $Height = 30
echo $Width = 120
echo $console = $host.ui.rawui
echo $ConBuffer = $console.BufferSize
echo $ConSize = $console.WindowSize
echo $currWidth = $ConSize.Width
echo $currHeight = $ConSize.Height
echo # if height is too large, set to max allowed size
echo if ^($Height -gt $host.UI.RawUI.MaxPhysicalWindowSize.Height^)
echo ^{
echo $Height = $host.UI.RawUI.MaxPhysicalWindowSize.Height
echo ^}
echo # if width is too large, set to max allowed size
echo if ^($Width -gt $host.UI.RawUI.MaxPhysicalWindowSize.Width^)
echo ^{
echo $Width = $host.UI.RawUI.MaxPhysicalWindowSize.Width
echo ^}
echo # If the Buffer is wider than the new console setting, first reduce the width
echo if ^($ConBuffer.Width -gt $Width^)
echo ^{
echo $currWidth = $Width
echo ^}
echo # If the Buffer is higher than the new console setting, first reduce the height
echo if ^($ConBuffer.Height -gt $Height^)
echo ^{
echo $currHeight = $Height
echo ^}
echo # initial resizing if needed
echo $host.UI.RawUI.WindowSize = New-Object System.Management.Automation.Host.size^($currWidth, $currHeight^)
echo # Set the Buffer
echo $host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.size^($Width, 2000^)
echo # Now set the WindowSize
echo $host.UI.RawUI.WindowSize = New-Object System.Management.Automation.Host.size^($Width, $Height^)
echo $command = '%command%'
echo $logFile = '%logFile%'
echo $startInfo = New-Object System.Diagnostics.ProcessStartInfo
echo $startInfo.FileName = 'cmd.exe'
echo $startInfo.Arguments = '/c ^' + $command + ^''
echo $startInfo.RedirectStandardOutput = $true
echo $startInfo.UseShellExecute = $false
echo $startInfo.CreateNoWindow = $true
echo $process = New-Object System.Diagnostics.Process
echo $process.StartInfo = $startInfo
echo $process.Start^(^)^| Out-Null
echo $streamReader = $process.StandardOutput
echo $fs = [System.IO.File]::AppendText^($logFile^)
echo while ^($null -ne ^($line = $streamReader.ReadLine^(^)^)^) ^{
echo ^ $dateTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
echo ^ Write-Host $line
echo ^ $fs.WriteLine^("[$dateTime] $line"^)
echo ^}
echo $fs.Close^(^)
echo $process.WaitForExit^(^)
echo exit $process.exitcode
rem echo [System.Environment]::Exit^($process.exitcode^)
) > "%temp%\cm3.ps1"
exit /b
:END
prompt
ENDLOCAL