2

I only want to find specific lines in his text file, so i figure that using range would be a good idea. But i can seem to find any tutorial online. please help..

An example of the text file

XXX scan report for 192.0.0.0
exampleexampleexampleexampleexample
OS: windows 8
exampleexampleexampleexample
exampleexampleexampleexample
PORT     STATE  SERVICE          VERSION
21/tcp   close  ftp
80/tcp   open   http             Microsoft ISS
exampleexampleexampleexample
exampleexampleexampleexample

XXX scan report for 192.0.0.1
exampleexampleexampleexampleexample
exampleexampleexampleexample
exampleexampleexampleexample
PORT     STATE  SERVICE          VERSION
21/tcp   close  ftp
80/tcp   open   http             Microsoft ISS
exampleexampleexampleexample
exampleexampleexampleexample

I wanted to get IP address, OS Details and Port status into a spreadsheet.

My code:

@echo off
set file=C:\Users\1.txt
set match=report for
set match1=OS


findstr /c:"%match%" %file%
findstr /c:"%match1%" %file%
findstr /c:"tcp " /c:"udp " %file%

for /f "tokens=1-5" %%a in ('findstr /c:"%match%" %file%') do (
echo "IP Address:","%%e" >> report1.csv

for /f "tokens=1,2 delims=:*" %%a in ('findstr /c:"%match1%" %file%') do 
( 
echo "Operating System: ","%%b" >> report1.csv
echo "PORT","STATE","SERVICE","VERSION" >> report1.csv  

for /f "tokens=1-4 delims=: " %%a in ('findstr /c:"tcp " /c:"udp " 
%file%') do (
echo "%%a","%%b","%%c","%%d" >> report1.csv
)

)

)

There is a big problem with this code and it is in the for loop. The code will get the first ip then will proceed to get the os details, but not ever ip have the os details, so the os details will be placed in the wrong ip.

Another problem with the code is that it will list all os and port details under one ip address. And the next ip address will also be the same, it will have all the os and port details as well.

Please do help me to solve this problem. Or is there any other method like call?

aschipfl
  • 33,626
  • 12
  • 54
  • 99
Ivan Sim
  • 305
  • 4
  • 15

2 Answers2

2
@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q43335765.txt"
SET "outfile=%destdir%\outfile.txt"
>"%outfile%" ECHO IP,OS,PORT,STATUS,SERVICE,VERSION
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO (
 CALL :process %%a
)

GOTO :EOF

:process
ECHO %*|FIND "scan report for " >NUL
IF NOT ERRORLEVEL 1 GOTO newip
IF "%~1"=="OS:" SET "$os=%*"&GOTO :eof
ECHO %~1|FIND "/">NUL
IF ERRORLEVEL 1 GOTO :EOF 
FOR /f "tokens=1,2,3*" %%p IN (
 "%*") DO >>"%outfile%" ECHO %$ip%,%$os:*: =%,%%p,%%q,%%r,%%s
GOTO :eof

:newip
IF "%~2" neq "" shift&GOTO newip
SET "$ip=%~1"
SET "$os=:  "

GOTO :eof

You would need to change the settings of sourcedir and destdir to suit your circumstances.

I used a file named q43335765.txt containing your data for my testing.

Produces the file defined as %outfile%

Having established the filenames, put the header line in the output file and process each line of the file through :process

In :process, detect the key string indicating a ne data item. If found, go to :newip which simply shuffles the data line along until only the last entry remains and assign this last entry to $ip. Set $ip to :Space + any special string you want to represent "not found" (like unknown for instance)

If the line doesn't contain the keystring, see whether the first token is OS:, and set $os to the entire original line if it is.

Otherwise, lookk for a / in the first token. If it's not there, abandon processing this line, otherwise simply tokenise the line, selecting the first to thid and rest and output using the saved ip, the saved os, except for the part before the first :Space and the four data line entries, all separated by commas.


Revision to cater for | in data - replace with /

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q43335765.txt"
SET "outfile=%destdir%\outfile.txt"
>"%outfile%" ECHO IP,OS,PORT,STATUS,SERVICE,VERSION
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO (
 SET "line=%%a"
 CALL :preprocess
)

GOTO :EOF

:preprocess
SET "line=%Line:|=/%"
CALL :process %line%
GOTO :eof

:process
ECHO %*|FIND "scan report for " >NUL
IF NOT ERRORLEVEL 1 GOTO newip
IF "%~1"=="OS:" SET "$os=%*"&GOTO :eof
ECHO %~1|FIND "/">NUL
IF ERRORLEVEL 1 GOTO :EOF 
FOR /f "tokens=1,2,3*" %%p IN (
 "%*") DO >>"%outfile%" ECHO %$ip%,%$os:*: =%,%%p,%%q,%%r,%%s
GOTO :eof

:newip
IF "%~2" neq "" shift&GOTO newip
SET "$ip=%~1"
SET "$os=:  "

GOTO :eof

Shows the need to provide a representative data sample...

With characters that have special meaning like |, assign to a variable and call a preprocessor to convert all | to / (or whatever else is desired) and then call the process with the result.

Formula: set "var=%somevar:string1=string2%"

will assign to var the value of somevar with all occurrences of string1 replaced by string2. The enclosing quotes in a set command ensure that any stray trailing spaces on the line are not included in the value assigned.

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • What does all these means? (ECHO %*|), (IF ERRORLEVEL 1), (IF "%~1"=="OS:" SET "$os=%*"&GOTO :eof), (Why find /), (IF "%~2" neq "" shift&GOTO newip) – Ivan Sim Apr 11 '17 at 04:25
  • 1
    When a batchfile is executed, or a subroutine invoked by a `call`, the routine can accept parameters (in this case, a line of text from the file). Within the routine, you can access those parameters as `%1` to `%9`. Executing the `shift` instruction drops the first parameter from the list and shuffles the rest along. `%*` means "all of the parameters" (in this case, all of the text line). Each parameter is separated by - separators - like comma, semicolon and space. Equals, too. – Magoo Apr 11 '17 at 07:37
  • 1
    i have notice that (IF "%~1"=="OS:" SET "$os=%*"&GOTO :eof) skips this line "OS: Microsoft Windows 7|2008" anyway on how to also read this line – Ivan Sim Apr 11 '17 at 09:39
1

The flaw in your logic is that each time you execute findstr, it starts back at line 1 of your text file. If you're working with multi-line records, you have to build your line of output with in one pass of the record. I suggest a for /F loop and testing tokens is better suited to this than findstr. Here's a suggestion:

@echo off
setlocal

set "file="C:\Users\1.txt"

>"report1.csv" (
    echo "IP Address","Operating System","port 21","port 80"

    for /F "usebackq tokens=1-3,5" %%I in ("%file%") do (

        rem // check if line begins a record
        if /i "%%~J"=="scan" if /i "%%~K"=="report" (
            set "IP=%%~L"
            set "OS="
        )

        rem // check if line contains OS
        if /i "%%~I"=="OS:" set OS="%%~J %%~K"

        rem // check if line contains port 21
        if /i "%%~I"=="21/tcp" set "state21=%%~J"

        rem // port 80 indicates end of needed info in record
        setlocal enabledelayedexpansion
        if /i "%%~I"=="80/tcp" echo(!IP!,!OS!,!state21!,%%~J
        endlocal
    )
)
rojo
  • 24,000
  • 5
  • 55
  • 101
  • I dont understand. The tokens=1-3,5 and it is only for the first line right? How can you also check other line?, (if /i "%%~I"=="OS:" set OS="%%~J %%~K") how does it works that allow you to check other line – Ivan Sim Apr 11 '17 at 04:39
  • 1
    @IvanSim `for /f` loops through the entire text file line-by-line. See `for /?` in a cmd console for full details. It works. – rojo Apr 11 '17 at 11:39