Blame | Last modification | View Log | RSS feed
#! /usr/bin/perl -w
# sysinfo.pl
# Author: R. W. Rodolico
# Operating System: Win32
# Primary client portion of sysinfo system. Will collect information about its current
# host and create a report containing the information. This report can then be processed
# by process_sysinfo.pl on the collection computer.
# output file consists of a key/value pair, with the key in square brackets, example:
# [tag]value
# where tag is the name of the function we are looking at (hostname, report date, cpu type)
# and value is the associated value.
# Also has multi line key/values, which are in the form
# [tag]
# value1
# value2
# [another tag (or end of file)]
# where value1 and value2 are considered attributes of tag. This is used where there are multiple
# values for a function, such as for installed packages, IP Addresses, hardware lists, and
# disk partitions.
#use strict;
#use warnings;
#no warnings qw(uninitialized);
use Win32::SystemInfo;
use Win32::DriveInfo;
#Optional: Change the delimiter to '/' to eliminate all of the extra backslashes
use Win32::TieRegistry (Delimiter => "/");
use Mail::Sendmail;
# Following are global variables overridden if configuration file exists
my $APPLICATION_ROOT;
my $client_name;
my $CUSTOM_PACKAGE_FINDER ;
my @directoriesToWatch;
# only required if reports are sent from process_sysinfo.pl. Not the norm.
my $iMailResults = 1; # if 0 (false), ignore following variables
my $mailTo;
my $mailCC;
my $mailBCC;
my $mailServer;
my $mailServerPort;
my $mailFrom;
my $mailSubject;
my $VERSION = '1.3.3 win32';
sub getSystemTime {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime(time);
return sprintf('%4d%02d%02d%02d%02d%02d',$year+1900,$mon+1,$mday,$hour,$min,$sec);
}
sub loadConfigurationFile {
my $configuration_file = shift;
unless ( $configuration_file ) { # They didn't give us a configuration filename
# figure out the configuration filename as the base file name, with .conf on the end
use File::Basename;
use Cwd qw(realpath);
my $path = realpath($0); # get my real path
my($filename, $directories, $suffix) = fileparse($path,('.pl')); # break filename apart
$configuration_file = $directories . $filename . '.conf'; # add the .conf
}
open CONFFILE, "<$configuration_file" or die "Can not open configuration file $configuration_file";
my $confFileContents = join( '', <CONFFILE> );
close CONFFILE;
return $confFileContents;
}
sub cleanUpString {
my $value = shift;
if ($value) {
$value =~ s/[^[:print:]]+//g;
} else {
$value = '';
}
return $value;
}
sub buildNetworkLine {
my ($connection,$ip,$subnet,$gateway,$domain) = @_;
$connection = &cleanUpString($connection);
$ip = &cleanUpString($ip);
$subnet = &cleanUpString($subnet);
$gateway = &cleanUpString($gateway);
$domain = &cleanUpString($domain);
my $line = "$connection\t$ip\t$subnet\t$gateway\t$domain";
return $line;
}
sub getNetworkInformation {
my $ipInfo = `ipconfig`;
#print $ipInfo;
my @ipInfo = split( "\n",$ipInfo );
chomp @ipInfo;
my @info = ();
my $connection = '';
my $ip = '';
my $domain = '';
my $subnet_mask = '';
my $gateway = '';
while (my $line = shift @ipInfo) {
if ( $line =~ m/ethernet adapter.*connection +(\d+)/i ) {
if ($connection) {
push @info,&buildNetworkLine($connection,$ip,$subnet_mask,$gateway,$domain);
}
$connection = $1;
$ip = '';
$domain = '';
$subnet_mask = '';
$gateway = '';
} elsif ( $line =~ m/dns suffix.+\: *(.*)/i ) {
$domain = $1;
} elsif ( $line =~ m/ip address.+\: *(.*)/i ) {
$ip = $1;
} elsif ( $line =~ m/subnet mask.+\: *(.*)/i ) {
$subnet_mask = $1;
} elsif ( $line =~ m/default gateway.+\: *(.*)/i ) {
$gateway = $1;
}
}
push @info,&buildNetworkLine($connection,$ip,$subnet_mask,$gateway,$domain);
return "[Network Information]\n" . join( "\n",@info ) . "\n";
}
sub getUptime {
my $string = `net statistics server`;
# my @string = split("\n",$string);
my $hostName;
my $lastReboot;
# while ($string = shift @string) {
if ($string =~ m/Server Statistics for \\\\(.*)/) {
$hostName = $1;
}
if ($string =~ m/Statistics since(.*)/) {
$lastReboot = $1;
}
# }
return ($hostName,$lastReboot);
}
sub getSystemInformation {
my @returnValue;
# get memory info
my %hash = (TotalPhys => 0);
use warnings;
no warnings qw(all);
if (Win32::SystemInfo::MemoryStatus(%hash) ) {
push @returnValue,'[memory]' . $hash{'TotalPhys'};
}
my %phash;
Win32::SystemInfo::ProcessorInfo(%phash);
# for (my $i = 0; $i < $phash{NumProcessors}; $i++) {
# print "Speed of processor $i: " . $phash{"Processor$i"}{MHZ} . "MHz";
# }
push @returnValue,'[num_cpu] ' . $phash{'NumProcessors'};
push @returnValue,'[cpu_speed]' . $phash{"Processor0"}{'MHZ'};
push @returnValue,'[cpu_type]' . $phash{"Processor0"}{'ProcessorName'} . '-' . $phash{"Processor0"}{'VendorIdentifier'};
push @returnValue,'[cpu_sub]' . $phash{"Processor0"}{'Identifier'};
# for (my $i = 0; $i < $hash{NumProcessors}; $i++) {
# $outputData{"Processor $i"}{'Identifier'} = $hash{"Processor$i"}{'Identifier'};
# $outputData{"Processor $i"}{'Speed'} = $hash{"Processor$i"}{'MHZ'};
# $outputData{"Processor $i"}{'Vendor ID'} = $hash{"Processor$i"}{'VendorIdentifier'};
# $outputData{"Processor $i"}{'Name'} = $hash{"Processor$i"}{'ProcessorName'};
# }
# } # if
use warnings qw(all);
#@returnValue .= '[kernel]' . qx(uname -r);
my ($hostname,$lastReboot) = &getUptime;
push @returnValue,"[hostname]$hostname";
push @returnValue,"[boot]$lastReboot";
return join( "\n",@returnValue) . "\n";
}
sub getDistributionInformation {
my ($MajorVersion, $MinorVersion, $BuildNumber, $PlatformId, $BuildStr) = Win32::DriveInfo::GetVersionEx ( );
my $returnValue = '';
$returnValue .= "[os_name]Windows\n";
$returnValue .= '[os_version]' . $MajorVersion . '.' . $MinorVersion . "\n";
$returnValue .= '[distro_description]' . $PlatformId . "\n";
$returnValue .= '[distro_release]' . $BuildNumber . "\n";
$returnValue .= '[distro_codename]' . $BuildStr . "\n";
return $returnValue;
}
sub getDrives {
my @info;
my $STANDARD_DRIVE_TYPE = 3; # standard hard drive partition, see Win32::DriveInfo documentation for more info
my @drives = Win32::DriveInfo::DrivesInUse ( );
foreach my $drive ( @drives ) {
if ( Win32::DriveInfo::DriveType ( $drive ) == $STANDARD_DRIVE_TYPE ) {
my ($SectorsPerCluster,
$BytesPerSector,
$NumberOfFreeClusters,
$TotalNumberOfClusters,
$FreeBytesAvailableToCaller,
$TotalNumberOfBytes,
$TotalNumberOfFreeBytes) = Win32::DriveInfo::DriveSpace($drive);
my ($VolumeName,
$VolumeSerialNumber,
$MaximumComponentLength,
$FileSystemName,
@attr) = Win32::DriveInfo::VolumeInfo ( $drive );
# convert to kilobytes
$TotalNumberOfBytes /= 1024;
$TotalNumberOfFreeBytes /= 1024;
$usedSpace = $TotalNumberOfBytes - $TotalNumberOfFreeBytes;
push @info,"$drive\t$FileSystemName\t$TotalNumberOfBytes\t$usedSpace";
}
}
return "[Disk Info]\n" . join("\n",@info) . "\n";
}
sub getPackagesInstalled {
use strict;
use warnings;
no warnings qw(uninitialized);
#%apps will have a list of applications
my @apps;
#$softKey points to the Uninstall key that has
#the Add/Remove Programs information
my $softKey = $Registry-> {"HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/Uninstall"};
#Sort and iterate through the keys under Uninstall
foreach(keys %{$softKey}){
#Append the key and DisplayName to the Uninstall key
#Set the result as a key in the %apps hash
#This also removes any duplicate entries
my $name = $softKey-> {"$_/DisplayName"};
next unless $name;
my $version = $softKey->{"$_/DisplayVersion"};
unless ( $version ) {
if ( $softKey->{"$_/VersionMajor"} ) {
$version = $softKey->{"$_/VersionMajor"} . '.' . $softKey->{"$_/VersionMinor"};
} elsif ( $softKey->{"$_/InstallDate"} ) {
$version = $softKey->{"$_/InstallDate"};
} else {
$version = 'UNK';
}
}
push @apps, "$name\t$version";
}
return "[Packages Installed]\n" . join ("\n", @apps) . "\n";
}
sub getHardware {
my @hardwareList;
my $Registry;
use Win32::TieRegistry 0.20 (
TiedRef => \$Registry, Delimiter => "/", ArrayValues => 0,
SplitMultis => 1, AllowLoad => 1,
qw( REG_SZ REG_EXPAND_SZ REG_DWORD REG_BINARY REG_MULTI_SZ
KEY_READ ),
);
my $machKey= $Registry->Open( "HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Enum/PCI", {Access=>KEY_READ(),Delimiter=>"/"} )
or die "Can't open PCI key: $^E\n";
foreach my $subkey ($machKey->SubKeyNames) {
my $thisVendor = $machKey->Open($subkey);
foreach my $device ($thisVendor->SubKeyNames) {
my $thisDevice = $thisVendor->Open($device);
push @hardwareList,$thisDevice->GetValue( "DeviceDesc" ) . "\t" . $thisDevice->GetValue( "LocationInformation" );
}
}
return "[PCI Info]\n" . join("\n",@hardwareList) . "\n";
}
sub sendResults {
$mail{'message'} = shift;
if (sendmail %mail) {
print "Mail sent OK.\n"
} else {
print "Error sending mail: $Mail::Sendmail::error \n"
}
print "\n\$Mail::Sendmail::log says:\n", $Mail::Sendmail::log;
}
my $result;
if (@ARGV) {
$result = join("\n", @ARGV) . "\n\n";
}
eval( &loadConfigurationFile ); # load the configuration file
# parameters are assumed to override configuration file details. If we have parameters
# they are of the form varname=value, where value is the new value to assign to varname
# the command has a dollar sign prepended (for the variable) and a semi-colon appended
# to create a command that may be executed by eval. Thus, this must be a single line
# no embedded spaces parameter.
#while ($parameter = shift ) {
# eval ( '$' . $parameter . ';');
#}
$result .= "[sysinfo version]$VERSION\n";
$result .= '[report date]' . &getSystemTime . "\n";
$result .= "[client name]$client_name\n";
$result .= &getDistributionInformation();
$result .= &getSystemInformation();
$result .= &getNetworkInformation();
$result .= &getDrives();
$result .= &getHardware();
$result .= &getPackagesInstalled();
&sendResults($result);
exit 1;