简体   繁体   中英

nested for loop, set variable and if else in a batch script

I am trying to make a batch script which will write specific IP addresses in a file. I have a txt file (created by one python script) having a list of IP addresses (one in each new-line), Now I need to ping each of these IPs using for loop, check if the TTL value is between 100 to 128 (windows hosts) and write the IP addresses to a new file. I've been trying to adjust into setting the variables and for loops but this all becomes too complex to run.
So far I've reached:-
EDIT: corrected below command

for /f %i in (ip.txt) do ping -n 1 %i | find "TTL"

This will give me multiple lines Ping output, showing here only for single line (I am using 4.2.2.2 just for example)

Reply from 4.2.2.2: bytes=32 time=1 ms ttl=45

If I do ping to single IP I can pick the TTL field but not TTL's exact value

for /f "tokens=6 delims= " %a in ('ping -n 1 4.2.2.2 ^| find "TTL"') do echo %a

It gives me the value TTL=45 whereas I needed 45 for the comparison. I read about setlocal enabledelayedexpansion which is useful, but I am not able to combine these all into a single line and use set variables and use IF-ELSE loops.
Plz give a little description on how to achieve the IP selection.

EDITED BY ME AFTER MAKING BATCH SCRIPT SOLUTION:-
This batch script will ping every IP address given in the ips.txt file. Find the TTL value, if TTL value is equal to 128, it'll run a command NBTSTAT -A ip-address (for finding the GROUP information) and store it in a nbt_query_op.txt file.
This file will be searched for existing results before firing the NBTSTAT command for every IP Address and if the result for a specific IP is not found in the file, NBTSTAT will be fired.
Note that variables should be referenced enclosed with ! characters, !TTL! , !ip1! , !ERRORLEVEL! . Further, thanks to Mr. RGuggisberg too for providing pointers.

@echo off
setlocal EnableDelayedExpansion
for /f %%i in (ips.txt) do (
for /f "tokens=6 delims= " %%a in ('ping -n 1 %%i ^| find "TTL"') do (
    for /f "tokens=2 delims==" %%b in ('echo.%%a') do set ttl=%%b
    echo %%i has TTL:- !ttl!
    if !TTL! == 128      (set ip1=%%i
                 echo        SELECTED IP- !ip1! TTL- !TTL!
                 findstr /c:!ip1! nbt_query_op.txt
                 if not !ERRORLEVEL! ==0 echo !ip1!>>nbt_query_op.txt && nbtstat -A !ip1! | find "GROUP">>nbt_query_op.txt
                     )
                                          )
)


Thanks,
kriss

This will do what you are asking. Modify as needed when you migrate to your first example.

for /f "tokens=6 delims= " %a in ('ping -n 1 4.2.2.2 ^| find "TTL"') do for /f "tokens=2 delims==" %b in ('echo.%a') do echo %b

BTW, the first FOR loop in your post is incomplete. I think you meant

for /f %i in (ip.txt) do ping -n 1 %i | find "TTL"

In vbscript you can do something like this :

strHost = "4.2.2.2"
if Ping(strHost) = True then
    Wscript.Echo "Host " & strHost & " contacted"
Else
    Wscript.Echo "Host " & strHost & " could not be contacted"
end if
'***************************************************************************************
Function Ping(strHost)
    dim objPing, objRetStatus
    set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}").ExecQuery _
      ("select * from Win32_PingStatus where address = '" & strHost & "'")
    for each objRetStatus in objPing
        if IsNull(objRetStatus.StatusCode) or objRetStatus.StatusCode <> 0 then
            Ping = False
            WScript.Echo "Status code is " & objRetStatus.StatusCode
        else
            Ping = True
            Msg = Msg & " Pingging " & strHost & vbCrlf & vbCrlf 
            Msg = Msg & "Bytes = " & objRetStatus.BufferSize & vbCrlf 
            Msg = Msg & "Time (ms) = " & objRetStatus.ResponseTime & vbCrlf 
            Msg = Msg & "TTL (s) = "  & objRetStatus.ResponseTimeToLive 
        end if
    next
    Wscript.echo Msg
End Function 
'***************************************************************************************

EDIT : On 30/06/2016 @ 19:11

I tested with this file : file.txt

 4.2.2.2 www.google.com www.google.fr www.facebook.com www.stackoverflow.com www.yahoo.com www.yahoo.fr www.developpez.net 

this batch file :

@echo off
Title Get TTL from IP adress
set vbsfile=%Tmp%\%~n0.vbs
set IP_File=E:\vb-ping\ip.txt
set LogFile=Log.txt
If Exist %LogFile% Del %LogFile%
For /f %%a in ('Type %IP_File%') Do ( 
    echo TTL for "%%a" is : & Call:VBS "%%a"
    ( echo TTL for "%%a" is : & Call:VBS "%%a" )>> %LogFile%
)
echo.
color 0A
echo Hit any key to open the LogFile "%LogFile%"
pause>nul
Start "" %LogFile%
Exit /b

:VBS 
(
    echo wscript.echo TTL(WScript.Arguments(0^)^)
    echo '**********************************************************************************************************
    echo Function TTL(strHost^)
    echo     dim objPing, objRetStatus
    echo     set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}"^).ExecQuery _
    echo       ("select * from Win32_PingStatus where address = '" ^& strHost ^& "'"^)
    echo     for each objRetStatus in objPing
    echo         if IsNull(objRetStatus.StatusCode^) or objRetStatus.StatusCode ^<^> 0 then
    echo            Ping = False
    echo           WScript.Echo "Status code is " ^& objRetStatus.StatusCode
    echo        else
    echo            Ping = True
    echo            TTL = objRetStatus.ResponseTimeToLive 
    echo        end if
    echo     next
    echo End Function 
    echo '**********************************************************************************************************
)> "%vbsfile%"
Cscript /Nologo "%vbsfile%" "%~1"
Exit /b

And i got as output result like that :

 TTL for "4.2.2.2" is : 53 TTL for "www.google.com" is : 51 TTL for "www.google.fr" is : 51 TTL for "www.facebook.com" is : 81 TTL for "www.stackoverflow.com" is : 53 TTL for "www.yahoo.com" is : 48 TTL for "www.yahoo.fr" is : 48 TTL for "www.developpez.net" is : 48 

So, my answer seems to turn to a somewhat different one than I was seeking. It is in python 2.x I just finished writing. Although it is not very sophisticated and stealth in terms of execution (pops up lots of CMD windows and writes to files and then reads to form the result). But still got the job done. I guess I'll have to do more research on DOS commands and start learning VB Scripting ;). lol.
Thank you @RGuggisberg and @Hackoo for the support

import os
import re
cwd = os.getcwd()
ip_file = cwd+"\\ip.txt"     ## IPs written in this file, one in each line, or the filename can be taken through command-line args (more portable)
ip = []
win_hosts = []
for line in open(ip_file).readlines():
    ip.append(line.rstrip())
del_cmd = "del "+cwd+"\\response.txt"    ## Delete response.txt file
os.system(del_cmd)                       ## as PING output keeps appending to it
for i in ip:
    cmd = "ping -n 1 "+str(i)+' | find "TTL" >> response.txt'    ## write PING response to response.txt
    os.system(cmd)
response_file = cwd+"\\response.txt"
for line in open(response_file).readlines():
    regs = r'Reply from\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*TTL=(\d{1,3})'   ## Regular Expression to catch IP and TTL-value
    obj = re.search(regs,line.rstrip('\n'))  ## also right-strip any possible new-lines, it'll probably be '\r\n' on Linux host
    if obj:
        ip = obj.group(1)
        ttl = obj.group(2)
        print ip," has TTL= ",ttl
        ttl = int(ttl)
        if (127<ttl<129):                ## change this to (54<ttl<65) to get Linux hosts
            win_hosts.append(ip)         ## Add the windows hosts to win_hosts list
print "\n[+][+] Windows Hosts = ",str(win_hosts)

My ip.txt file has:-

192.168.1.1
192.168.1.2
192.168.1.4
192.168.1.5

The result is:-

>>> 
192.168.1.1  has TTL=  30
192.168.1.2  has TTL=  64
192.168.1.4  has TTL=  64
192.168.1.5  has TTL=  128

[+][+] Windows Hosts =  ['192.168.1.5']

I don't exactly remember but couldn't get support of commands module (not supported on Windows) and subprocess module ( Though they work flawlessly on Linux box ). If someone has any idea on how to store their result to any list/dictionary/variable, plz update. I didn't like using output re-directions in CMD.

Give a try for this batch file to get the TTL value in the same line having IP address

@echo off
Title Get TTL from IP adress
set vbsfile=%Tmp%\%~n0.vbs
set IP_File=E:\vb-ping\ip.txt
set LogFile=Log.txt
If Exist %LogFile% Del %LogFile%
For /f %%a in ('Type %IP_File%') Do ( 
     Call:VBS "%%a" & echo  %%a
    ( Call:VBS "%%a" & echo  %%a)>> %LogFile%
)
echo.
color 0A
echo Hit any key to open the LogFile "%LogFile%"
pause>nul
Start "" %LogFile%
Exit /b

:VBS 
(
    echo WScript.StdOut.Write TTL(WScript.Arguments(0^)^)
    echo '**********************************************************************************************************
    echo Function TTL(strHost^)
    echo     dim objPing, objRetStatus
    echo     set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}"^).ExecQuery _
    echo       ("select * from Win32_PingStatus where address = '" ^& strHost ^& "'"^)
    echo     for each objRetStatus in objPing
    echo         if IsNull(objRetStatus.StatusCode^) or objRetStatus.StatusCode ^<^> 0 then
    echo            Ping = False
    echo           WScript.Echo "Status code is " ^& objRetStatus.StatusCode
    echo        else
    echo            Ping = True
    echo            TTL = objRetStatus.ResponseTimeToLive 
    echo        end if
    echo     next
    echo End Function 
    echo '**********************************************************************************************************
)> "%vbsfile%"
Cscript /Nologo "%vbsfile%" "%~1"
Exit /b

So, I created the full scanning script for all the Windows clients which are not a part of my Org's Domain. It's been enough long time, but I thought to post it here.

This script relies on initial client's scan with ping-sweep of nmap . Since creating script using multiprocessing module didn't work on windows box, so the best shot was nmap . NMAP does a ping-sweep of full subnet of 255 hosts within few seconds and returns the FQDN (Fully qualified domain names) of the clients found alive in the network.

NOTE: you should hve the DNS server defined in your scanner PC.

Next thing the script does is, /ites the nmap scan's output to a file nmap_op.txt . Then scripts reads the output from this file and uses regular-expression to take out IP and FQDN. If any IP isn't having FQDN, it is pinged once and output is written to a file response.txt . This file is read and IPs having TTL value between 100-129 are taken out.

add_to_db function is responsible for returning a list of IP which actually do not belong to Domain. This function crosschecks the IPs with 3 lists and removes the IP from final list which was in the database file but later was joined to Domain and also keeps adding new non-domain IPs to DB as and when they come online.

Save this python file in a directory where the script could be able to write files. You should look for two files non-domain-ips.txt (all non domain IPs) and [subnet_value]-result.txt for the final results.

Usage - run this file in command prompt as follows:-
python scanner.py 192.168.1.0/24 192.168.2.0/24
You can add any number of networks to scan. Plz do not change the pattern of network arg. You must use "/" only to define the mask value of network (do not use * in place of /). There is no exception handling on the arguments being passed. Rest of the output will be understood when you run the script.

Further I am thinking to add one or two more functions to define some IPs as exception as per the Vendor's bits of their MAC-Address. For example- some thin-client type devices (as they are going to run in standalone mode only) which give the TTL value of windows range.
The script was made in quite a hurry without any use of classes (moreover I'm not very fond of them), so it's in it's ugliest form ;)

import os
import time
import re
import sys
import pickle
import commands
import subprocess

def add_to_db(nondomain_ips, pickled_ips, domainIPs):
    print "NON domain IPs= ", str(nondomain_ips)
    #raw_input("....")
    print "PICKLED IPs= ",str(pickled_ips)
    #raw_input("....")
    print "Length of PICKLED IPs= ",len(pickled_ips)
    print "domain IPs:- ",str(domainIPs)
    #raw_input("....")
    if (len(pickled_ips) == 0):
        pickled_ips= nondomain_ips
        return pickled_ips
    for new_ip in nondomain_ips:
        print "comparing- ",str(new_ip)
        if new_ip not in pickled_ips:
            print "APPENDING ",str(new_ip),"  to PICKLED IPs"
            pickled_ips.append(new_ip)           
        else:   pass
    for pickled_ip in pickled_ips:
        #print "CHECKING - ",pickled_ip," in domain and in DB file or not"
        if pickled_ip in domainIPs:
            print pickled_ip," JOINED domain, removing from DB file"
            pickled_ips.remove(pickled_ip)
    #print "PICKLED IPs:- ",str(pickled_ips)
    #raw_input("...")
    return pickled_ips
def main():
    if (len(sys.argv)<2):
        print "Wrong args, Give the subnet to scan, Example- \n\npython script.py 192.168.1.0/24 192.168.2.0/24 [more subnets...]\n\nExiting...\n"
        exit(3)
    print "TOTAL SUBNETS TO SCAN:- ",len(sys.argv)
    cwd = os.getcwd()
    print "Current Directory= ",cwd
    outfile = cwd+"\\nmap_op.txt"
    for i in range(1,len(sys.argv)):
    time_now = time.ctime()
        net = sys.argv[i]
        #print i
        #cmd = "nmap -sn " + str(sys.argv[i]) + " -oG "+str(outfile)
        cmd = "nmap -sn " + str(net) + " -oG "+str(outfile)
        print cmd
        try:
            os.remove(outfile)
        except Exception, e:
            print "Error deleting file",str(e)
        #raw_input("SENDING -sn SCAN....\n")
        print "SENDING -sn SCAN....\n"
        os.system(cmd)

        #print "Argv[i]= ",sys.argv[i].split('/')[0]
        print "Argv[i]= ",net.split('/')[0]
        result_file = str(cwd)+"\\"+net.split('/')[0]+"-result.txt"
        print "result file= ",result_file
        #raw_input(" ... ")
        if os.path.exists(outfile):
            print outfile," - oG file created\n\n-------------------------------------\n"
        fp = open(outfile)
        hostlist=[]
        domainIPs = []
        nondomain = []
        ping_file = cwd+"\\response.txt"
        try:
            os.remove(ping_file)
        except Exception, e:
            e=e
        for line in fp.readlines():
            #print line
            #reg = r'Host:(.*\)).*Status.*Up'
            reg = r'Host:\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s(\(.*\)).*Status.*Up'
            res = re.match(reg,line)
            if res:
                #print "\t\t",res.group()
                ip = res.group(1)
                if ('()' in res.group(2)):
                    name = 0
                    nondomain.append([ip,name])
                    ping_cmd = 'ping -n 1 '+str(ip)+'| find "TTL" >>'+cwd+"\\response.txt"
                    os.system(ping_cmd)
                else:
                    name = res.group(2)
                    domainIPs.append(ip)
                hostlist.append([ip,name])
            else:   pass #print "No object"
        fp.close()      ## CLOSE THE NMAP OUTPUT FILE-HANDLE
        print "[+][+] All HOSTS:- ",str(hostlist),"\n"
        #print "domain IPs:- ",str(domainIPs)
        print "TOTAL unresolved IPs:- ",nondomain,"\n"
        nondomain_ip = []
        #print "\n\nIP and TTL from RegExp\n"
        regs = r'Reply from\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*TTL=(\d{1,3})'
        for line in open(ping_file).readlines():
            #print line
            obj = re.search(regs,line)
            if obj:
                ip = obj.group(1)
                ttl = obj.group(2)
                print str(ip)+" --- " + str(ttl)
                if (100<int(ttl)<129):
                    nondomain_ip.append(ip)
        #print "non domain IPs = ",str(nondomain_ip)
        fp_result = open(result_file,'a')
        fp_result.write("\n\n"+time_now+"\n")
        fp_result.write(str(nondomain_ip))
        fp_result.close()

        db_file = cwd+"\\dbfile"
        if not os.path.exists(db_file):
            fpdb = open(db_file,'w')
            fpdb.close()
            if os.path.exists(db_file):
                print "DB_FILE created"
        with open(db_file,'rb') as fpdb:
            try:
                pickled_ips = pickle.load(fpdb)
            except Exception, error:
                print "Error in loading pickeled list"
                pickled_ips = []
                print "Formed new pickled list= ",str(pickled_ips)
        fpdb.close()
        new_list = add_to_db(nondomain_ip, pickled_ips, domainIPs)
        #print "\nNEW IP-ADDRESSES ESTABLISHED AFTER COMPARING ALL LISTS:- \n",str(new_list)
        with open(db_file, 'wb') as fpdb:
            pickle.dump(new_list, fpdb)
        fpdb.close()
        with open(db_file, 'rb') as fpdb:
            ips = pickle.load(fpdb)
            print "\n\n\t\tTHE NON-domain IPs:- \n",str(ips)
            with open("non-domain-ips.txt",'wb') as handle:
                for ip in ips:
                    handle.write(ip)
                    handle.write("\r\n")
            handle.close()
        print "SLEEPING FOR 10 SECONDS..."
        time.sleep(10)
if __name__ == '__main__':
    while True:
        main()
        print "\n\n\n\t\tSCAN COMPLETED...sleep for 5 minutes before running another loop of scan...\n\n\n"
        time.sleep(300)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM