1

I am making a batch code to execute commands and capture result in files, while also keeping the output on screen.

For programs with fast execution and simple output of one line after another I have found a solution.

This solution does not seem to work unfortunately with commands that have a progress bar on the screen. The output of the progress line is spread in the following lines and this is not wanted.

For example this:

@echo off
rem Warning! Run as administrator. 
rem go safe place for testing...
cd /D "%temp%"

for %%C in (
    "chkdsk /scan"
    "dism /online /cleanup-image /scanhealth"
    "sfc /scannow"
) do ( 
    rem Partially simulates "echo on" on commands. 
    echo(%CD%^>%%~C
    rem Execute command.
    %%~C
)

I would like to keep the original output and keep the time progress on the screen, while on file I would like the final output or in any case the possibility to extract it.

I tried to re-route the output to file but I should re-read and reformat it, maybe there is a better solution.

Is there a way this can be achieved?

I'm open to workarounds involving batch files and PowerShell


i tried to run this command in powershell but the result on screen is not what i want:

PS C:\Users\fposc\AppData\Local\Temp> chkdsk /scan *>&1 | Tee-Object -Variable Tee
Il file system è di tipo NTFS.
L'etichetta del volume è Windows.

Fase 1: analisi della struttura del file system di base in corso...
Avanzamento: 0 di 536592 completati. Fase:  0%, totale:  0%, ETA:   0:25:49
Avanzamento: 1630 di 536592 completati. Fase:  0%, totale:  0%, ETA:   0:25:48 .
Avanzamento: 4549 di 536592 completati. Fase:  0%, totale:  0%, ETA:   0:25:45 ..
Avanzamento: 6765 di 536592 completati. Fase:  1%, totale:  0%, ETA:   0:03:36 ...
Avanzamento: 10756 di 536592 completati. Fase:  2%, totale:  0%, ETA:   0:03:18
Avanzamento: 10803 di 536592 completati. Fase:  2%, totale:  0%, ETA:   0:04:22 .
Avanzamento: 13373 di 536592 completati. Fase:  2%, totale:  0%, ETA:   0:04:30 ..
Avanzamento: 16728 di 536592 completati. Fase:  3%, totale:  1%, ETA:   0:04:12 ...
Avanzamento: 23233 di 536592 completati. Fase:  4%, totale:  1%, ETA:   0:03:39

EDIT I have tried the answer of Cpt.Whale and this work very well. The output on screen is kept as the original command

C:\WINDOWS\system32>echo chkdsk /scan | powershell -c "Start-Transcript tee.txt -Force; Invoke-Expression $input; Stop-Transcript"
Trascrizione avviata. File di output: tee.txt
Il file system è di tipo NTFS.
L'etichetta del volume è Windows.

Fase 1: analisi della struttura del file system di base in corso...
  536592 record file elaborati.
Verifica file completata.
Durata fase (Verifica record di file): 58.78 secondi.
  39496 record di file di grandi dimensioni elaborati.
Durata fase (Recupero record di file orfani): 0.00 millisecondi.
...
  10504959 unità totali di allocazione su disco.
   3520856 unità di allocazione disponibili su disco.
Durata totale: 1.87 minuti (112741 ms).
Trascrizione arrestata. File di output: C:\WINDOWS\system32\tee.txt

C:\WINDOWS\system32>

but the file has problem: look at "´╗┐" and "├¿"

C:\WINDOWS\system32>type C:\WINDOWS\system32\tee.txt
´╗┐**********************
Inizio trascrizione Windows PowerShell
Ora di inizio: 20210425161211
Nome utente: PC-ASUS\fposc
Esegui come utente: PC-ASUS\fposc
Nome configurazione:
Computer PC-ASUS (Microsoft Windows NT 10.0.19042.0)
Applicazione host: powershell -c Start-Transcript tee.txt -Force; Invoke-Expression $input; Stop-Transcript
ID processo: 8476
PSVersion: 5.1.19041.906
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.19041.906
BuildVersion: 10.0.19041.906
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
Trascrizione avviata. File di output: tee.txt
Il file system è di tipo NTFS.
L'etichetta del volume è Windows.

Fase 1: analisi della struttura del file system di base in corso...
  536592 record file elaborati.
Verifica file completata.
Durata fase (Verifica record di file): 58.78 secondi.
  39496 record di file di grandi dimensioni elaborati.
Durata fase (Recupero record di file orfani): 0.00 millisecondi.
  0 record file non validi elaborati.
Durata fase (Controllo record di file non validi): 0.46 millisecondi.

Fase 2: analisi del collegamento dei nomi file in corso...
  72663 record reparse elaborati.
  730874 voci di indice elaborate.
Verifica indici completata.
Durata fase (Verifica dell'indice): 47.53 secondi.
  0 file non indicizzati analizzati.
Durata fase (Riconnessione orfano): 5.58 secondi.
  0 file non indicizzati ripristinati nella cartella dei file persi e ritrovati.
Durata fase (Ripristino orfano nella cartella dei file persi e ritrovati): 6.15 millisecondi.
  72663 record reparse elaborati.
Durata fase (Verifica reparse point e ID oggetto): 372.90 millisecondi.

Fase 3: analisi dei descrittori di sicurezza in corso...
Verifica descrittori di sicurezza completata.
Durata fase (Verifica descrittori di sicurezza): 74.18 millisecondi.
  97142 file di dati elaborati.
Durata fase (Verifica attributi dati): 0.43 millisecondi.
CHKDSK sta verificando il journal USN...
  34812696 byte USN elaborati.
Verifica del journal USN completata.
Durata fase (Verifica journal USN): 352.43 millisecondi.

Analisi del file system effettuata. Nessun problema rilevato.
Non sono necessarie ulteriori azioni.

  42019839 KB di spazio totale su disco.
  27079516 KB in 285283 file.
    189088 KB in 97143 indici.
         0 KB in settori danneggiati.
    667811 KB in uso dal sistema.
     65536 KB occupati dal file registro.
  14083424 KB disponibili su disco.

      4096 byte in ogni unità di allocazione.
  10504959 unità totali di allocazione su disco.
   3520856 unità di allocazione disponibili su disco.
Durata totale: 1.87 minuti (112741 ms).
**********************
Fine trascrizione Windows PowerShell
Ora di fine: 20210425161414
**********************

C:\WINDOWS\system32>
Einstein1969
  • 317
  • 1
  • 13

2 Answers2

2

These tools all just dump everything to stdout, so the best option is capture everything, then filter out what you don't need. Here's an example using simple regex and a string method. Updated to include all three commands:

# Put all this in a .ps1 file - c:\temp\CmdAndLog.ps1
#Requires -RunAsAdministrator

$commands = (
    'chkdsk /scan',
    'dism /online /cleanup-image /scanhealth',
    'sfc /scannow'
)

Set-Location $env:TEMP

# Iterate through command list
Foreach ($command in $commands) {

    # record all output, overwrite existing file
    Start-Transcript tee.txt -Force

    # Run command string
    Invoke-Expression $command *>&1
    Stop-Transcript

    $tee = Get-Content tee.txt

    $result = $tee | 
        Where {
            $_ -notmatch 'Progress'  -and        # Exclude lines with 'Progress'
            $_ -notmatch 'processed' -and        # Exclude lines with 'processed'
            # !                                  # Add more filters here if needed
            ![string]::IsNullOrEmpty($_.trim())  # Exclude empty and whitespace lines
        }

    $result | Out-File result.log -Append
}

The final amount and complexity of the filters is up to you.

If you need to start it from a batch file for some reason, you can use this to call it:

powershell -f c:\temp\CmdAndLog.ps1
Cpt.Whale
  • 4,784
  • 1
  • 10
  • 16
  • I tried running the command `chkdsk /scan *>&1 | Tee-Object -Variable Tee` in powershell, but the output on the screen is not what you want, the lines displayed by the progress are displayed one after the other. Maybe I didn't understand how to do it? maybe I explained wrong in my question? – Einstein1969 Apr 20 '21 at 19:22
  • @Einstein1969 no, I see what you mean now - that's strange behavior but there's another way. Use `Start-Transcript c:\temp\tee.txt` before your cmd, and `Stop-Transcript` after. Then do the same trimming as in the example where `$tee = Get-Content c:\temp\tee.txt` – Cpt.Whale Apr 20 '21 at 21:43
  • i am not familiar with powershell, can you modify your answer and describe well how should i do? – Einstein1969 Apr 21 '21 at 06:56
  • @Einstein1969 I've updated my answer to use `Start-Transcript` instead. – Cpt.Whale Apr 21 '21 at 14:34
  • can you help me do the merge in my code? Add you part where there is `rem Execute command.` – Einstein1969 Apr 21 '21 at 15:55
  • @Einstein1969 I threw it all into a single powershell script instead of Batch. It's a pain to escape powershell commands correctly for cmd – Cpt.Whale Apr 21 '21 at 16:50
  • ok! work! Great! I have tried this: echo chkdsk /scan | powershell -c "Start-Transcript tee.txt -Force; Invoke-Expression $input; Stop-Transcript" the output on screen is perfect. The output on file is not good. There are some wrong character. It is possible correct this? – Einstein1969 Apr 21 '21 at 23:17
  • Probably the encoding. Use `-utf8` – Abraham Zinala Apr 22 '21 at 02:28
  • @Einstein1969 Unfortunately `Start-Transcript` doesn't allow for changing the encoding - the default will be `UTF8-BOM` in powershell v5.1 and lower (doesn't display well everywhere), and `UTF8` in powershell v7+ (better). – Cpt.Whale Apr 22 '21 at 14:37
  • If you have an example command that does this, add it and the bad output you see to your question, and I can try it out. Also, do you have any language packs or keyboard layouts installed? – Cpt.Whale Apr 22 '21 at 14:41
  • @Cpt.Whale Sorry for delay. See the question update. I have only italian and english pack. The default for my system. I don't have added nor keyboard layout or language pack. With a ps1 file I have problem on execute. I tried `echo chkdsk /scan | powershell -c "Start-Transcript tee.txt -Force; Invoke-Expression $input; Stop-Transcript"` – Einstein1969 Apr 25 '21 at 16:09
  • @Einstein1969 It's probably an encoding issue. Try opening the file in notepad and see if it displays properly. *If it does*, check the encoding at the bottom right (probably UTF8 or UTF8-BOM). *If not* try setting the output encoding in powershell before running the other commands: `$OutputEncoding = [System.Text.Encoding]::UTF8`. Powershell's default ascii encoding for the terminal does not handle italian characters very well. – Cpt.Whale Apr 26 '21 at 13:37
0

Sorry but i am not familiar with stackoverflow, so i can't make it that understandable, but i hope that this is enough.

I may have misunderstood you, but what I did understand is:

  • You want to capture the result and send it to text files while still maintaining the original output on the screen.
  • You wanted a type of program with fast execution, even if it doesn't seem to be the case since you are using executables from Windows itself.
  • The progress bars keep crashing or, in general, bugging and this interferes with the files you want to write and makes the output on the screen look ugly.

You can create an invisible program that is writing the outputs in a separate file and another that is reading those outputs, as in:

Invisible: code1.bat

@echo off
chkdsk /scan >actual

Visible: code2.bat

@echo off
:loop
set /p actual=<actual
echo %actual%>>log.txt
echo %actual%
timeout /t 1 >nul
goto loop

Certainly these codes can be improved, but you get the idea.
You can make these codes invisible using the following VBS script:

Set oShell = CreateObject ("Wscript.Shell")
Dim strArgs
strArgs = "cmd /c X:\YOURSCRIPTPATH\YOURSCRIPTNAME.bat/cmd"
oShell.Run strArgs, 0, false

It could also show a command so that you can run everything with administrative permissions, since that is what is needed for commands like chkdsk, but there you go, just ask.

As the progress bars get buggy, it could be a problem with your code page, try to search for the CHCP that's right for you. Perhaps @chcp 1252 is what is needed. Try adding "@ chcp 1252 >nul" to the beginning of your code or increasing the size of the console using "mode con lines=xxx cols=xxx"

Finally, about the speed of the batch: Batch script is a utility for the Windows shell. The shell itself is a program to facilitate navigation and the work of people who work with computer concerts with commands like chkdsk itself, so it is not optimized for everyday use, the execution is extremely slow. Make a test, put a loop that only prints 1000 "A" s on the screen in Python and another in Batch. Batch will take 5 ~ 20 seconds, Python will take probably less than milliseconds.

Hope this helps,
K.

  • thanks for your advice. however I have already tried that route and I have difficulty with the output. If you try it yourself you see. `chkdsk /scan > actual | < actual ( for /l %L in (1,1,15) do @ping -n 2 127.0.0.1 >nul & set /p line= & if defined ^ line call echo %line% )` – Einstein1969 Apr 22 '21 at 08:04
  • You shouldn't have used a pipe "|" for that, but I didn't understand your comment anyway ... I believe that PING was a good choice for a shorter response time, but the pipe does not make sense, the set /p line should be set /p line= –  Apr 22 '21 at 08:48
  • It was a pseudocode to help you figure out. –  Apr 22 '21 at 21:07
  • sorry, maybe we are not understanding each other. In the previous comment you told me that the command to use is set /p line= – Einstein1969 Apr 23 '21 at 08:05
  • I can't use the "chkdsk /scan" command on my Windows to do something more feasible for you because I use a customized version of Windows for privacy and I haven't touched chkdsk yet because it is something slightly complex so might be it, but what I wanted to do was give an example of code that would work for the case. Try it yourself, type any command like: `echo %allusersprofile%>actual.txt` and `set /p actual= –  Apr 23 '21 at 10:55
  • Of course, with separate windows, as I said. One processing the command and the other reading and showing the outputs. –  Apr 23 '21 at 10:56