1 |
rodolico |
1 |
#! /usr/bin/perl -w
|
|
|
2 |
|
|
|
3 |
# sysinfo.pl
|
|
|
4 |
# Author: R. W. Rodolico
|
|
|
5 |
# Operating System: Win32
|
|
|
6 |
# Primary client portion of sysinfo system. Will collect information about its current
|
|
|
7 |
# host and create a report containing the information. This report can then be processed
|
|
|
8 |
# by process_sysinfo.pl on the collection computer.
|
|
|
9 |
# output file consists of a key/value pair, with the key in square brackets, example:
|
|
|
10 |
# [tag]value
|
|
|
11 |
# where tag is the name of the function we are looking at (hostname, report date, cpu type)
|
|
|
12 |
# and value is the associated value.
|
|
|
13 |
# Also has multi line key/values, which are in the form
|
|
|
14 |
# [tag]
|
|
|
15 |
# value1
|
|
|
16 |
# value2
|
|
|
17 |
# [another tag (or end of file)]
|
|
|
18 |
# where value1 and value2 are considered attributes of tag. This is used where there are multiple
|
|
|
19 |
# values for a function, such as for installed packages, IP Addresses, hardware lists, and
|
|
|
20 |
# disk partitions.
|
|
|
21 |
|
|
|
22 |
#use strict;
|
|
|
23 |
#use warnings;
|
|
|
24 |
#no warnings qw(uninitialized);
|
|
|
25 |
use Win32::SystemInfo;
|
|
|
26 |
use Win32::DriveInfo;
|
|
|
27 |
#Optional: Change the delimiter to '/' to eliminate all of the extra backslashes
|
|
|
28 |
use Win32::TieRegistry (Delimiter => "/");
|
|
|
29 |
use Mail::Sendmail;
|
|
|
30 |
|
|
|
31 |
# Following are global variables overridden if configuration file exists
|
|
|
32 |
my $APPLICATION_ROOT;
|
|
|
33 |
my $client_name;
|
|
|
34 |
my $CUSTOM_PACKAGE_FINDER ;
|
|
|
35 |
my @directoriesToWatch;
|
|
|
36 |
# only required if reports are sent from process_sysinfo.pl. Not the norm.
|
|
|
37 |
my $iMailResults = 1; # if 0 (false), ignore following variables
|
|
|
38 |
my $mailTo;
|
|
|
39 |
my $mailCC;
|
|
|
40 |
my $mailBCC;
|
|
|
41 |
my $mailServer;
|
|
|
42 |
my $mailServerPort;
|
|
|
43 |
my $mailFrom;
|
|
|
44 |
my $mailSubject;
|
|
|
45 |
|
|
|
46 |
my $VERSION = '1.3.3 win32';
|
|
|
47 |
|
|
|
48 |
sub getSystemTime {
|
|
|
49 |
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
|
|
|
50 |
localtime(time);
|
|
|
51 |
return sprintf('%4d%02d%02d%02d%02d%02d',$year+1900,$mon+1,$mday,$hour,$min,$sec);
|
|
|
52 |
}
|
|
|
53 |
|
|
|
54 |
sub loadConfigurationFile {
|
|
|
55 |
my $configuration_file = shift;
|
|
|
56 |
unless ( $configuration_file ) { # They didn't give us a configuration filename
|
|
|
57 |
# figure out the configuration filename as the base file name, with .conf on the end
|
|
|
58 |
use File::Basename;
|
|
|
59 |
use Cwd qw(realpath);
|
|
|
60 |
my $path = realpath($0); # get my real path
|
|
|
61 |
my($filename, $directories, $suffix) = fileparse($path,('.pl')); # break filename apart
|
|
|
62 |
$configuration_file = $directories . $filename . '.conf'; # add the .conf
|
|
|
63 |
}
|
|
|
64 |
open CONFFILE, "<$configuration_file" or die "Can not open configuration file $configuration_file";
|
|
|
65 |
my $confFileContents = join( '', <CONFFILE> );
|
|
|
66 |
close CONFFILE;
|
|
|
67 |
return $confFileContents;
|
|
|
68 |
}
|
|
|
69 |
|
|
|
70 |
sub cleanUpString {
|
|
|
71 |
my $value = shift;
|
|
|
72 |
if ($value) {
|
|
|
73 |
$value =~ s/[^[:print:]]+//g;
|
|
|
74 |
} else {
|
|
|
75 |
$value = '';
|
|
|
76 |
}
|
|
|
77 |
return $value;
|
|
|
78 |
}
|
|
|
79 |
|
|
|
80 |
sub buildNetworkLine {
|
|
|
81 |
my ($connection,$ip,$subnet,$gateway,$domain) = @_;
|
|
|
82 |
$connection = &cleanUpString($connection);
|
|
|
83 |
$ip = &cleanUpString($ip);
|
|
|
84 |
$subnet = &cleanUpString($subnet);
|
|
|
85 |
$gateway = &cleanUpString($gateway);
|
|
|
86 |
$domain = &cleanUpString($domain);
|
|
|
87 |
my $line = "$connection\t$ip\t$subnet\t$gateway\t$domain";
|
|
|
88 |
return $line;
|
|
|
89 |
}
|
|
|
90 |
sub getNetworkInformation {
|
|
|
91 |
my $ipInfo = `ipconfig`;
|
|
|
92 |
#print $ipInfo;
|
|
|
93 |
my @ipInfo = split( "\n",$ipInfo );
|
|
|
94 |
chomp @ipInfo;
|
|
|
95 |
my @info = ();
|
|
|
96 |
my $connection = '';
|
|
|
97 |
my $ip = '';
|
|
|
98 |
my $domain = '';
|
|
|
99 |
my $subnet_mask = '';
|
|
|
100 |
my $gateway = '';
|
|
|
101 |
while (my $line = shift @ipInfo) {
|
|
|
102 |
if ( $line =~ m/ethernet adapter.*connection +(\d+)/i ) {
|
|
|
103 |
if ($connection) {
|
|
|
104 |
push @info,&buildNetworkLine($connection,$ip,$subnet_mask,$gateway,$domain);
|
|
|
105 |
}
|
|
|
106 |
$connection = $1;
|
|
|
107 |
$ip = '';
|
|
|
108 |
$domain = '';
|
|
|
109 |
$subnet_mask = '';
|
|
|
110 |
$gateway = '';
|
|
|
111 |
} elsif ( $line =~ m/dns suffix.+\: *(.*)/i ) {
|
|
|
112 |
$domain = $1;
|
|
|
113 |
} elsif ( $line =~ m/ip address.+\: *(.*)/i ) {
|
|
|
114 |
$ip = $1;
|
|
|
115 |
} elsif ( $line =~ m/subnet mask.+\: *(.*)/i ) {
|
|
|
116 |
$subnet_mask = $1;
|
|
|
117 |
} elsif ( $line =~ m/default gateway.+\: *(.*)/i ) {
|
|
|
118 |
$gateway = $1;
|
|
|
119 |
}
|
|
|
120 |
}
|
|
|
121 |
push @info,&buildNetworkLine($connection,$ip,$subnet_mask,$gateway,$domain);
|
|
|
122 |
return "[Network Information]\n" . join( "\n",@info ) . "\n";
|
|
|
123 |
}
|
|
|
124 |
|
|
|
125 |
|
|
|
126 |
sub getUptime {
|
|
|
127 |
my $string = `net statistics server`;
|
|
|
128 |
# my @string = split("\n",$string);
|
|
|
129 |
my $hostName;
|
|
|
130 |
my $lastReboot;
|
|
|
131 |
# while ($string = shift @string) {
|
|
|
132 |
if ($string =~ m/Server Statistics for \\\\(.*)/) {
|
|
|
133 |
$hostName = $1;
|
|
|
134 |
}
|
|
|
135 |
if ($string =~ m/Statistics since(.*)/) {
|
|
|
136 |
$lastReboot = $1;
|
|
|
137 |
}
|
|
|
138 |
# }
|
|
|
139 |
return ($hostName,$lastReboot);
|
|
|
140 |
}
|
|
|
141 |
|
|
|
142 |
sub getSystemInformation {
|
|
|
143 |
my @returnValue;
|
|
|
144 |
# get memory info
|
|
|
145 |
my %hash = (TotalPhys => 0);
|
|
|
146 |
use warnings;
|
|
|
147 |
no warnings qw(all);
|
|
|
148 |
if (Win32::SystemInfo::MemoryStatus(%hash) ) {
|
|
|
149 |
push @returnValue,'[memory]' . $hash{'TotalPhys'};
|
|
|
150 |
}
|
|
|
151 |
my %phash;
|
|
|
152 |
Win32::SystemInfo::ProcessorInfo(%phash);
|
|
|
153 |
# for (my $i = 0; $i < $phash{NumProcessors}; $i++) {
|
|
|
154 |
# print "Speed of processor $i: " . $phash{"Processor$i"}{MHZ} . "MHz";
|
|
|
155 |
# }
|
|
|
156 |
push @returnValue,'[num_cpu] ' . $phash{'NumProcessors'};
|
|
|
157 |
push @returnValue,'[cpu_speed]' . $phash{"Processor0"}{'MHZ'};
|
|
|
158 |
push @returnValue,'[cpu_type]' . $phash{"Processor0"}{'ProcessorName'} . '-' . $phash{"Processor0"}{'VendorIdentifier'};
|
|
|
159 |
push @returnValue,'[cpu_sub]' . $phash{"Processor0"}{'Identifier'};
|
|
|
160 |
# for (my $i = 0; $i < $hash{NumProcessors}; $i++) {
|
|
|
161 |
# $outputData{"Processor $i"}{'Identifier'} = $hash{"Processor$i"}{'Identifier'};
|
|
|
162 |
# $outputData{"Processor $i"}{'Speed'} = $hash{"Processor$i"}{'MHZ'};
|
|
|
163 |
# $outputData{"Processor $i"}{'Vendor ID'} = $hash{"Processor$i"}{'VendorIdentifier'};
|
|
|
164 |
# $outputData{"Processor $i"}{'Name'} = $hash{"Processor$i"}{'ProcessorName'};
|
|
|
165 |
# }
|
|
|
166 |
# } # if
|
|
|
167 |
use warnings qw(all);
|
|
|
168 |
#@returnValue .= '[kernel]' . qx(uname -r);
|
|
|
169 |
my ($hostname,$lastReboot) = &getUptime;
|
|
|
170 |
push @returnValue,"[hostname]$hostname";
|
|
|
171 |
|
|
|
172 |
push @returnValue,"[boot]$lastReboot";
|
|
|
173 |
return join( "\n",@returnValue) . "\n";
|
|
|
174 |
}
|
|
|
175 |
|
|
|
176 |
|
|
|
177 |
sub getDistributionInformation {
|
|
|
178 |
my ($MajorVersion, $MinorVersion, $BuildNumber, $PlatformId, $BuildStr) = Win32::DriveInfo::GetVersionEx ( );
|
|
|
179 |
my $returnValue = '';
|
|
|
180 |
$returnValue .= "[os_name]Windows\n";
|
|
|
181 |
$returnValue .= '[os_version]' . $MajorVersion . '.' . $MinorVersion . "\n";
|
|
|
182 |
$returnValue .= '[distro_description]' . $PlatformId . "\n";
|
|
|
183 |
$returnValue .= '[distro_release]' . $BuildNumber . "\n";
|
|
|
184 |
$returnValue .= '[distro_codename]' . $BuildStr . "\n";
|
|
|
185 |
return $returnValue;
|
|
|
186 |
}
|
|
|
187 |
|
|
|
188 |
sub getDrives {
|
|
|
189 |
my @info;
|
|
|
190 |
my $STANDARD_DRIVE_TYPE = 3; # standard hard drive partition, see Win32::DriveInfo documentation for more info
|
|
|
191 |
my @drives = Win32::DriveInfo::DrivesInUse ( );
|
|
|
192 |
foreach my $drive ( @drives ) {
|
|
|
193 |
if ( Win32::DriveInfo::DriveType ( $drive ) == $STANDARD_DRIVE_TYPE ) {
|
|
|
194 |
my ($SectorsPerCluster,
|
|
|
195 |
$BytesPerSector,
|
|
|
196 |
$NumberOfFreeClusters,
|
|
|
197 |
$TotalNumberOfClusters,
|
|
|
198 |
$FreeBytesAvailableToCaller,
|
|
|
199 |
$TotalNumberOfBytes,
|
|
|
200 |
$TotalNumberOfFreeBytes) = Win32::DriveInfo::DriveSpace($drive);
|
|
|
201 |
my ($VolumeName,
|
|
|
202 |
$VolumeSerialNumber,
|
|
|
203 |
$MaximumComponentLength,
|
|
|
204 |
$FileSystemName,
|
|
|
205 |
@attr) = Win32::DriveInfo::VolumeInfo ( $drive );
|
|
|
206 |
# convert to kilobytes
|
|
|
207 |
$TotalNumberOfBytes /= 1024;
|
|
|
208 |
$TotalNumberOfFreeBytes /= 1024;
|
|
|
209 |
$usedSpace = $TotalNumberOfBytes - $TotalNumberOfFreeBytes;
|
|
|
210 |
push @info,"$drive\t$FileSystemName\t$TotalNumberOfBytes\t$usedSpace";
|
|
|
211 |
}
|
|
|
212 |
}
|
|
|
213 |
return "[Disk Info]\n" . join("\n",@info) . "\n";
|
|
|
214 |
}
|
|
|
215 |
|
|
|
216 |
sub getPackagesInstalled {
|
|
|
217 |
use strict;
|
|
|
218 |
use warnings;
|
|
|
219 |
no warnings qw(uninitialized);
|
|
|
220 |
#%apps will have a list of applications
|
|
|
221 |
my @apps;
|
|
|
222 |
#$softKey points to the Uninstall key that has
|
|
|
223 |
#the Add/Remove Programs information
|
|
|
224 |
my $softKey = $Registry-> {"HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/Uninstall"};
|
|
|
225 |
#Sort and iterate through the keys under Uninstall
|
|
|
226 |
foreach(keys %{$softKey}){
|
|
|
227 |
#Append the key and DisplayName to the Uninstall key
|
|
|
228 |
#Set the result as a key in the %apps hash
|
|
|
229 |
#This also removes any duplicate entries
|
|
|
230 |
my $name = $softKey-> {"$_/DisplayName"};
|
|
|
231 |
next unless $name;
|
|
|
232 |
my $version = $softKey->{"$_/DisplayVersion"};
|
|
|
233 |
unless ( $version ) {
|
|
|
234 |
if ( $softKey->{"$_/VersionMajor"} ) {
|
|
|
235 |
$version = $softKey->{"$_/VersionMajor"} . '.' . $softKey->{"$_/VersionMinor"};
|
|
|
236 |
} elsif ( $softKey->{"$_/InstallDate"} ) {
|
|
|
237 |
$version = $softKey->{"$_/InstallDate"};
|
|
|
238 |
} else {
|
|
|
239 |
$version = 'UNK';
|
|
|
240 |
}
|
|
|
241 |
}
|
|
|
242 |
push @apps, "$name\t$version";
|
|
|
243 |
}
|
|
|
244 |
return "[Packages Installed]\n" . join ("\n", @apps) . "\n";
|
|
|
245 |
}
|
|
|
246 |
|
|
|
247 |
sub getHardware {
|
|
|
248 |
my @hardwareList;
|
|
|
249 |
my $Registry;
|
|
|
250 |
use Win32::TieRegistry 0.20 (
|
|
|
251 |
TiedRef => \$Registry, Delimiter => "/", ArrayValues => 0,
|
|
|
252 |
SplitMultis => 1, AllowLoad => 1,
|
|
|
253 |
qw( REG_SZ REG_EXPAND_SZ REG_DWORD REG_BINARY REG_MULTI_SZ
|
|
|
254 |
KEY_READ ),
|
|
|
255 |
);
|
|
|
256 |
my $machKey= $Registry->Open( "HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Enum/PCI", {Access=>KEY_READ(),Delimiter=>"/"} )
|
|
|
257 |
or die "Can't open PCI key: $^E\n";
|
|
|
258 |
foreach my $subkey ($machKey->SubKeyNames) {
|
|
|
259 |
my $thisVendor = $machKey->Open($subkey);
|
|
|
260 |
foreach my $device ($thisVendor->SubKeyNames) {
|
|
|
261 |
my $thisDevice = $thisVendor->Open($device);
|
|
|
262 |
push @hardwareList,$thisDevice->GetValue( "DeviceDesc" ) . "\t" . $thisDevice->GetValue( "LocationInformation" );
|
|
|
263 |
}
|
|
|
264 |
}
|
|
|
265 |
return "[PCI Info]\n" . join("\n",@hardwareList) . "\n";
|
|
|
266 |
}
|
|
|
267 |
|
|
|
268 |
sub sendResults {
|
|
|
269 |
$mail{'message'} = shift;
|
|
|
270 |
if (sendmail %mail) {
|
|
|
271 |
print "Mail sent OK.\n"
|
|
|
272 |
} else {
|
|
|
273 |
print "Error sending mail: $Mail::Sendmail::error \n"
|
|
|
274 |
}
|
|
|
275 |
print "\n\$Mail::Sendmail::log says:\n", $Mail::Sendmail::log;
|
|
|
276 |
}
|
|
|
277 |
|
|
|
278 |
|
|
|
279 |
my $result;
|
|
|
280 |
if (@ARGV) {
|
|
|
281 |
$result = join("\n", @ARGV) . "\n\n";
|
|
|
282 |
}
|
|
|
283 |
|
|
|
284 |
eval( &loadConfigurationFile ); # load the configuration file
|
|
|
285 |
# parameters are assumed to override configuration file details. If we have parameters
|
|
|
286 |
# they are of the form varname=value, where value is the new value to assign to varname
|
|
|
287 |
# the command has a dollar sign prepended (for the variable) and a semi-colon appended
|
|
|
288 |
# to create a command that may be executed by eval. Thus, this must be a single line
|
|
|
289 |
# no embedded spaces parameter.
|
|
|
290 |
#while ($parameter = shift ) {
|
|
|
291 |
# eval ( '$' . $parameter . ';');
|
|
|
292 |
#}
|
|
|
293 |
|
|
|
294 |
|
|
|
295 |
|
|
|
296 |
$result .= "[sysinfo version]$VERSION\n";
|
|
|
297 |
$result .= '[report date]' . &getSystemTime . "\n";
|
|
|
298 |
$result .= "[client name]$client_name\n";
|
|
|
299 |
$result .= &getDistributionInformation();
|
|
|
300 |
$result .= &getSystemInformation();
|
|
|
301 |
$result .= &getNetworkInformation();
|
|
|
302 |
$result .= &getDrives();
|
|
|
303 |
$result .= &getHardware();
|
|
|
304 |
$result .= &getPackagesInstalled();
|
|
|
305 |
&sendResults($result);
|
|
|
306 |
exit 1;
|
|
|
307 |
|