Page 1 of 1

Here is a Working Progress Bar

Posted: 07 May 2019 04:14
by Gustaaf
Hi there,

I thought I would share my DOS progress bar I have been quietly working on over the years. It processes text files containing PC names. The idea would be to process commands etc on computers etc as needed.
The script is written in a DEMO fashion where it creates its OWN PC lists etc, and processes those. You would need to strip out the parts you need to process your own PC name list etc.
This progress bar function is part of my larger collection of scripts I use to do remote remediation on computers.

NOTE: This script/code relies strongly on NTFS formatted volumes. FAT32 support is not possible. The script relies a lot on NTFS-streams.

Please give credit where credit is due when using the code, that is all.

Code: Select all

@ECHO Off
REM NOTE: This script relies on NTFS formatted file systems. Will not work on FAT32 file system.
REM Written by: G.A. von Pickartz


>NUL CHCP 65001
:: Prompt $ to suppress CMD path strings. Turn @ECHO ON to get debug like output.
:: To record your debug output, simply invoke the script from the console and redirect to a log.
:: example: progress_v2.cmd >>debug.txt
:: that is, if you ENABLE @ECHO ON and leave PROMPT $ in place.
prompt $

SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION
SETLOCAL

:: Progress on activity
 SET PRG0=[░░░░░░░░░░]
 SET PRG1=[▓░░░░░░░░░]
 SET PRG2=[▓▓░░░░░░░░]
 SET PRG3=[▓▓▓░░░░░░░]
 SET PRG4=[▓▓▓▓░░░░░░]
 SET PRG5=[▓▓▓▓▓░░░░░]
 SET PRG6=[▓▓▓▓▓▓░░░░]
 SET PRG7=[▓▓▓▓▓▓▓░░░]
 SET PRG8=[▓▓▓▓▓▓▓▓░░]
 SET PRG9=[▓▓▓▓▓▓▓▓▓░]
SET PRG10=[▓▓▓▓▓▓▓▓▓▓]
:: Variable %SPACES% does need 79x SPACE characters as a variable. Don't remove the spaces.
SET SPACES=                                                                            
:: Create a variable that contains back-spaces. This is used to re-write the progress bar text without issuing a return.
FOR /F "usebackq" %%a IN (`copy /Z "%~dpf0" nul`) DO ( SET "bs=%%a")


ECHO.
del /q trace.log 2>nul
ECHO Creating SAMPLE PC names...

FOR %%C IN (1 3 5 7 10 20 50 100) DO ( 
    FOR /L %%I IN (0,1,%%C) DO (
        IF %%I EQU 0 TYPE NUL>%%C.txt
        IF %%I NEQ 0 ECHO Computer_%%I>>%%C.txt
    )
    REM Create some duplicates..
    FOR /L %%I IN (0,1,%%C) DO (
        IF %%I EQU 0 ECHO ;Computer_%%I>>%%C.txt
        IF %%I NEQ 0 ECHO Computer_%%I>>%%C.txt
    ) 
)

FOR %%L IN (1.txt 3.txt 5.txt 7.txt 10.txt 20.txt 50.txt 100.txt) DO (
    SET IND=
    >nul timeout /t 3
    CALL :PROGRESS %%L
)

ECHO.
ECHO Ended
REM The trace/debug log will reveal if the loop uniquely called the computer names.
REM Trace.log output must be as uniques as the source file lists 1.txt 3.txt etc.
notepad trace.log
del /q trace.log 2>nul
pause

:PROGRESS %1
ECHO.
SET lst=%1
SET lstname=%~nx1%
:: Temporarily change the code page back to en-US ascii to correctly read the contents of the %list% file.
>NUL CHCP 437
ECHO ** JOB: Processing list [!lstname!]

REM Reset the temp files.
DEL /Q totals.tmp tlist.tmp DEDUPLICATE.TMP 2>nul

>NUL ECHO LIST --- %lst% >>trace.log

<NUL ( CALL :EchoBs ** JOB: Filtering excluded devices.... )
>NUL TIMEOUT /T 1
REM Skip lines with ";" as commented out or excluded.
FOR /F "EOL=;" %%C IN (%lst%) DO ( ECHO %%C>>TLIST.TMP )

<NUL ( CALL :EchoBs ** JOB: De-duplicating devices.... )
>NUL TIMEOUT /T 1
TYPE NUL>"DEDUPLICATE.TMP"
:: This technique relies on NTFS file system! We are using NTFS STREAMS!!
:: The result is ultra fast de-duplication, as we are simply overwriting the same STREAM.
:: NTFS stream is like meta data to an existing file.
( FOR /F "USEBACKQ" %%T IN ("TLIST.TMP") DO ECHO %%T>"DEDUPLICATE.TMP":%%T ) >NUL
:: Now FARM the NTFS stream with the DIR /R command.
( FOR /F "USEBACKQ TOKENS=2 DELIMS=:" %%I IN (`DIR /R "DEDUPLICATE.TMP" ^| FIND /I "TMP:"`) DO ( ECHO %%I>>"DEDUPLICATE.TMP") ) >NUL

<NUL ( CALL :EchoBs ** JOB: Getting device totals.... )
>NUL TIMEOUT /T 1
TYPE NUL>TOTALS.TMP
REM Write a formatted totals.tmp that contains line numbers and devices.
FINDSTR /R /N "^" "DEDUPLICATE.TMP">TOTALS.TMP
REM Grand total of things, simply add via FOR.
SET totals=0
FOR /F "USEBACKQ" %%T IN ("totals.tmp") DO SET /A totals+=1


SET STEP=0
FOR /L %%I IN (%TOTALS%,-10,1) DO ( SET /A STEP +=1 )

ECHO ** JOB: Total device(s) count: %totals%
ECHO ** JOB: Progress shift @ %STEP% steps.
ECHO.
<NUL ( CALL :EchoBs )
IF %TOTALS% LEQ 10 (
    SET /A IND=10/%TOTALS%
)


:: use code page 65001 for DOS elegant progress bar.
>NUL CHCP 65001

FOR /L %%P IN (0,1,10) DO (
    SET /A S=%%P*%STEP%
    SET /A E=!S!+%STEP%
    
    REM When %total% is less than 10 items, attempt to correct the indicator.
    IF DEFINED IND (
        SET /A JMP=%IND%*%%P
        IF !S! GEQ %TOTALS% SET JMP=10
        FOR %%I IN (PRG0 PRG1 PRG2 PRG3 PRG4 PRG4 PRG6 PRG7 PRG8 PRG9 PRG10) DO (
            IF "%%I" EQU "PRG!JMP!" CALL SET INDICATOR=!%%I!
        )
    ) ELSE (
        CALL SET INDICATOR=!PRG%%P!
    )
    
    REM Progress bar moves at each %%P loop, thus %%T is the new control START/STOP for our computer names loop.
    REM Loop %%T will load "totals.tmp", then skip ahead to the matching index in the file, thus resuming the count.
    REM When the STOP !E! is reached, it returns back to the first %%P loop to shift the indicator and start again.
    FOR /L %%T IN (!S!,1,!E!) DO ( 
        
        IF !E! NEQ %%T (
            FOR /F "usebackq tokens=1-2 delims=:" %%l IN ("totals.tmp") DO (
            IF %%l EQU %%T (
                <NUL ( CALL :EchoBs [S=!S!;E=!E!] [%%T/%TOTALS%] PROGRESS: !INDICATOR! %%m !cr!)
                
                REM Insert your function call here to do some actual work.
                CALL :MAIN %%m
                REM ----------

                )
            )
        )
    )

)
ECHO.
>NUL ECHO --- END OF LIST --- %lst% >>trace.log
GOTO :EOF

:: This function adds "spaces to a string", then trims it out at length 78.
:: It then appends the special character <BackSpace> to the end of the string.
:: This helps with creating special text messages that can be over written by 
:: a new string, suppressing <LF> or <CR> in the string. 
:: The progress bar cannot work without this.
:EchoBs %*
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
SET STRING=%*%SPACES%
SET SPACED=%STRING:~0,78%
ENDLOCAL & SET /P X=%SPACED%!BS!
GOTO :EOF

:MAIN %1
REM Be sure NOT to use ECHO etc that will break the progress bar.
REM Everything needs to go to NUL or its own LOG!
>NUL timeout /t 2
>NUL ECHO %1>>trace.log
GOTO :EOF