perl-win32-users-boun...@listserv.activestate.com wrote on 06/05/2012
03:00:02 PM:
> A non-text attachment was scrubbed...
> Name: pullFromEventLog.pl
It was a text attachment, you silly little program... Well, I don't know
how to get my mailer to send text only, so I can't blame it much.
Its only 250 lines, so hopefully the list will not mind if I post it
directly.
#!c:\perl\bin\perl.exe
# vim:sw=2:et:ic:sm:syn=perl:nu
#
# $Id: pullFromEventLog.pl,v 1.4 2009/12/28 14:24:57 edf78qd Exp edf78qd $
#
# $Log: pullFromEventLog.pl,v $
# Revision 1.4 2009/12/28 14:24:57 edf78qd
# Cleaned up the CIM into a standard mysql datetime format before
insertion.
#
# Revision 1.3 2009/09/24 22:05:48 edf78qd
# Added some docs
#
# Revision 1.2 2009/09/21 13:36:09 edf78qd
# made it a stand-alone, so that it would run as a child process.
# Added some instrumentation to log.$$.log
#
# Revision 1.1 2009/09/18 19:04:42 edf78qd
# Initial revision
#
=pod
Database structure for table logentries: most of these come straight from
windows event log fields (as seen below). I just add "host" and "string"
at the end (for the FQDN host containing log entry, and the string that
the
host is in).
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| logID | int(10) unsigned | NO | PRI | NULL |
auto_increment |
| Category | int(10) unsigned | YES | | NULL | |
| CategoryString | tinytext | YES | | NULL | |
| ComputerName | tinytext | YES | | NULL | |
| Data | text | YES | | NULL | |
| EventCode | int(10) unsigned | YES | | NULL | |
| EventIdentifier | int(10) unsigned | YES | | NULL | |
| EventType | int(11) | YES | | NULL | |
| InsertionStrings | text | YES | | NULL | |
| LogFile | tinytext | YES | | NULL | |
| Message | text | YES | | NULL | |
| RecordNumber | int(10) unsigned | YES | | NULL | |
| SourceName | tinytext | YES | | NULL | |
| TimeGenerated | datetime | YES | | NULL | |
| TimeWritten | datetime | YES | | NULL | |
| Type | tinytext | YES | | NULL | |
| User | tinytext | YES | | NULL | |
| Host | tinytext | YES | | NULL | |
| string | tinytext | YES | | NULL | |
+------------------+------------------+------+-----+---------+----------------+
=cut
use strict;
use Win32::OLE qw(in);
use Getopt::Std;
use DBI;
my $now = time;
my $DEBUG = 0;
$| = 1;
our %opts;
getopts( 'hu:p:s:H:', \%opts );
if ( $opts{'h'} ) {
print <<EOH;
usage: $0 [-h] -u username -p password
-h this message
-u domain qualified username (e.g. ad\\hashid)
-p password, in quotes if necessary
-s string (for addition to DB)
-H limit to specific hosts (comma delimited)
EOH
exit;
}
my $TEXT = "
class Win32_NTLogEvent
{
uint16 Category;
string CategoryString;
string ComputerName;
uint8 Data[];
uint16 EventCode;
uint32 EventIdentifier;
uint8 EventType;
string InsertionStrings[];
string Logfile;
string Message;
uint32 RecordNumber;
string SourceName;
datetime TimeGenerated;
datetime TimeWritten;
string Type;
string User;
};
";
my ( $mib, @properties ) = text2properties($TEXT);
my $FQDN = $opts{'H'};
if ($DEBUG) {
open F, '>', "log.$$.log" or die "can't open log.$$.log: $_";
}
print "Process $$ to $FQDN (" . localtime(time) . ")\n";
print F "Process $$ to $FQDN (" . localtime(time) . ")\n" if $DEBUG;
my $locatorObj = Win32::OLE->new('WbemScripting.SWbemLocator')
|| die "Error creating locator object: "
. Win32::OLE->LastError() . "\n";
$locatorObj->{Security_}->{impersonationlevel} = 3;
# $locatorObj->{Security_}->{setdebugpriviledge} = 1;
my $rv = 0;
my $serverObj = $locatorObj->ConnectServer( # connect to WMI server
$FQDN, # on this host
'root\cimv2', # this namespace
$opts{'u'}, # user
$opts{'p'}
) # password
|| ( $rv = 1 );
if ($rv) {
print "Process $$ had an error connecting to $FQDN: "
. Win32::OLE->LastError() . "\n";
print F "Process $$ had an error connecting to $FQDN: "
. Win32::OLE->LastError() . "\n"
if $DEBUG;
exit;
}
my $dbh = DBI->connect( 'DBI:mysql:eventlogs', 'woody', '' )
or die "Can't connect to mysql: $!";
my $sth = $dbh->prepare(
"SELECT lastEntry FROM newestlogs WHERE Host LIKE '$FQDN'")
or die "Can't prepare search for max: " . $dbh->errstr();
$sth->execute()
or die "Can't execute search for max: " . $dbh->errstr();
my $ref = $sth->fetchrow_arrayref;
my $searchTime = convert2CIM( $$ref[0] );
my $preparestr =
"INSERT INTO logentries VALUES (0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, '$FQDN', '$opts{'s'}')";
$sth = $dbh->prepare($preparestr)
or die "Can't prepare insert: " . $dbh->errstr();
my $once = 0;
my $count = 0;
print "looking for log entries since $searchTime\n";
print F "looking for log entries since $searchTime\n" if $DEBUG;
my $newestLogDate;
foreach my $obj (
in $serverObj->ExecQuery(
"SELECT * FROM WIN32_NTLogEvent WHERE (TimeGenerated > '$searchTime')",
'WQL',
48
)
) {
$count++;
if ( not $once ) {
print "DB call for $FQDN returned in "
. ( time - $now )
. " seconds\n";
print F "DB call for $FQDN returned in "
. ( time - $now )
. " seconds\n"
if $DEBUG;
$once = 1;
}
my @params = ();
foreach my $property (@properties) {
if ( ref $obj->{$property} eq 'ARRAY' ) {
my $str = join( ",", @{$obj->{$property}} );
$str =~ tr/\r\n\t/ /s;
push @params, $str;
} elsif ( $property eq 'Message' ) {
my $mess = $obj->{$property};
$mess =~ tr/\r\n\t/ /s;
push @params, $mess;
} elsif ( ( $property eq 'TimeGenerated' )
or ( $property eq 'TimeWritten' ) ) {
my $time = $obj->{$property};
push @params, convertFromCIM($time);
} else {
push @params, $obj->{$property};
}
} ## end foreach my $property (@properties)
$sth->execute(@params)
or die "$$ can't insert params ", join( ", ", @params ),
" sorry. " . $dbh->errstr();
$newestLogDate = $obj->{TimeGenerated};
} ## end foreach my $obj ( in $serverObj...
print "Captured $count NT Event Log records for $FQDN\n";
print F "Captured $count NT Event Log records for $FQDN\n" if $DEBUG;
updateNewestLogs( $FQDN, $newestLogDate );
exit; # main
sub text2properties {
my @tokens = split( /\s+/, shift );
my $i = 0;
while ( ( $i < $#tokens ) and ( $tokens[$i] ne 'class' ) ) {
$i++;
}
if ( $tokens[$i] ne 'class' ) {
die "Please check your input text, couldn't find 'class'\n";
} else {
$i++;
}
my $mib = $tokens[$i];
my @rv;
foreach my $token (@tokens) {
if ( $token =~ /;/ ) {
chop $token;
next if ( $token eq '}' );
if ( $token =~ /\[/ ) {
chop $token;
chop $token;
}
push @rv, $token;
}
}
return ( $mib, @rv );
} ## end sub text2properties
sub convert2CIM {
my $time = shift;
return '20090917000000.000000-240'
if not defined $time; # day zero of the run
# probably something related to real time would be better, maybe 'start
from yesterday'
if ( $time =~ m/(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/ ) {
return sprintf( '%04d%02d%02d%02d%02d%02d.000000-300',
$1, $2, $3, $4, $5, $6 );
} else {
die "bad time $time\n";
}
}
sub convertFromCIM {
my $CIM = shift;
if ( $CIM =~ /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)\.\d+-300$/ ) {
return
sprintf( '%04d-%02d-%02d %02d:%02d:%02d', $1, $2, $3, $4, $5,
$6 );
} else {
die "Bad CIM $CIM\n";
}
}
sub updateNewestLogs {
my $host = shift;
my $date = convertFromCIM(shift);
my $sth =
$dbh->prepare("UPDATE newestlogs SET lastEntry=? WHERE host=?")
or die "can't prepare update for newestlogs: " . $dbh->errstr();
$sth->execute( $date, $host )
or die "can't update newestlog setting $host to $date: "
. $dbh->errstr();
}
_______________________________________________
Perl-Win32-Users mailing list
Perl-Win32-Users@listserv.ActiveState.com
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs