
I enhanced my command line ip scanner by adding a Tk gui and adding a few more features. Above, I am scanning a range of contiguous addresses on my home network.
It can also accept a list of hosts from a csv file.

Here are the results from the scan of the above list.

I am forced against my will to use Windows 10 on my PC at work. I also lack admin privileges, so I cannot install a free ip scanner application. I do, however, have ActivePerl installed on my box, and it has tons of modules so I can write my own utilities.
I have several classes of ip devices (routers, switches, battery chargers, etc.) that I want to monitor and have created individual csv files for each. This simple script is highly effective at discovering devices on a subnet, or to give a quick glance at what devices on a list are online.
1 #!/usr/bin/perl -w 2 use strict; 3 use Tkx; 4 use Tkx::Scrolled; 5 use Net::Ping; 6 use Time::HiRes qw(gettimeofday); 7 #main window 8 my $mw = Tkx::widget->new("."); 9 $mw->g_wm_title("nnmap network scanner"); 10 $mw->g_wm_geometry("800x600"); 11 #global vars 12 my $ip_range = ''; 13 my $tdelay = 250; 14 #create ping object 15 my $p = Net::Ping->new('icmp'); 16 #hi res time 17 $p->hires(); 18 #a single ip address 19 my $host; 20 #up / down devices 21 my @online_devices; 22 my @offline_devices; 23 #main content frame 24 my $mfrm = $mw->new_ttk__frame(-padding => "5 10"); 25 $mfrm->g_grid(-column => 1, -row => 0, -sticky => "news"); 26 $mfrm->new_ttk__label(-text => "ip range")->g_grid(-column => 1, -row => 1, -sticky => "nw", -padx => 3, -pady => 1); 27 $mfrm->new_ttk__entry(-textvariable => \$ip_range, -width => 24)->g_grid(-column => 1, -row => 2, -sticky => "nw", -padx => 3, -pady => 1); 28 $mfrm->new_ttk__label(-text => "delay msec")->g_grid(-column => 1, -row => 3, -sticky => "nw", -padx => 3, -pady => 1); 29 $mfrm->new_ttk__spinbox(-from => 1, -to => 900, -width => 5, -textvariable => \$tdelay)->g_grid(-column => 1, -row => 4, -sticky => "nw", -padx => 1, -pady => 2); 30 $mfrm->new_ttk__button(-text => "scan", -command => sub {scan_net($ip_range);})->g_grid(-column => 1, -row => 5, -sticky => "nw", -padx => 1, -pady => 2); 31 my $ta = $mfrm->new_tkx_Scrolled( 32 'text', 33 -scrollbars => "e", 34 -width => 70, 35 -height => 33, 36 -state => "normal" 37 ); 38 $ta->g_grid(-column => 2, -row => 1, -sticky => "e", -padx => 5, -pady => 5, -rowspan => 50); 39 #colors 40 $ta->tag_configure("success", -foreground=>"white", -background=>"green"); 41 $ta->tag_configure("failure", -foreground=>"white", -background=>"red"); 42 #fonts 43 $ta->tag_configure("lgtxt", -font =>"r18", -relief=>"raised", -underline=>1); 44 sub scan_net{ 45 my $func_name = (caller(0))[3]; 46 print "Called $func_name on line ". __LINE__."\n"; 47 48 print "ip range: $ip_range\n"; 49 #parse ip range 50 #only for class c or smaller subnets 51 #?'s in regex account for a single ip address to scan 52 $ip_range =~ /(\d+\.\d+\.\d+)\.(\d+)-?(\d+)?/; 53 my $network = $1; 54 my $start_ip = $2; 55 my $end_ip = $3; 56 57 print "end_ip: $end_ip\tstart ip: $start_ip\n"; 58 #account for just one ip to scan 59 if($end_ip eq ""){ 60 $end_ip = $start_ip; 61 }#end if 62 #convert time delay 63 my $ping_delay = $tdelay * 0.001; 64 #empty text area 65 $ta->delete("1.0", "end"); 66 #get t0 for benchmark 67 my $t0 = gettimeofday(); 68 #line counter 69 my $line_n = 1; 70 for(my $i=$start_ip;$i<=$end_ip;$i++) { 71 $host = "$network.$i"; 72 print "scanning host: $host\n"; 73 #list context, returns duration 74 my ($ret, $dur, $ip) = $p->ping($host, $ping_delay); 75 76 #format time 77 $dur = sprintf("%.6f", $dur); 78 #results 79 if($ret){ 80 #print WHITE ON_GREEN "$host is up latency: $dur seconds", RESET; 81 #form response string 82 my $response = "$host is up $dur seconds"; 83 my $res_len = length($response); 84 if($res_len < 70){#fill up ta rows with color 85 my $n_sp = 70 - $res_len; 86 for(my $x=0;$x<$n_sp;$x++){ 87 $response = $response." "; 88 }#end for add sp 89 }#end if 90 $response = $response."\n"; 91 #print "res_len: $res_len\n"; 92 #print "\n"; 93 $ta->insert("$line_n.0", $response); 94 $ta->tag_add("success", "$line_n.0", "$line_n.0 lineend"); 95 push @online_devices, $host; 96 }#end if 97 else{ 98 my $response = "$host down"; 99 my $res_len = length($response); 100 if($res_len < 70){ 101 my $n_sp = 70 - $res_len; 102 for(my $x=0;$x<$n_sp;$x++){ 103 $response = $response." "; 104 }#end for add sp 105 }#end if 106 $response = $response."\n"; 107 #print "res_len: $res_len\n"; 108 #print WHITE ON_RED "$host down", RESET; 109 #print "\n"; 110 $ta->insert("$line_n.0", $response); 111 $ta->tag_add("failure", "$line_n.0", "$line_n.0 lineend"); 112 push @offline_devices, $host; 113 }#end else 114 #increment line number 115 $line_n++; 116 117 }#end for 118 #results 119 #benchmarking results 120 my $t1 = gettimeofday(); 121 my $elapsed = $t1 - $t0; 122 $elapsed = sprintf("%6f", $elapsed); 123 print "\ntime elapsed: $elapsed....\n"; 124 my $up_sz = @online_devices; 125 my $down_sz = @offline_devices; 126 print "$up_sz devices online\n$down_sz devices offline\n"; 127 #form results 128 my $results = "Results\ntime elapsed: $elapsed\n\n$up_sz devices online\n$down_sz devices offline\n"; 129 130 #insert results 131 $ta->insert("$line_n.0", $results); 132 $ta->tag_add("lgtxt", "$line_n.0", "$line_n.0 lineend"); 133 }#end scan_net 134 sub openCSV{ 135 my $func_name = (caller(0))[3]; 136 print "Called $func_name on line ". __LINE__."\n"; 137 my $fn = Tkx::tk___getOpenFile(); 138 print "FILE: $fn\n"; 139 #open csv file 140 open HF, $fn, or die $!; 141 #empty text area 142 $ta->delete("1.0", "end"); 143 #ping delay 144 my $ping_delay = $tdelay*0.001; 145 #get t0 for benchmark 146 my $t0 = gettimeofday(); 147 #line number counter 148 my $line_n = 1; 149 while(){ 150 my $ipdevice = $_; 151 my @ipdev = split(',', $ipdevice); 152 my $description = $ipdev[1]; 153 $host = $ipdev[2]; 154 $host =~ s/\s+//; 155 $description =~ s/\n//; 156 157 #list context, returns duration 158 my ($ret, $dur, $ip) = $p->ping($host, $ping_delay); 159 print "scanning host: $host\n"; 160 161 #format time 162 $dur = sprintf("%.6f", $dur); 163 164 my $host_desc = $host."\t\t".$description; 165 166 #results 167 if($ret){ 168 #print WHITE ON_GREEN "$host $description is up latency: $dur seconds", RESET; 169 #print "\n"; 170 my $response = "$host $description is up $dur sec"; 171 my $res_len = length($response); 172 if($res_len < 70){#fill up ta rows with color 173 my $n_sp = 70 - $res_len; 174 for(my $x=0;$x<$n_sp;$x++){ 175 $response = $response." "; 176 }#end for add sp 177 }#end if 178 $response = $response."\n"; 179 $ta->insert("$line_n.0", $response); 180 $ta->tag_add("success", "$line_n.0", "$line_n.0 lineend"); 181 push @online_devices, $host_desc; 182 }#end if 183 else{ 184 #print WHITE ON_RED "$host $description down", RESET; 185 #print "\n"; 186 push @offline_devices, $host_desc; 187 my $response = "$host $description down"; 188 my $res_len = length($response); 189 if($res_len < 70){#fill up ta rows with color 190 my $n_sp = 70 - $res_len; 191 for(my $x=0;$x<$n_sp;$x++){ 192 $response = $response." "; 193 }#end for add sp 194 }#end if 195 $response = $response."\n"; 196 $ta->insert("$line_n.0", $response); 197 $ta->tag_add("failure", "$line_n.0", "$line_n.0 lineend"); 198 }#end else 199 $line_n++; 200 }#end while 201 202 close HF; 203 #results 204 #benchmarking results 205 my $t1 = gettimeofday(); 206 my $elapsed = $t1 - $t0; 207 $elapsed = sprintf("%6f", $elapsed); 208 print "\ntime elapsed: $elapsed....\n"; 209 my $up_sz = @online_devices; 210 my $down_sz = @offline_devices; 211 print "$up_sz devices online\n$down_sz devices offline\n"; 212 #form results 213 my $results = "Results\ntime elapsed: $elapsed\n\n$up_sz devices online\n$down_sz devices offline\n"; 214 215 #insert results 216 $ta->insert("$line_n.0", $results); 217 $ta->tag_add("lgtxt", "$line_n.0", "$line_n.0 lineend"); 218 }#end openCSV 219 #menu 220 Tkx::option_add("*tearOff", 0); 221 $mw->configure(-menu => mk_menu($mw)); 222 sub mk_menu{ 223 my $mw = shift; 224 my $menu = $mw->new_menu(); 225 my $file = $menu->new_menu( -tearoff => 0); 226 $menu->add_cascade( 227 -label => "File", 228 -underline => 0, 229 -menu => $file 230 ); 231 $file->add_command( 232 -label => "Open CSV File", 233 -underline => 0, 234 -command => sub {openCSV();} 235 ); 236 $file->add_command( 237 -label => "Exit", 238 -underline => 1, 239 -command => [\&Tkx::destroy, $mw], 240 ); 241 return $menu; 242 }#end mk_menu 243 Tkx::MainLoop();
This is one of those utilities of mine that will probably continue to grow in complexity.