Search code examples
batch-filetext-filesline-breakswmicsystem-information

How to remove new lines in batch file?


I'm working on batch file and export to text file. Seem all of them is ok, but when i open text file, many new lines break. So, i want to remove of them.

@echo OFF
setlocal EnableDelayedExpansion
(
  systeminfo |findstr /c:"Host Name" /c:"OS Name" /c:"OS Version" /c:"Original Install Date" /c:"System Manufacturer" /c:"System Model" /c:"System Type" /c:"Total Physical Memory"
    wmic bios get serialnumber /Format:list | more | findstr .
    wmic cpu get name /Format:list | more | findstr .
  echo=%userdomain%\%username%
)> %ComputerName%.txt

The result text file is ok, but still many new lines break, i want to remove of them

Host Name:                 PGV-PF165HNN
OS Name:                   Microsoft Windows 10 Pro
OS Version:                10.0.18363 N/A Build 18363
Original Install Date:     7/22/2019, 6:28:01 PM
System Manufacturer:       LENOVO
System Model:              20JM0009US
System Type:               x64-based PC
BIOS Version:              LENOVO N1QET87W (1.62 ), 2/27/2020
Total Physical Memory:     8,072 MB
SerialNumber=PF165HNN

Name=Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz

WINDOM1\brian.lee

Solution

  • The OS language dependent output of %SystemRoot%\System32\systeminfo.exe is character encoded in ASCII/ANSI/OEM which means one byte per character using the code page as displayed on running in a command prompt window chcp. The code page depends on the country (region) configured for the account used to run the batch file. The code page does not really matter as long as the data of interest do not contain characters with a code value greater 127 (non-ASCII character).

    The output of systeminfo filtered by findstr is in binary with hexadecimal offset in file left to colon, hexadecimal values of the bytes, and their ASCII representation after the semicolon:

    0000h: 48 6F 73 74 20 4E 61 6D 65 3A 20 20 20 20 20 20 ; Host Name:      
    0010h: 20 20 20 20 20 20 20 20 20 20 20 50 47 56 2D 50 ;            PGV-P
    0020h: 46 31 36 35 48 4E 4E 0D 0A 4F 53 20 4E 61 6D 65 ; F165HNN..OS Name
    0030h: 3A 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; :               
    0040h: 20 20 20 20 4D 69 63 72 6F 73 6F 66 74 20 57 69 ;     Microsoft Wi
    0050h: 6E 64 6F 77 73 20 31 30 20 50 72 6F 0D 0A 4F 53 ; ndows 10 Pro..OS
    0060h: 20 56 65 72 73 69 6F 6E 3A 20 20 20 20 20 20 20 ;  Version:       
    0070h: 20 20 20 20 20 20 20 20 20 31 30 2E 30 2E 31 38 ;          10.0.18
    0080h: 33 36 33 20 4E 2F 41 20 42 75 69 6C 64 20 31 38 ; 363 N/A Build 18
    0090h: 33 36 33 0D 0A 4F 72 69 67 69 6E 61 6C 20 49 6E ; 363..Original In
    00a0h: 73 74 61 6C 6C 20 44 61 74 65 3A 20 20 20 20 20 ; stall Date:     
    00b0h: 37 2F 32 32 2F 32 30 31 39 2C 20 36 3A 32 38 3A ; 7/22/2019, 6:28:
    00c0h: 30 31 20 50 4D 0D 0A 53 79 73 74 65 6D 20 4D 61 ; 01 PM..System Ma
    00d0h: 6E 75 66 61 63 74 75 72 65 72 3A 20 20 20 20 20 ; nufacturer:     
    00e0h: 20 20 4C 45 4E 4F 56 4F 0D 0A 53 79 73 74 65 6D ;   LENOVO..System
    00f0h: 20 4D 6F 64 65 6C 3A 20 20 20 20 20 20 20 20 20 ;  Model:         
    0100h: 20 20 20 20 20 32 30 4A 4D 30 30 30 39 55 53 0D ;      20JM0009US.
    0110h: 0A 53 79 73 74 65 6D 20 54 79 70 65 3A 20 20 20 ; .System Type:   
    0120h: 20 20 20 20 20 20 20 20 20 20 20 20 78 36 34 2D ;             x64-
    0130h: 62 61 73 65 64 20 50 43 0D 0A 42 49 4F 53 20 56 ; based PC..BIOS V
    0140h: 65 72 73 69 6F 6E 3A 20 20 20 20 20 20 20 20 20 ; ersion:         
    0150h: 20 20 20 20 20 4C 45 4E 4F 56 4F 20 4E 31 51 45 ;      LENOVO N1QE
    0160h: 54 38 37 57 20 28 31 2E 36 32 20 29 2C 20 32 2F ; T87W (1.62 ), 2/
    0170h: 32 37 2F 32 30 32 30 0D 0A 54 6F 74 61 6C 20 50 ; 27/2020..Total P
    0180h: 68 79 73 69 63 61 6C 20 4D 65 6D 6F 72 79 3A 20 ; hysical Memory: 
    0190h: 20 20 20 20 38 2C 30 37 32 20 4D 42 0D 0A       ;     8,072 MB..
    

    The output of %SystemRoot%\System32\wbem\wmic.exe is always Unicode encoded using UTF-16 Little Endian encoding with byte order mark (BOM). So the output by the two used wmic command lines is with two bytes per character.

    The command line wmic bios get serialnumber /Format:list produces in binary the output:

    0000h: FF FE 0D 00 0A 00 0D 00 0A 00 53 00 65 00 72 00 ; ÿþ........S.e.r.
    0010h: 69 00 61 00 6C 00 4E 00 75 00 6D 00 62 00 65 00 ; i.a.l.N.u.m.b.e.
    0020h: 72 00 3D 00 50 00 46 00 31 00 36 00 35 00 48 00 ; r.=.P.F.1.6.5.H.
    0030h: 4E 00 4E 00 0D 00 0A 00 0D 00 0A 00 0D 00 0A 00 ; N.N.............
    

    The first two bytes FF FE is the byte order mark for UTF-16 Little Endian. Each ASCII character is encoded with two bytes (16 bits) with high byte having value 0. The newline characters are carriage return (0D 00) and line-feed (0A 00). There are two empty lines output first, then the line with the data of interest, and finally once again two empty lines.

    The command line wmic cpu get name produces in binary the output:

    0000h: FF FE 0D 00 0A 00 0D 00 0A 00 4E 00 61 00 6D 00 ; ÿþ........N.a.m.
    0010h: 65 00 3D 00 49 00 6E 00 74 00 65 00 6C 00 28 00 ; e.=.I.n.t.e.l.(.
    0020h: 52 00 29 00 20 00 43 00 6F 00 72 00 65 00 28 00 ; R.). .C.o.r.e.(.
    0030h: 54 00 4D 00 29 00 20 00 69 00 35 00 2D 00 36 00 ; T.M.). .i.5.-.6.
    0040h: 33 00 30 00 30 00 55 00 20 00 43 00 50 00 55 00 ; 3.0.0.U. .C.P.U.
    0050h: 20 00 40 00 20 00 32 00 2E 00 34 00 30 00 47 00 ;  .@. .2...4.0.G.
    0060h: 48 00 7A 00 0D 00 0A 00 0D 00 0A 00 0D 00 0A 00 ; H.z.............
    

    The Unicode output is redirected by cmd.exe processing the batch file to more which outputs the lines now with one byte per character. But Windows command processor has a bug on interpreting UTF-16 LE encoded lines as it can be seen on using the following command line:

    wmic bios get serialnumber /Format:list | more >output.txt
    

    The file output.txt contains the binary bytes:

    0000h: 0D 0D 0A 0D 0D 0A 53 65 72 69 61 6C 4E 75 6D 62 ; ......SerialNumb
    0010h: 65 72 3D 50 46 31 36 35 48 4E 4E 0D 0D 0A 0D 0D ; er=PF165HNN.....
    0020h: 0A 0D 0D 0A 0D 0A 0D 0A                         ; ........
    

    Each Unicode encoded carriage return + line-feed (0D 00 0A 00) becomes ASCII encoded carriage return + carriage return + line-feed (0D 0D 0A).

    That is the real problem here. The additional carriage return results on using regular expression search string . to match all lines with at least one character that also the empty lines are matched by this regular expression search string on output converted not correct from Unicode to ASCII.

    It depends on used text editor how the not valid sequence of newline characters are interpreted. Most text editors interpret the carriage return without line-feed as line termination, but findstr does not do that.

    One solution is explicitly searching for the line which contains the data of interest.

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    (
        %SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
        %SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE | %SystemRoot%\System32\findstr.exe /L /C:SerialNumber
        %SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE | %SystemRoot%\System32\findstr.exe /L /C:Name
        echo %USERDOMAIN%\%USERNAME%
    ) >"%ComputerName%.txt"
    endlocal
    

    The data written into file %ComputerName%.txt is completely encoded in ASCII with everywhere used just 0D 0A as line termination.

    Some additional information about small changes on code:

    1. The command more is omitted as not really necessary. The not correct conversion from Unicode to ASCII is done by Windows command processor cmd.exe.
    2. Delayed environment variable expansion is not enabled by this batch file as not needed at all.
    3. All executables are specified with well-known full qualified file name. So cmd.exe has not to search for the executables using the values of the environment variables PATHEXT and PATH.
    4. WMIC option /Format:list is replaced by option /VALUE which results in same output.
    5. FINDSTR is run with option /L to explicitly instruct findstr to run a literal search although that is the default on using option /C:.

    An even better batch file code would be:

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    (
        %SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
        for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE') do if not "%%J" == "" echo Serial Number:             %%J
        for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE') do if not "%%J" == "" echo CPU Name:                  %%J
        echo Domain\User Name:          %USERDOMAIN%\%USERNAME%
    ) >"%ComputerName%.txt"
    endlocal
    

    The additional data determined with WMIC and output with ECHO are written into the text file in same format as the output of systeminfo.

    Attention: The last echo command line is not safe in case of value of environment variable USERDOMAIN or of environment variable USERNAME contains ) or &. 100% safe would be:

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    (
        %SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
        for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE') do if not "%%J" == "" echo Serial Number:             %%J
        for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE') do if not "%%J" == "" echo CPU Name:                  %%J
    ) >"%ComputerName%.txt"
    setlocal EnableDelayedExpansion
    echo Domain\User Name:          !USERDOMAIN!\!USERNAME!>>"%ComputerName%.txt"
    endlocal
    endlocal
    

    To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.

    • echo /?
    • endlocal /?
    • findstr /?
    • for /?
    • if /?
    • setlocal /?
    • systeminfo /?
    • wmic /?
    • wmic bios /?
    • wmic bios get /?
    • wmic cpu /?
    • wmic cpu get /?