User Tools

Site Tools


scripts:perl:scan-network-software.pl
scan-network-software.pl
# Scans a /24 network segment for Windows machines and adds the data to a SQLite database
# Version 0.2
# Written by Thomas York
# This script requires a Windows machine, Win32:WQL, Win32::PingICMP, Win32::Event and SQLite
 
# Variables
$| = 1;
my $database = "network-software.sqlite";
my $i = 1;
my $network = 0;
my $epoch = time();
use strict;
use warnings;
use DBI;
use Win32::PingICMP;
 
# Trim function
sub trim {
	my $t=shift;
	$t =~ s/^\s+|\s+$//g if defined $t;
	return length $t ? $t : 'N/A';
}
 
# Check to make sure the user passed a network segment as an argument
if ($#ARGV != 0 ) {
	print "usage: scan-network-software.pl '/24 network'\neg: scan-network-software.pl 10.1.1.0";
	exit;
}
 
# Trim the passed subnet and possibly return an error if it isn't formatted corrrectly
if ($ARGV[0] =~ m/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/) { 
	$network = "$1.$2.$3.";
} else { # Invalid IPv4 address passed
	print "Sorry, $ARGV[0] is not a valid IPv4 address!\n";
	exit;
}
 
# Connect to SQLite database
print "Connecting to SQLite database...\n";
my $dbhsqlite = DBI->connect("dbi:SQLite:dbname=$database","","");
 
# Verify table layout
my $sqloutput = $dbhsqlite->selectall_arrayref("SELECT * FROM sqlite_master WHERE type='table' AND name='software'");
if (@$sqloutput == 0) { # No table, create it
	print "Creating software table...\n";
	$dbhsqlite->do("create table software(sid integer primary key autoincrement, cid integer, runepoch integer, caption, description, identifyingnumber, installdate, installlocation, installsource, language, localpackage, name, packagecode, packagename, productid, regcompany, regowner, skunumber, transforms, urlinfoabout, urlupdateinfo, vendor, version, wordcount)");
}
 
$sqloutput = $dbhsqlite->selectall_arrayref("SELECT * FROM sqlite_master WHERE type='table' AND name='client'");
if (@$sqloutput == 0) { # No table, create it
	print "Creating client table...\n";
	$dbhsqlite->do("create table client(cid integer primary key autoincrement, runepoch integer, loggedinuser, computername, domain, indomain, ip, os, architecture)");
}
 
# Main program loop
print "Starting scan of network...\n";
for($i = 1; $i < 255; $i++) { # Start at 1 and go to 254
	my $ip = "$network$i";
	print "Pinging $ip\n";
	my $p = Win32::PingICMP->new();
	my $dbhwmi;
	if ($p->ping($ip)) {
		print "Attempting WMI connection with $ip...";
		eval { $dbhwmi = DBI->connect("dbi:WMI:$ip"); }; # Win32::OLE gives a FATAL error if the WMI connection fails!	
		if (!$@) { # If the WMI connection didn't fail, then continue
			print "Success!\n";
 
			# Variables
			my $os;
			my $computername;
			my $arch;
			my $domain;
			my $loggedinuser;
			my $indomain;
			my $cid;
			my $caption;
			my $description;
			my $identifyingnumber;
			my $installdate;
			my $installlocation;
			my $installsource;
			my $language;
			my $localpackage;
			my $name;
			my $packagecode;
			my $packagename;
			my $productid;
			my $regcompany;
			my $regowner;
			my $skunumber;
			my $transforms;
			my $urlinfoabout;
			my $urlupdateinfo;
			my $vendor;
			my $version;
			my $wordcount;
 
			# Get computer information from Win32_OperatingSystem
			my $query = $dbhwmi->prepare("SELECT * from Win32_OperatingSystem");
			$query->execute();
			my @row = $query->fetchrow;
			$os = trim($row[0]->{Caption});
			$computername = trim($row[0]->{CSName});
 
			# The OSArchitecture field is missing from Windows XP/2003 and older installs...so, we must detect it ourselves!
			if ($os =~ m/2000/) { # Windows 2000 (2000 didn't come in x86_64 and we only care about x86 architectures)
				$arch = "32-bit";
			} elsif ($os =~ m/2003/) { # Server 2003
				if ($os =~ m/x64/) { # x86_64 Edition of 2003
					$os =~ s/x64 Edition//; # Get rid of the string "x64 Edition"..
					$arch = "64-bit"; # and set the architecture to 64-bit!
				} else { # The OS is 32-bit
					$arch = "32-bit";
				}
			} elsif ($os =~ m/XP/) { # Windows XP
				if ($os =~ m/x64/) { # x86_64 Edition of XP
					$os =~ s/x64 Edition//; # Get rid of the string "x64 Edition"..
					$arch = "64-bit"; # and set the architecture to 64-bit!
				} else { # The OS is 32-bit
					$arch = "32-bit";
				}
			} else { # Vista or newer has the OSArchitecture field
				$arch = trim($row[0]->{OSArchitecture});
			}
 
			# Get computer information from Win32_ComputerSystem
			$query = $dbhwmi->prepare("SELECT * from Win32_ComputerSystem");
			$query->execute();
			@row = $query->fetchrow;
			if ($row[0]->{PartOfDomain}) { # Fill in with domain info if the machine is in one, otherwise..
				$domain = trim($row[0]->{Domain});
				$indomain = 1;
			} else { # fill out with workgroup!
				$domain = trim($row[0]->{Workgroup});
				$indomain = 0;
			}
			$loggedinuser = trim($row[0]->{UserName});
 
			# Insert an entry in to the client database
			print "Inserting remote computer information...\n";
			$dbhsqlite->do("INSERT INTO client VALUES(NULL, '$epoch', '$loggedinuser', '$computername', '$domain', '$indomain', '$ip', '$os', '$arch')");
			$cid = $dbhsqlite->last_insert_id(undef, undef, undef, undef);
			print "Client ID is $cid\n";
 
			# Query list of installed software from Win32_Product and insert the data in to the database
			$query = $dbhwmi->prepare("SELECT * from Win32_Product");
			print "Retrieving program data from remote computer...\n";
			$query->execute();
			print "Inserting program data in to the database";
			while (@row = $query->fetchrow) { # Every peice of installed software is on its own row
 
				# Assign the data to a variable (if memory is a constraint, replace SQL below with data directly from the array 'row'
 
				# Windows 2003/XP and older are missing some WMI fields. If the OS matches these, don't try to get the data from wMI (WIN32::OLE is a fickle beast)
				if ($os =~ m/2000/ || $os =~ m/XP/ || $os =~ m/2003/) {
					$installsource = "N/A";
					$language = "N/A";
					$localpackage = "N/A";
					$packagecode = "N/A";
					$packagename = "N/A";
					$productid = "N/A";
					$regcompany = "N/A";
					$regowner = "N/A";
					$transforms = "N/A";
					$urlinfoabout = "N/A";
					$urlupdateinfo = "N/A";
					$wordcount = "N/A";
				} else {
					$installsource = trim($row[0]->{InstallSource});
					$language = trim($row[0]->{Language});
					$localpackage = trim($row[0]->{LocalPackage});
					$packagecode = trim($row[0]->{PackageCode});
					$packagename = trim($row[0]->{PackageName});
					$productid = trim($row[0]->{ProductID});
					$regcompany = trim($row[0]->{RegCompany});
					$regowner = trim($row[0]->{RegOwner});
					$transforms = trim($row[0]->{Transforms});
					$urlinfoabout = trim($row[0]->{URLInfoAbout});
					$urlupdateinfo = trim($row[0]->{URLUpdateInfo});
					$wordcount = trim($row[0]->{WordCount});
				}
 
				$caption = trim($row[0]->{Caption});
				$description = trim($row[0]->{Description});
				$identifyingnumber = trim($row[0]->{IdentifyingNumber});
				$installdate = trim($row[0]->{InstallDate});
				$installlocation = trim($row[0]->{InstallLocation});
				$name = trim($row[0]->{Name});
				$skunumber = trim($row[0]->{SKUNumber});
				$vendor = trim($row[0]->{Vendor});
				$version = trim($row[0]->{Version});
 
				# Insert the data in to the database
				print ".";
				$dbhsqlite->do("INSERT INTO software VALUES(NULL, '$cid', '$epoch', '$caption', '$description', '$identifyingnumber', '$installdate', '$installlocation', '$installsource', '$language', '$localpackage', '$name', '$packagecode', '$packagename', '$productid', '$regcompany', '$regowner', '$skunumber', '$transforms', '$urlinfoabout', '$urlupdateinfo', '$vendor', '$version', '$wordcount')");
			}
			print "\n";
 
			# Clean up
			undef $query;
			undef @row;
			undef $os;
			undef $computername;
			undef $arch;
			undef $domain;
			undef $loggedinuser;
			undef $indomain;
			undef $cid;
			undef $caption;
			undef $description;
			undef $identifyingnumber;
			undef $installdate;
			undef $installlocation;
			undef $installsource;
			undef $language;
			undef $localpackage;
			undef $name;
			undef $packagecode;
			undef $packagename;
			undef $productid;
			undef $regcompany;
			undef $regowner;
			undef $skunumber;
			undef $transforms;
			undef $urlinfoabout;
			undef $urlupdateinfo;
			undef $vendor;
			undef $version;
			undef $wordcount;
			$dbhwmi->disconnect;
		} else {# Connection to WMI failed
			print "Failed!\n";
		}
	}
 
	# Clean up
	undef $p;
	undef $ip;
	undef $dbhwmi;
}
 
# Close the SQLite database
$dbhsqlite->disconnect;
undef $dbhsqlite;
undef $database;
undef $i;
undef $network;
undef $epoch;
/var/www/vhost/www.fuhell.com/data/pages/scripts/perl/scan-network-software.pl.txt · Last modified: 2014/09/01 15:00 (external edit)