How to remove new lines in batch file?

1.3k views Asked by At

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
3

There are 3 answers

0
Mofi On BEST ANSWER

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 /?
0
Alejandro Bermúdez On

can you try this: create a sysi.vbs file with the following code and run this way: cscript //nologo sysi.vbs

adjust as you needs.

sysi.vbs: '---------------------------------------------

Set dtmConvertedDate = CreateObject("WbemScripting.SWbemDateTime")

    strComputer = "."
    Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

    Set colOperatingSystems = objWMIService.ExecQuery ("Select * from Win32_OperatingSystem")

    ' Create a new WshNetwork object to access network properties.
    Wscript.Echo "*** from WScript.Network ***************"

    Set WshNetwork = WScript.CreateObject("WScript.Network")
    Wscript.Echo "Computer name : " & WshNetwork.ComputerName 
    Wscript.Echo "Domain : " & WshNetwork.UserDomain 
    Wscript.Echo "User name : " & WshNetwork.UserName 

    Wscript.Echo "*** from Win32_OperatingSystem  **************"
    For Each objOperatingSystem in colOperatingSystems
        Wscript.Echo "OS Caption: " & objOperatingSystem.Caption
        Wscript.Echo "OS Version: " & objOperatingSystem.Version

        dtmConvertedDate.Value = objOperatingSystem.InstallDate
        dtmInstallDate = dtmConvertedDate.GetVarDate

        Wscript.Echo "OS Install Date: " & dtmInstallDate
        Wscript.Echo "OS Serial Number: " & objOperatingSystem.SerialNumber

    Next

    Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)

    Wscript.Echo "*** from Win32_ComputerSystem **********"

    For Each objItem in colItems
        Wscript.Echo "Manufacturer: " & objItem.Manufacturer
        Wscript.Echo "Model: " & objItem.Model
        Wscript.Echo "SystemType: " & objItem.SystemType
        Wscript.Echo "TotalPhysicalMemory: " & objItem.TotalPhysicalMemory
    Next

    Wscript.Echo "*** from Win32_Processor **********"
    Set colItems = objWMIService.ExecQuery("Select * from Win32_Processor",,48)
    For Each objItem in colItems
        Wscript.Echo "Proc Name: " & objItem.Name
        Wscript.Echo "CurrentClockSpeed: " & objItem.CurrentClockSpeed
        Wscript.Echo "ErrorDescription: " & objItem.ErrorDescription
        Wscript.Echo "DeviceID: " & objItem.DeviceID
        Wscript.Echo "Manufacturer: " & objItem.Manufacturer
        Wscript.Echo "MaxClockSpeed: " & objItem.MaxClockSpeed

    Next



    Wscript.Echo "*** from Win32_BIOS ******* "
    Set colBIOS = objWMIService.ExecQuery("Select * from Win32_BIOS")

    Set dtmRelDateRaw = CreateObject("WbemScripting.SWbemDateTime")

    For each objBIOS in colBIOS
         Wscript.Echo "BIOS Name: " & objBIOS.Name
         Wscript.Echo "BIOS Manufacturer: " & objBIOS.Manufacturer
         Wscript.Echo "Primary BIOS: " & objBIOS.PrimaryBIOS

         dtmRelDateRaw.Value = objBIOS.ReleaseDate
         dtmRelDate = dtmRelDateRaw.GetVarDate
         Wscript.Echo "Release Date: " & objBIOS.ReleaseDate
         Wscript.Echo "Release Date: " & dtmRelDate
         Wscript.Echo "Serial Number: " & objBIOS.SerialNumber
         Wscript.Echo "Status: " & objBIOS.Status
         Wscript.Echo "Version: " & objBIOS.Version


    Next
0
Io-oI On

Just an alternative way without using DisableDelayedExpansion:

@echo off && setlocal EnableDelayedExpansion

set "_usrd=Domain\User Name:          !USERDOMAIN!\!USERNAME!" && set "_bios=Bios Serial Number:       -x" && set "_CPUs=CPU Name:                 -y"
set "_wmic=%SystemRoot%\System32\wbem\wmic.exe" && pushd "%SystemRoot%\System32" && >"%temp%\%ComputerName%.txt" 2>nul (
systeminfo.exe | findstr "Host.Name OS.Name OS.Version Original.Install.Date System.Manufacturer System.Model System.Type Total.Physical.Memory"
for /f skip^=1^tokens^=* %%i in ('!_wmic! bios get serialnumber^|findstr "[0-9] [aZ]"')do ^< nul call set /p "'=!_bios:-x= %%~i!" <nul & echo\
for /f skip^=1^tokens^=* %%j in ('!_wmic! cpu get name^|findstr "[0-9] [aZ]"')do ^< nul call set /p "'=!_CPUs:-y= %%~j!" <nul & echo\
echo\!_usrd! ) && type "%temp%\%ComputerName%.txt" && popd && endlocal && goto :EOF 
  • Outputs:
Host Name:                 LAME_SLUG
OS Name:                   Microsoft Windows 10 Pro
OS Version:                10.0.18363 N/A Build 18363
Original Install Date:     3/27/2020, 11:17:06 PM
System Manufacturer:       LENOVO
System Model:              80YH
System Type:               x64-based PC
BIOS Version:              LENOVO 4WCN46WW, 12/30/2019
Total Physical Memory:     16,259 MB
Bios Serial Number:        PE03A187
CPU Name:                  Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz
Domain\User Name:          LAME_SLUG\ecker