#!/usr/bin/perl -w #################################################################################################################################### # Written by: Jared Cheney ## Copyright 2005 Jared Cheney ## ## License: ## CLeWMI (hereafter referred to as "program") is free software; ## you can redistribute it and/or modify it under the terms of the GNU General ## Public License as published by the Free Software Foundation; either version ## 2 of the License, or (at your option) any later version. ## Note that when redistributing modified versions of this source code, you ## must ensure that this disclaimer and the above coder's names are included ## VERBATIM in the modified code. ## ## Disclaimer: ## This program is provided with no warranty of any kind, either expressed or ## implied. It is the responsibility of the user (you) to fully research and ## comprehend the usage of this program. As with any tool, it can be misused, ## either intentionally (you're a vandal) or unintentionally (you're a moron). ## THE AUTHOR(S) IS(ARE) NOT RESPONSIBLE FOR ANYTHING YOU DO WITH THIS PROGRAM ## or anything that happens because of your use (or misuse) of this program, ## including but not limited to anything you, your lawyers, or anyone else ## can dream up. And now, a relevant quote directly from the GPL: ## ## NO WARRANTY ## ## 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ## FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ## OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ## PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ## OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ## TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ## PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ## REPAIR OR CORRECTION. ## # Creation Date: Apr 16, 2005 # # Changelog: # # 2005-06-19 v1.2-RC2 Jared Cheney # - fixed display bugs when listing in default format and when selecting specific # properties (versus all) # - added flag to just print version # # 2005-05-25 v1.1-RC2 Jared Cheney # - fixed bug that prevented all fields from displaying properly when specifying properties # # 2005-05-17 v1.0-RC2 Jared Cheney # - fixed convertDate option to work when time offset is +*** # - changed output of csv and tab format to not include wmi class and instance # and computername by default; also removed --nodetail flag since now it's # not necessary. # - instead of outputting [BLANK], just changed it to actually output nothing # - added WQL flag to allow custom WQL query to be passed in # - added noheader flag to suppress field names in output # # 2005-05-03 v1.0-RC1 Jared Cheney # - script ready for first release # ############################################################################# ## FIXME's: ## - add username and password options (prompt for password if not specified with user) use strict; no warnings 'uninitialized'; ## cheap, but I don't want to trap for every undef or "" string in this script... use Win32::OLE qw( in ); use Win32::OLE::Variant; # support for OLE data types ## Global Variable(s) my %conf = ( "programName" => $0, ## The name of this program "version" => '1.2-RC2', ## The version of this program "authorName" => 'Jared Cheney', ## Author's Name "authorEmail" => 'jared@iLeaf.net', ## Author's Email Address "debug" => 0, ## Default debug level "mode" => '', "logging" => '1', ## set to 1 if you want to enable logging ## PROGRAM VARIABLES "logFile" => '', ## default log file, if none specified on command line "remoteServer" => 'localhost', ## server we're connecting to "htmlOutput" => '', ## file you want HTML output to go to "tabOutput" => '', ## file you want tab-delimited output to go to "xmlOutput" => '', ## file you want XML output to go to "wmiNameSpace" => '', ## default WMI NameSpace "wmiProperty" => '*', ## default WMI Properties to return (all) "wmiFilter" => '', ## default WMI Filter to apply to query (blank) "wmiRegexpFilter" => '', ## regexp filter applied to instance properties "wmiClass" => '', ## WMI Class to connect to when enumerating instances "listProperties" => 0, ## if 1, list all possible properties available for an instance ## in specified wmiClass "enumClass" => 0, ## if 1, list all possible subClasses of specified class (all if no parent class specified) "enumClassRecursive" => 0, ## if 1, list all possible subClasses of specified class, recursive (all if no parent class specified "enumNameSpace" => 0, ## if 1, list all possible namespaces, beginning with specified namespace "output" => 'list', ## default output format to screen, either csv or tab "manualQueryWMI" => '', ## Used to perform an interactive query against WMI "nobanner" => 0, ## if set, no banner is displayed when executing program "noheader" => 0, ## if set, field headers are not displayed in output "nodetail" => 1, ## prevents WMI class and namespace from being displayed with each line "username" => '', ## username used to connect to remote machines ); $conf{'programName'} =~ s/(.)*[\/,\\]//; ## Remove path from filename $0 = "[$conf{'programName'}]"; ## set remoteServer to correct name if available from env. variable if ($ENV{'COMPUTERNAME'}) {$conf{'remoteServer'} = $ENV{'COMPUTERNAME'};} else { $conf{'remoteServer'} = "."; } ## Variables populated by the configuration file my %audit = (); my @userVars = (); ## global array used for output later my @globalOutput = (); ############################# ## ## MAIN PROGRAM ## ############################# my $stopwatch = time(); ## keep track of how long it takes to run the script ## Initialize initialize(); ## Process Command Line processCommandLine(); if ($conf{'mode'} eq "running") { printmsg ("\nCLeWMI (Command Line WMI) v$conf{'version'}\nby $conf{'authorName'} ($conf{'authorEmail'})\nPROGRAM STARTED on $conf{'remoteServer'} - " . localtime() . "\n",0,1) unless ($conf{'nobanner'}); ############################# ######## MAIN CODE #### ############################# if ($conf{'wmiFilter'}) { ## make sure our OS version supports this flag; XP and 2003 only printmsg ("Going to check OS Version to make sure we can support the -f option",2); filterCheckOSVersion(); } if ($conf{'enumNameSpace'}) { ## establish a connection to WMI my $objectHandle; connectWMI(\$objectHandle,$conf{'userName'}); ## passing a reference to the function recurseNameSpace ($objectHandle,$conf{'wmiNameSpace'},0); quit(); } if ($conf{'enumClass'} || $conf{'enumClassRecursive'}) { ## establish a connection to WMI my $objectHandle; connectWMI(\$objectHandle,$conf{'userName'}); ## passing a reference to the function printmsg ("INFO => Beginning class enumeration for namespace $conf{'wmiNameSpace'}. Be patient, this may take a while",0); recurseClasses ($objectHandle,$conf{'wmiClass'}) if ($conf{'enumClass'}); ## top level only recurseClasses ($objectHandle,$conf{'wmiClass'},0,1) if ($conf{'enumClassRecursive'}); ## recursive quit(); } if ($conf{'listProperties'}) { ## establish a connection to WMI my $objectHandle; connectWMI(\$objectHandle,$conf{'userName'}); ## passing a reference to the function listProperties($objectHandle,$conf{'wmiClass'}); quit(); } if ($conf{'listMethods'}) { ## establish a connection to WMI my $objectHandle; connectWMI(\$objectHandle,$conf{'userName'}); ## passing a reference to the function listMethods($objectHandle,$conf{'wmiClass'}); quit(); } #wmiLook ("/root/cimv2","Win32_Service","*",""); wmiLook ($conf{'wmiNameSpace'},$conf{'wmiClass'},$conf{'wmiProperty'},$conf{'wmiFilter'}); writeList (\@globalOutput,"SCREEN") unless ($conf{'listProperties'}); if ($conf{'tabOutput'}) { printmsg ("INFO => generating TAB output now",0); writeTAB (\@globalOutput); } if ($conf{'htmlOutput'}) { printmsg ("INFO => generating HTML output now",0); writeHTML (\@globalOutput); } if ($conf{'xmlOutput'}) { printmsg ("INFO => generating xml output now (FIXME - not implemented yet",0); ## FIXME - write this function: ## writeXML (\@globalOutput); } } ## Quit printmsg ("INFO => Program execution finished in " . (time() - $stopwatch) . " seconds",1); quit("",0); ###################################################################### ## Function: version () ## ## Description: Prints program version and author ## ###################################################################### sub version { print < Licensed under the terms of the GNU General Public License. EOM exit(1); } ###################################################################### ## Function: help () ## ## Description: For all those newbies ;) ## Prints a help message and exits the program. ## ###################################################################### sub help { print < Licensed under the terms of the GNU General Public License. Command Line WMI (CLeWMI) query tool. Allows one to perform simple Data queries against WMI. Future release should support Schema and Event queries. Usage: $conf{'programName'} [options] -c WMI Class; i.e. Win32_Service -s Server you want to connect to. By default it is localhost -n WMI NameSpace you want to connect to. By default it is /root/cimV2 -p Specify which properties of each instance to return. List the properties separated by commas (no spaces) (i.e. Name,DisplayName,Size). Without this flag, all properties will be returned. -f Only Valid on Windows XP or 2003. Use -r flag for Windows 2000. Filter what instances of a class are returned (i.e. Name~Alert% will return instances where Name property begins with 'Alert' followed by anything) To restrict to an exact match, instead use = instead of ~ (i.e. Name=Alert will return instances where Name property exactly matches 'Alert') You can also reverse the logic of the = sign by prefacing it with ! (i.e. Name!=Alert returns anything that does NOT have Name matching 'Alert') You can also filter on NULL or NOT NULL, like this: e.g. Name=NULL (returns instances with NULL Name property) Name!=NULL (returns instances whose Name property is not NULL) -r Similar to above filter option, but less efficient. It causes all instances of the specified class to be returned from the WMI query, and then just filters the output based on the value specified. Windows 2000 does not support the LIKE operator in WQL queries, hence this flag was created. Syntax is PropertyName~Value, where Value is evaluated as a regular expression, thus allowing great flexibility. RegExp is case insensitive. e.g. Name~windows.* (returns anything with name property beginning with windows and followed by 0 or more characters) Like the -f option, if you use the = character instead of the ~ character, it changes the behaviour of the query slightly. Using != reverses the match. -w This flag allows you to specify an actual WQL query string. If specified, then it overrides the -f or -r flags, as well as the -c flags. Don't use this unless you know what you're doing. e.g. \"Select * FROM Win32_Service WHERE Name = \'Alerter\'\" -o tab|csv|list Choose whether to display output in tab separated, comma separated, or list style format. Default is to display in $conf{'output'} format. --list Lists all possible properties for an instance of the specified class. --listMethods Lists all possible methods available for the specified class. --listNameSpaces Lists all available WMI NameSpaces on a machine --listClasses Lists all available classes for the given NameSpace, top level only (doesn't recurse in). Will start at specific Class, if specified. Only dynamic classes are listed. --recurseClasses Lists all available classes for a given NameSpace, and recurses down into each class. Will start at specific Class, if specified. Lists all subclasses, not just dynamic ones. -v verbosity - use multiple times for greater effect -l logFile to be used. -h | --help Display this help message -V Display program version and exit --nobanner Suppresses display of program name and version at top of script output. Useful when gathering data for import into a spreadsheet. --convertDate Specify this option if you want dates returned by WMI to be in a readable format. Default is to simply return them in the format given. EXAMPLES $conf{'programName'} -c Win32_Service --list Lists all available properties for instances of the Win32_Service class $conf{'programName'} -c Win32_Service -p Name,Status -o tab --nobanner Returns the Name and Status of all Services on a box in tab delimited format. Script banner information is suppressed. $conf{'programName'} -c Win32_Service -p Name,DisplayName -f \"state~%run%\" Returns the Name and DisplayName of all Services whose state contains the word 'run' somewhere in it (-f only works on XP and 2003) $conf{'programName'} -c Win32_Service -p Name,DisplayName -r \"state=run.*\" -o csv Returns the Name and DisplayName of all services whose state contains the word 'run' followed by any set of characters. Results are listed in csv format $conf{'programName'} --listNameSpaces Lists all available namespaces installed on a computer $conf{'programName'} -n /root/cimv2 -s servername --listClasses Lists all available top level classes available to the /root/cimv2 namespace on the remote computer servername EOM exit(1); } #--html HTML output - File you want HTML output written to #--tab Tab-delimited output - File you want Tab-delimited # output written to #--xml XML output - File you want XML output written to #-u If you want to connect to a remote computer, use # this flag. # e.g. -u "DOMAIN\john" # You'll be prompted for a password when the # connection is being made ###################################################################### ## Function: initialize () ## ## Does all the script startup jibberish. ## ###################################################################### sub initialize { ## Set STDOUT to flush immediatly after each print $| = 1; ## Intercept signals $SIG{'QUIT'} = sub { quit("$$ - $conf{'programName'} - EXITING: Received SIG$_[0]", 1); }; $SIG{'INT'} = sub { quit("$$ - $conf{'programName'} - EXITING: Received SIG$_[0]", 1); }; $SIG{'KILL'} = sub { quit("$$ - $conf{'programName'} - EXITING: Received SIG$_[0]", 1); }; $SIG{'TERM'} = sub { quit("$$ - $conf{'programName'} - EXITING: Received SIG$_[0]", 1); }; ## ALARM and HUP signals are not supported in Win32 unless ($^O =~ /win/i) { $SIG{'HUP'} = sub { quit("$$ - $conf{'programName'} - EXITING: Received SIG$_[0]", 1); }; $SIG{'ALRM'} = sub { quit("$$ - $conf{'programName'} - EXITING: Received SIG$_[0]", 1); }; } return(1); } ###################################################################### ## Function: processCommandLine () ## ## Processes command line storing important data in global var %conf ## ###################################################################### sub processCommandLine { ############################ ## Process command line ## ############################ my $x; my @ARGS = @ARGV; my $numargv = scalar(@ARGS); help() unless ($numargv); for (my $i = 0; $i < $numargv; $i++) { $x = $ARGS[$i]; if ($x =~ /^--help$|^-h$/i) { help(); } elsif ($x =~ /^-V$/) { version(); } elsif ($x =~ /^-v+/) { my $tmp = (length($&) - 1); $conf{'debug'} += $tmp; } elsif ($x =~ /^-l$/i) { $i++; $conf{'logFile'} = $ARGS[$i];} elsif ($x =~ /^-s$/i) { $i++; $conf{'remoteServer'} = $ARGS[$i];} elsif ($x =~ /^-n$/i) { $i++; $conf{'wmiNameSpace'} = $ARGS[$i];} elsif ($x =~ /^-p$/i) { $i++; $conf{'wmiProperty'} .= ",$ARGS[$i]"; $conf{'wmiProperty'} =~ s/\*//;} ## add to the string, to allow -p to be used multiple places elsif ($x =~ /^-f$/i) { $i++; $conf{'wmiFilter'} = $ARGS[$i];} elsif ($x =~ /^-r$/i) { $i++; $conf{'wmiRegexpFilter'} = $ARGS[$i];} elsif ($x =~ /^-o$/i) { $i++; $conf{'output'} = $ARGS[$i]; help() if ($conf{'output'} !~ /tab|csv|list/i);} elsif ($x =~ /^-u$/i) { $i++; $conf{'userName'} = $ARGS[$i];} elsif ($x =~ /^-w$|^--wql=$/i) { $i++; $conf{'wql'} = $ARGS[$i];} elsif ($x =~ /^--list$/i) { $conf{'listProperties'} = 1;} elsif ($x =~ /^--listMethods$/i) { $conf{'listMethods'} = 1;} elsif ($x =~ /^--listClasses$/i) { $conf{'enumClass'} = 1;} elsif ($x =~ /^--recurseClasses$/i) { $conf{'enumClassRecursive'} = 1;} elsif ($x =~ /^--listNameSpaces$/i) { $conf{'enumNameSpace'} = 1;} elsif ($x =~ /^--nobanner$/i) { $conf{'nobanner'} = 1;} elsif ($x =~ /^--noheader$/i) { $conf{'noheader'} = 1;} #elsif ($x =~ /^--nodetail/i) { $conf{'nodetail'} = 1;} elsif ($x =~ /^--convertDate/i) { $conf{'convertDate'} = 1;} elsif ($x =~ /^--html$/i) { $i++; $conf{'htmlOutput'} = $ARGS[$i];} elsif ($x =~ /^--tab$/i) { $i++; $conf{'tabOutput'} = $ARGS[$i];} elsif ($x =~ /^--xml$/i) { $i++; $conf{'xmlOutput'} = $ARGS[$i];} elsif ($x =~ /^-c$/i) { $i++; $conf{'wmiClass'} = $ARGS[$i];} elsif ($x =~ /^--audit$/i) { $i++; $conf{'manualQueryWMI'} = $ARGS[$i];} else { quit ("Error: \"$x\" is not a recognised option! Try '$conf{'programName'} -h' for a usage summary", 1); ## help(); } } ## need to remove leading comma, if there $conf{'wmiProperty'} =~ s/^,//; ## set some defaults, if necessary, and fix some things if ($conf{'enumNameSpace'}) { if ("x$conf{'wmiNameSpace'}" eq "x") { $conf{'wmiNameSpace'} = "/root"; } } ## Set default value of namespace to /root/cimv2, if not already set if ("x$conf{'wmiNameSpace'}" eq "x") { $conf{'wmiNameSpace'} = "/root/cimv2"; } ## add leading slash if wasn't specified from command line if ($conf{'wmiNameSpace'} !~ /^\/|\\/) { $conf{'wmiNameSpace'} = "/$conf{'wmiNameSpace'}"; } my @required = ( 'wmiClass', ); #if (!$conf{'userName'} && $conf{'remoteServer'} !~ /^\.$|^$ENV{'COMPUTERNAME'}$/) { # quit("ERROR: Value [userName] was not set after parsing command line arguments! It is required when specifying a remote computer to connect to.", 1); #} if ($conf{'wql'}) { ## set class to something to prevent error from occurring below $conf{'wmiClass'} = "overriddenByWQLStatement"; } foreach (@required) { if ("x$conf{$_}" eq "x") { quit("ERROR: Value [$_] was not set after parsing command line arguments!", 1) unless ($conf{'enumClass'} || $conf{'enumClassRecursive'} || $conf{'enumNameSpace'}); } } ## made it past checks, so safe to set mode to running $conf{'mode'} = "running"; return(1); } ############################################################################################### ## Function: printmsg (string $message, int $level) ## ## Description: Handles all messages - logging them to a log file, ## printing them to the screen or both depending on ## the $level passed in, $conf{'debug'} and wether ## $conf{'mode'}. ## ## Input: $message A message to be printed, logged, etc. ## $level The debug level of the message. If ## not defined 0 will be assumed. 0 is ## considered a normal message, 1 and ## higher is considered a debug message. ## $leaveCarriageReturn Whether or not to strip carriage returns (always will strip, unless other than 0) ## ## Output: Prints to STDOUT, to LOGFILE, both, or none depending ## on the state of the program. ## ## Example: printmsg ("WARNING: We believe in generic error messages... NOT!", 1); ############################################################################################### sub printmsg { my %incoming = (); ( $incoming{'message'}, $incoming{'level'}, $incoming{'leaveCarriageReturn'}, ) = @_; $incoming{'level'} = 0 if (!defined($incoming{'level'})); $incoming{'leaveCarriageReturn'} = 0 if (!defined($incoming{'leaveCarriageReturn'})); $incoming{'message'} =~ s/\r|\n/ /sg unless ($incoming{'leaveCarriageReturn'} >= 1); ## Continue on if the debug level is >= the incoming message level if ($conf{'debug'} >= $incoming{'level'}) { ## Print to the log file if ($conf{'logFile'}) { open (LOGFILE, ">>$conf{'logFile'}"); print LOGFILE "$conf{'programName'}-v$conf{'version'} ". localtime() . " L$incoming{'level'} $incoming{'message'}\n"; close (LOGFILE); } if ($conf{'alertCommand'} && ($conf{'debug'} == 0) && ($incoming{'message'} =~ /ERR|CRIT|WARN/) ) { my $tmpAlert = $conf{'alertCommand'}; $tmpAlert =~ s/MESSAGE/$incoming{'message'}/g; system ($tmpAlert); } ## Print to STDOUT if ($conf{'debug'} > 0) { print STDOUT "$conf{'programName'}-v$conf{'version'}-". localtime() . "-dbg:$incoming{'level'} $incoming{'message'}\n"; } else { print STDOUT "$incoming{'message'}\n"; } } ## Return return(1); } ###################################################################### ## Function: quit (string $message, int $errorLevel) ## ## Description: Exits the program, optionally printing $message. It ## returns an exit error level of $errorLevel to the ## system (0 means no errors, and is assumed if empty.) ## ## Example: quit("Exiting program normally", 0); ###################################################################### sub quit { my %incoming = (); ( $incoming{'message'}, $incoming{'errorLevel'} ) = @_; $incoming{'errorLevel'} = 0 if (!defined($incoming{'errorLevel'})); ## Print exit message if ($incoming{'message'}) { printmsg($incoming{'message'}, 0); } ## Exit exit($incoming{'errorLevel'}); } ############################################## ############################################## ## ## ## WMI specific functions below here ## ## ## ############################################## ############################################## ############################################################################################### ## Function: wmiLook (string $queryString,string $description) ## ## Description: Performs a lookup of wmi value(s) ## ## ## Input: $queryString Full path of wmi property you wish to find ## - If ends in '/', then it assumes it is a class and ## will recurse through all instances and values and return ## data for each value ## - If last word BEGINS with '//' and does not have trailing '/', ## assumes it is a single instance/value and will return the data for it ## - you can include multiple instances of a class at the end of the query, ## just separate them by commas and leave no whitespace. ## Also, you can check to see if a value is matched by putting the ## instancename=matchvalue (see example) ## ## $description String you want generated in the output to 'label' the value looked up ## ## Output: Prints to STDOUT, to LOGFILE, OUTPUTFILE, all, or none depending ## on the state of the program. ## ## Examples: wmiLook ("/root/cimv2","Win32_Service","*",""); ## wmiLook ($conf{'wmiNameSpace'},$conf{'wmiClass'},$conf{'wmiProperty'},$conf{'wmiFilter'}); ############################################################################################### sub wmiLook { #my %incoming = (); #( # $incoming{'wmiQuery'}, # $incoming{'description'}, #) = @_; my ( $wmiNameSpace, $wmiClass, $wmiProperty, $wmiFilter, ) = @_; my $wmiInstance = ""; my $wmiFilterValue = ""; my @wmiOutput = (); my $sep = "~"; ## separation character ## if all properties are desired, then set the wmiProperty field to NULL if ($wmiProperty eq "*") { $wmiProperty = "NULL"; printmsg ("going to return all properties of each instance of class $wmiClass, because wmiProperty field is a *",1); } else { printmsg ("INFO => Going to return properties [$wmiProperty] for instances of class $wmiClass",1); } ## get the filter ready if ("x$wmiFilter" eq "x") { printmsg ("INFO => No filter specified, thus returning all instances of class $wmiClass",1) unless ($conf{'wmiRegexpFilter'}); } elsif ($wmiFilter =~ /\!=NULL/i) { my ($tmpProperty,$tmpValue) = split(/\!=/,$wmiFilter); $wmiFilter = "$tmpProperty IS NOT NULL"; $wmiFilterValue = "[NOT NULL]"; } elsif ($wmiFilter =~ /=NULL/i) { my ($tmpProperty,$tmpValue) = split(/\=/,$wmiFilter); $wmiFilter = "$tmpProperty IS NULL"; $wmiFilterValue = "[NULL]"; } elsif ($wmiFilter =~ /~/) { my ($tmpProperty,$tmpValue) = split(/~/,$wmiFilter); $wmiFilter = "$tmpProperty LIKE '$tmpValue'"; $wmiFilterValue = $tmpValue; if ("x$wmiFilterValue" eq "x") { quit ("ERROR => Your wmiFilter string [$wmiFilter=$wmiFilterValue] is not formatted correctly - You should not specify a WMI Property in the query portion without also specifying a Value; i.e. InterfaceType~SCSI. See documentation for more details",0); } } else { my ($tmpProperty,$tmpValue) = split(/=/,$wmiFilter); $wmiFilter = "$tmpProperty='$tmpValue'"; $wmiFilterValue = $tmpValue; if ("x$wmiFilterValue" eq "x") { quit ("ERROR => Your wmiFilter string [$wmiFilter=$wmiFilterValue] is not formatted correctly - You should not specify a WMI Property in the query portion without also specifying a Value; i.e. InterfaceType~SCSI. See documentation for more details",0); } } ## check to see if -r flag used with = sign if ("x$conf{'wmiRegexpFilter'}" eq "x" && ! $wmiFilter) { printmsg ("INFO => No regexp filter specified, thus displaying all instances of class $wmiClass",1); } elsif ($conf{'wmiRegexpFilter'} =~ /\!=NULL/i) { my ($tmpProperty,$tmpValue) = split(/\!=/,$conf{'wmiRegexpFilter'}); $wmiFilter = "$tmpProperty IS NOT NULL"; $wmiFilterValue = "[NOT NULL]"; } elsif ($conf{'wmiRegexpFilter'} =~ /=NULL/i) { my ($tmpProperty,$tmpValue) = split(/\=/,$conf{'wmiRegexpFilter'}); $wmiFilter = "$tmpProperty IS NULL"; $wmiFilterValue = "[NULL]"; } elsif ($conf{'wmiRegexpFilter'} =~ /.+=.+/) { ## make sure the regexpFilter is using = instead of ~ my ($tmpProperty,$tmpValue) = split(/=/,$conf{'wmiRegexpFilter'}); $wmiFilter = "$tmpProperty='$tmpValue'"; $wmiFilterValue = $tmpValue; if ("x$wmiFilterValue" eq "x") { quit ("ERROR => Your wmiFilter string [$conf{'wmiRegexpFilter'}] is not formatted correctly - You should not specify a WMI Property in the query portion without also specifying a Value; i.e. InterfaceType~SCSI. See documentation for more details",0); } } printmsg ("Details of Query => server:[$conf{'remoteServer'}] - wmiNameSpace:[$wmiNameSpace] - wmiClass:[$wmiClass] - wmiProperty:[$wmiProperty] - wmiFilter:[$wmiFilter]",1); ## establish a connection to WMI my $objectHandle; connectWMI(\$objectHandle,$conf{'userName'}); ## passing a reference to the function #if ($objectHandle = Win32::OLE->GetObject("WinMgmts:{impersonationLevel=impersonate}!//$conf{'remoteServer'}$wmiNameSpace")) { # printmsg ("INFO => Successfully opened a handle to the WMI Name Space $wmiNameSpace",1); #} #else { # quit ("ERROR => problem binding to WMI Path. Error was:" . Win32::OLE->LastError() . " Ending execution of script",3); #} ## will be used later on my $headerLine = "SERVERNAME" .$sep. "WMI NAMESPACE" .$sep. "WMI CLASS" .$sep; ## Now let's look inside if ($objectHandle) { printmsg ("obtained WMI Object handle",3); ## initialize match flag my $match = "NOCOMPARE"; my $wmiRegexpFilter = ""; my $wmiRegexpProp = ""; if ($conf{'wmiRegexpFilter'} =~ /~/) { $wmiRegexpProp = (split(/~/,$conf{'wmiRegexpFilter'}))[0]; $wmiRegexpFilter = (split(/~/,$conf{'wmiRegexpFilter'}))[1]; } ## determine whether to enumerate all properties or just a select few if ("x $wmiProperty" eq "x NULL") { printmsg ("proceeding with all properties of each instance from $wmiClass, because wmiProperty is blank",3); my $wmiQuery = "SELECT * FROM $wmiClass"; my $wmiClassDisplay = $wmiClass; ## String used in output later. if ($wmiFilter) { #$wmiQuery = "SELECT $wmiFilter FROM $wmiClass"; #$wmiClassDisplay .= "." . $wmiProperty; #if ($wmiFilter) { $wmiQuery = "SELECT * FROM $wmiClass WHERE $wmiFilter"; $wmiClassDisplay .= "=" . $wmiFilterValue; #} } ## check to see if custom wql query passed in if ($conf{'wql'}) { $wmiQuery = "$conf{'wql'}"; printmsg ("INFO => received a custom WQL Query, so using that instead of anything that was passed in as a filter with -r or -f flags",1); } printmsg ("wmi Query = [$wmiQuery]",2); my $results = $objectHandle->ExecQuery($wmiQuery); ## FIXME - check for errors now if (scalar(in($results)) lt "1") { printmsg ("WARNING => Check the computer and class name. No information was received from the specified class. wmi query: [$wmiQuery]",0); #push (@globalOutput,$indicator . "WMI|$wmiNameSpace|$wmiClassDisplay|NO ITEM FOUND|$incoming{'description'}|NO VALUE FOUND|$match|UNDEF"); #push (@wmiOutput,"SomeDescription|NOCOMPARE|$wmiNameSpace/$wmiClassDisplay/???|UNDEF|NO VALUE FOUND"); push (@wmiOutput,"NO VALUES FOUND"); } my $resultString = ""; my $i = 0; foreach my $instance (in ($results)) { $i++; printmsg("INFO => --------------------------processing an instance------------------------------",3); ## check to see if we should keep this instance or not my $keep = 1; ## flag used to keep track of whether this instance gets skipped or not if ($wmiRegexpFilter && $instance->{$wmiRegexpProp} =~ /$wmiRegexpFilter/i) { printmsg ("Matches filter [$wmiRegexpFilter], continuing",2); } elsif ($wmiRegexpFilter) { $keep = 0; printmsg ("Skipping this instance, it didn't match filter criteria for regular expression option",2); next; } foreach my $item (in $instance->{Properties_}) { if (ref($item->{Value}) eq "ARRAY") { ## sometimes we'll get back an array my $tmpString = "["; foreach my $value (in($item->{Value}) ) { ## loop through array and add each element to a csv string $tmpString .= "$value;"; } $tmpString =~ s/;$//g; ## remove trailing comma $tmpString .= "]"; ## close off array brackets printmsg ("INFO => Array contents are: $tmpString",3); $headerLine .= "$item->{Name}$sep" if ($i == 1); $resultString .= "$tmpString$sep"; } elsif ($item->{Value}) { ## otherwise a normal value, if populated printmsg ("$item->{Name} = $item->{Value}",3); $headerLine .= "$item->{Name}$sep" if ($i == 1); ## see if it matches date format, and convert it if so if ($conf{'convertDate'} && $item->{Value} =~ /\d{14}\.\d{6}[+-][\d|\*]{3}/i) { ## example: 20050305121057.000000-420 ## yyyymmddHHMMSS.mmmmmmsUUU my $tmp = ($item->{Value}); $tmp =~ s/^(....)(..)(..)(..)(..)(..)\.......(.)(...)$/$2\/$3\/$1 $4:$5:$6/; my $timeOffset = $8; my $sign = $7; if ($timeOffset =~ /\*+/) { printmsg ("asterisks found in 8th pattern:$sign$timeOffset",4); $tmp .= " (GMT $sign" . "0)"; } else { printmsg ("asterisks NOT found in 8th pattern:$sign$timeOffset",4); $tmp .= " (GMT $sign" . ($timeOffset/60) . ")"; } $resultString .= "$tmp$sep"; } else { $resultString .= "$item->{Value}$sep"; } } else { printmsg ("$item->{Name} = [BLANK]",3); $headerLine .= "$item->{Name}$sep" if ($i == 1); $resultString .= "$sep"; } } $resultString =~ s/\$sep$//; push (@wmiOutput,$resultString) if ($keep); $resultString = ""; } } ## Specific properties were specified.. else { printmsg ("Proceeding with individual properties of instances within class $wmiClass. Properties are [$wmiProperty]",3); ## since we're looking for specific instances, let's improve the efficiency of our query my $propertyList = $wmiProperty; ## if we're filtering results using -r option, need to make sure filter criteria is included in the select query if ($wmiRegexpProp && $propertyList !~ /$wmiRegexpProp/i) { $propertyList .= ",$wmiRegexpProp"; } my $wmiQuery = "SELECT $propertyList FROM $wmiClass"; my $wmiClassDisplay = $wmiClass; ## String used in output later. if ($wmiFilter) { $wmiClassDisplay .= "." . $wmiFilter . "=" . $wmiFilterValue; $wmiQuery = "SELECT $propertyList FROM $wmiClass WHERE $wmiFilter"; } ## check to see if custom wql query passed in if ($conf{'wql'}) { $wmiQuery = "$conf{'wql'}"; printmsg ("INFO => received a custom WQL Query, so using that instead of anything that was passed in as a filter with -r or -f flags",1); } printmsg ("wmi Query = [$wmiQuery]",2); my $results = $objectHandle->ExecQuery($wmiQuery); ## FIXME - do an OLE error check here if (scalar(in($results)) lt "1") { printmsg ("WARNING => Check the computer and class name. No information was received from the specified class. wmi query: [$wmiQuery]",0); push (@wmiOutput,"NO VALUE FOUND"); } my $i = 0; foreach my $instance (in ($results)) { $i++; printmsg("INFO => --------------------------processing an instance------------------------------",3); ## check to see if we should keep this instance or not my $keep = 1; ## flag used to keep track of whether this instance gets skipped or not if ($wmiRegexpFilter && $instance->{$wmiRegexpProp} =~ /$wmiRegexpFilter/i) { printmsg ("Matches filter [$wmiRegexpFilter], continuing",2); } elsif ($wmiRegexpFilter) { $keep = 0; printmsg ("Skipping this instance, it didn't match filter criteria for regular expression option",2); #next; } my @properties = split (/,/,$wmiProperty); my $resultString = ""; foreach my $prop (@properties) { if (! $instance->{$prop}) { printmsg ("$prop = [NO VALUE FOUND]",3); $headerLine .= "$prop$sep" if ($i == 1); $resultString .= "$sep"; } else { printmsg ("$prop = [$instance->{$prop}]",3); if (ref($instance->{$prop}) eq "ARRAY") { my $tmpString = "["; foreach my $value (in($instance->{$prop}) ) { $tmpString .= "$value;"; } $tmpString =~ s/;$//g; $tmpString .= "]"; printmsg ("INFO => Array contents are: $tmpString",2); $headerLine .= "$prop$sep" if ($i == 1); $resultString .= "$tmpString$sep"; } else { $headerLine .= "$prop$sep" if ($i == 1); ## check to see if matches date format and if so, convert it to readable format if ($conf{'convertDate'} && $instance->{$prop} =~ /\d{14}\.\d{6}[+-][\d\*]{3}/i) { ## example: 20050305121057.000000-420 ## yyyymmddHHMMSS.mmmmmmsUUU my $tmp = ($instance->{$prop}); $tmp =~ s/^(....)(..)(..)(..)(..)(..)\.......(.)(...)$/$2\/$3\/$1 $4:$5:$6/; my $timeOffset = $8; my $sign = $7; if ($timeOffset =~ /\*+/) { printmsg ("asterisks found in 8th pattern:$sign$timeOffset",4); $tmp .= " (GMT $sign" . "0)"; } else { printmsg ("asterisks NOT found in 8th pattern:$sign$timeOffset",4); $tmp .= " (GMT $sign" . ($timeOffset/60) . ")"; } $resultString .= "$tmp$sep"; } else { $resultString .= "$instance->{$prop}$sep"; } } } } #printmsg ("Result String for this instance is currenlty [$resultString]",0); $resultString =~ s/$sep$//; ## trim off any trailing separator characters #printmsg ("Result String for this instance is currenlty [$resultString]",0); push (@wmiOutput,$resultString) if ($keep); ## only add to result array if this is an instance that matched any filters $resultString = ""; } } } else { quit("ERROR - unable to talk to WMI on this computer, check to make sure that it is available over the network",3); } printmsg ("headerLine is now [$headerLine]",3); $headerLine =~ s/$sep$//; printmsg ("headerLine is now [$headerLine]",3); ## Now add all results onto the global output array for parsing later. push (@globalOutput, "$headerLine"); foreach my $tmp (@wmiOutput) { # "SERVERNAME\tAUDITTYPE\tDESCRIPTION\tMATCHSTATUS\tInspectedElement\tMatchString\tOutput\n"; push (@globalOutput, "$conf{'remoteServer'}$sep$wmiNameSpace$sep$wmiClass$sep" . $tmp); } } ############################################################################################### ## FUNCTION: ## connectWMI () ## ## DESCRIPTION: ############################################################################################### sub connectWMI { my ( $handle, $username, $password, $namespace, ) = @_; ## validate variable value if ("x$namespace" eq "x") { $namespace = $conf{'wmiNameSpace'}; } if ("x$username" eq "x") { if (${$handle} = Win32::OLE->GetObject("WinMgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!//$conf{'remoteServer'}$namespace")) { printmsg ("INFO => Successfully opened a handle to the WMI Name Space $namespace",1); } else { #quit ("ERROR => problem binding to WMI namespace $conf{'wmiNameSpace'}.",1); quit ("ERROR => problem binding to WMI namespace $namespace. Error was:" . Win32::OLE->LastError() . " Ending execution of script",3); } } else { if ("x$password" eq "x") { my $objPassword = Win32::OLE->new('ScriptPW.Password'); print STDOUT 'Please enter your password:'; $conf{'password'} = $objPassword->GetPassword(); $password = $conf{'password'}; print STDOUT "\n"; } my $objSWbemLocator = Win32::OLE->new('WbemScripting.SWbemLocator'); ${$handle} = $objSWbemLocator->ConnectServer($conf{'remoteServer'}, "$namespace", $username, $password, 'MS_409',''); #my $colSwbemObjectSet = ${$handle}->ExecQuery('Select Properties_ From Win32_Process'); #foreach my $objProcess (in $colSwbemObjectSet) { # print 'Process Name: ' . $objProcess->Name, "\n"; #} } # [ strServer = "" ], # [ strNamespace = "" ], # [ strUser = "" ], # [ strPassword = "" ], # [ strLocale = "" ], # [ strAuthority = "" ], # [ iSecurityFlags = 0 ], # [ objwbemNamedValueSet = null ] } ############################################################################################### ## FUNCTION: ## listProperties () ## ## DESCRIPTION: ############################################################################################### sub listProperties { my ( $objService, $strClass, $i, ) = @_; print "Class [$strClass] Available Properties\n\n"; my $objWEBM = $objService->Get($strClass); my $colProperties = $objWEBM->{Properties_}; foreach my $prop (in($colProperties)) { print "$strClass : $prop->{Name}\n"; } #my $colProperties = $objService->{Properties_}; #foreach my $prop (in($colProperties)) { # print "$strClass : $prop->{Name}\n"; #} } ############################################################################################### ## FUNCTION: ## listMethods () ## ## DESCRIPTION: ############################################################################################### sub listMethods { my ( $objService, $strClass, $i, ) = @_; print "Class [$strClass] Available Methods (this script doesn't invoke methods, just reports them)\n\n"; my $objWEBM = $objService->Get($strClass); my $colMethods = $objWEBM->{Methods_}; foreach my $method (in($colMethods)) { print "$strClass : $method->{Name}\n"; } #my $colMethods = $objService->{Methods_}; #foreach my $method (in($colMethods)) { # print "$strClass : $method->{Name}\n"; #} } ############################################################################################### ## FUNCTION: ## recurseNameSpace () ## ## DESCRIPTION: ############################################################################################### sub recurseNameSpace { my ( $objService, $strNameSpace, $i, ) = @_; my $colNameSpaces = $objService->InstancesOf("__NAMESPACE"); foreach my $new (in($colNameSpaces)) { my $tmp = $new->{Name}; my $strNewNameSpace .= "$strNameSpace/$tmp"; printmsg ($strNewNameSpace,0); $conf{'wmiNameSpace'} = $strNewNameSpace; my $objServiceTmp; connectWMI(\$objServiceTmp,$conf{'userName'},$conf{'password'}); ## passing a reference to the function #$objServiceTmp = Win32::OLE->GetObject("WinMgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!//$conf{'remoteServer'}$strNewNameSpace"); ##print "error " . Win32::OLE->LastError() . "\n"; recurseNameSpace ($objServiceTmp,$strNewNameSpace,$i++); } #my $objectHandle; # connectWMI(\$objectHandle,$conf{'userName'}); ## passing a reference to the function # recurseNameSpace ($objectHandle,$conf{'wmiNameSpace'},0); } ############################################################################################### ## FUNCTION: ## recurseClasses () ## ## DESCRIPTION: ############################################################################################### sub recurseClasses { my ( $objService, $strClass, $i, $recurse, ) = @_; if ("x$i" eq "x") { $i = 0; } my $colClasses = $objService->SubclassesOf("$strClass"); my $count = 0; my $dynamicCount = 0; my @final = (); print STDERR "Querying..." unless ($recurse); foreach my $class (in($colClasses)) { print STDERR "." unless ($count % 15 || $recurse); $count++; my $padding = ""; if (! $recurse) { foreach my $objClassQualifier (in($class->{Qualifiers_})) { #print $class->{Path_}->{Class} . " => " . $objClassQualifier->{Name} . ":" . $objClassQualifier->{Value} . "\n" if ($objClassQualifier->{Name} eq "dynamic"); if ($objClassQualifier->{Name} eq "dynamic") { #print "$padding" . $class->{Path_}->{Class} . "\n"; $dynamicCount++; push (@final,$class->{Path_}->{Class} . "\n"); } } } else { for (my $j = 0;$j<$i;$j++) { $padding.=" "; } print "$padding" . $class->{Path_}->{Class} . "\n"; recurseClasses ($objService,$class->{Path_}->{Class},$i+1,$recurse); } } if (! $recurse) { print STDERR "\n"; print sort(@final); } printmsg ("Total top level Classes: $count, $dynamicCount dynamic classes shown",0) unless ($recurse); } ############################################################################################### ## FUNCTION: ## filterCheckOSVersion () ## ## DESCRIPTION: ############################################################################################### sub filterCheckOSVersion { ## if not XP or 2003, need to indicate that -f option won't work. ## unless doing a NULL query #if ($conf{'wmiFilter'} =~ /NULL/) { # ## doesn't apply, so skip checking # return 0; #} ## bind to WMI my $objectHandle; connectWMI(\$objectHandle,$conf{'username'},"","/root/cimv2"); ## check OS version printmsg ("Checking OS Version to ensure -f flag is valid",2); my $result = $objectHandle->execQuery("SELECT Version from Win32_OperatingSystem") || die ("Error trying to query WMI for OS Version"); if (scalar(in($result)) lt "1") { printmsg ("WARNING OSCheck => Check the computer and class name. No information was received from the specified class. wmi query: [SELECT Version from Win32_OperatingSystem]",0); quit ("ERROR while trying to verify OS compatibility with the -f option : " . Win32::OLE->LastError(),1); } foreach my $instance (in($result)) { printmsg ("INFO => OS Version is:" . $instance->{Version},2); my $version = $instance->{Version}; if ($version =~ /^5\.[^0]/) { printmsg ("INFO => Version indicates this is XP or 2003 or higher, proceeding with use of -f flag",1); } elsif ($version =~ /^5\.0/) { quit ("ERROR => the -f flag can only be used on XP or 2003 systems. On Windows 2000, use the -r flag instead to do a regular expression filter. See '$conf{'programName'} -h' for details",1); } else { quit ("ERROR => the -f flag can only be used on XP or 2003 systems. On older versions of Windows, use the -r flag instead to do a regular expression filter. See '$conf{'programName'} -h' for details",1); } } } ############################################################################################### ## FUNCTION: ## writeList () ## ## ## DESCRIPTION: ## uses the @globalOutput array and goes through it line by line and outputs the results to screen ## ## Example: ## writeList (); ## ############################################################################################### sub writeList { ## Get incoming variables my %incoming = (); ( $incoming{'arrayPointer'}, $incoming{'destination'}, ) = @_; my @globalCopy = @globalOutput; my $sep = "~"; #my $headerline = "SERVERNAME\tWMI NAME SPACE\tWMI CLASS\tPROPERTIES\n"; my $i = 0; my @header = ""; my @properties = ""; my $propCount = 0; foreach my $line (@globalCopy) { printmsg ("globalCopy Line: [$line]",3); ## format output if ($conf{'output'} =~ /list/i) { if ($i == 0) { printmsg ("number of elements to process is: " . scalar(split(/$sep/,$line)) . " First line is: $line",4); @properties = split (/$sep/,$line); $propCount = scalar(split(/$sep/,$line)); } elsif ($i == 1) { @header = split (/$sep/,$line); print "Server Name: " . $header[0] . "\n" unless ($conf{'nobanner'}); print "WMI NameSpace: " . $header[1] . "\n" unless ($conf{'nobanner'}); print "WMI Class: " . $header[2] . "\n" unless ($conf{'nobanner'}); print "\n\n" unless ($conf{'nobanner'}); print "[instance $i]\n"; for (my $field = 3;$field < $propCount; $field++) { printmsg("Now processing record $field:" . $properties[$field] . "-" . (split(/$sep/,$line))[$field],4); if ($conf{'noheader'}) { printmsg ("Only printing values since --noheader was specified",5); if ("x" . (split(/$sep/,$line))[$field] ne "x") { printf ("%s\n", (split(/$sep/,$line))[$field]); #$properties[$field] . " : " . (split(/$sep/,$line))[$field] . "\n"; } } else { printmsg ("Printing entire string since didn't specify --noheader",5); printf ("%-30s = %s\n", $properties[$field], (split(/$sep/,$line))[$field]); #$properties[$field] . " : " . (split(/$sep/,$line))[$field] . "\n"; } #printf ("%-20s = %s\n", $properties[$field], (split(/$sep/,$line))[$field]); #$properties[$field] . " : " . (split(/$sep/,$line))[$field] . "\n"; } } elsif ($i >=2) { print "\n[instance $i]\n"; for (my $field = 3;$field < $propCount; $field++) { printmsg("Now processing record $field:" . $properties[$field] . "-" . (split(/$sep/,$line))[$field],4); if ($conf{'noheader'}) { printmsg ("Only printing values since --noheader was specified",3); printf ("%s\n", (split(/$sep/,$line))[$field]); #$properties[$field] . " : " . (split(/$sep/,$line))[$field] . "\n"; } else { printmsg ("Printing entire string since didn't specify --noheader",3); printf ("%-30s = %s\n", $properties[$field], (split(/$sep/,$line))[$field]); #$properties[$field] . " : " . (split(/$sep/,$line))[$field] . "\n"; } } } } else { if (! $conf{'nobanner'} && $i==0) { print "Server Name: " . $conf{'remoteServer'} . "\n"; print "WMI NameSpace: " . $conf{'wmiNameSpace'} . "\n"; print "WMI Class: " . $conf{'wmiClass'} . "\n"; print "\n\n"; } $line =~ s/.*?$sep.*?$sep.*?$sep// if ($conf{'nodetail'}); $line =~ s/$sep/\t/g if ($conf{'output'} =~ /tab/i); $line =~ s/$sep/,/g if ($conf{'output'} =~ /csv/i); $line =~ s/\,$//; print "$line\n" unless ($i == 0 && $conf{'noheader'}); } ## increment counter $i++; } print "\n\nIf you need the output in a format easily imported into a \nspreadsheet program, run '$conf{'programName'} -h' and read \nabout the -o option\n" if (($conf{'output'} =~ /list/i) && ! $conf{'nobanner'}); } ############################################################################################### ## FUNCTION: ## writeHTML () ## ## ## DESCRIPTION: ## uses the @globalOutput array and goes through it line by line and outputs the results to a ## HTML formatted file. ## ## Example: ## writeHTML (); ## ############################################################################################### sub writeHTML { my $date = localtime(); if (! open (OUTHTML,">$conf{'htmlOutput'}") ) { printmsg ("ERROR: Cannot open html file for writing: $!",0); return (2); } my @globalCopy = @globalOutput; ## print out nice HTML headers first print OUTHTML <\n \n \n \n

$ENV{COMPUTERNAME} Audit report

$date

Expand All Collapse All Refresh page



\n EOM my $header = "UNDEF"; ## flag to indicate whether headers have been printed yet my $ctr = 0; my $headerClass = "cell"; my @output = (); my $pastFirstHeader = 0; foreach my $line (@globalCopy) { $ctr++; # used to create unique div id's my $i = $ctr . "_$conf{'remoteServer'}"; my $class = "none"; ## used for CSS formatting if ($line =~ /^:::/) { ## This line indicates a group header to be processed. $header = ":::"; ## unless this is the first header encountered, we need to flush the output array ## in preparation for the next header and sub objects. if (! $pastFirstHeader) { ## do nothing printmsg ("At the first header during HTML processing",4); ## increment pastFirstHeader now that we've encountered the first one $pastFirstHeader++; } else { ## print out what's in @output push (@output,"
\n"); $output[0] =~ s/HEADERCLASS/$headerClass/g; print OUTHTML @output; ## add another to pastFirstHeader count $pastFirstHeader++; } @output = (); $headerClass = "cell"; my $tmp = substr($line,rindex($line,":::")+3); $header = "
+ - $tmp
"; push (@output,$header); } ## format it with table code if ($line =~ /\|NOMATCH\|/) { ## no match $class = "nomatch"; $headerClass= "hnomatch"; } elsif ($line =~ /\|MATCH\|/) { ## match $class = "match"; $headerClass = "hmatch" unless ($headerClass =~/nomatch/); } elsif ($line =~ /\|NOCOMPARE\|/) { ## don't care $class = "none"; } if ($line =~ /^:::/) { $line = ""; } ## this indicates a group header line # 0 SERVERNAME # 1 SECTIONNAME # 2 AUDITTYPE # 3 DESCRIPTION # 4 MATCHSTATUS # 5 InspectedElement # 6 MatchString # 7 Output my @details = split(/\|/,$line); ## format inspected element differently for LDAP type queries for HTML output if ($details[2] eq "LDAP") { $details[5] =~ s/(.*)(ATTRIBUTE.*)/$2/; } my $entry = "" . ""; #$line =~ s/\|/\<\/td\>\"; $line = "$entry"; $line .= $subDetail . "\n"; ## fix match strings for CMD output $line =~ s/:MATCHED-://g; $line =~ s/:-MATCHED:/<\/font><\/b>/g; ## convert newlines to
's $line =~ s/\\n/\/g; if ($class eq "nomatch") { #print OUTHTML "$line\n"; push (@output, "$line\n"); } else { #print OUTHTML "$line\n"; push (@output, "$line\n"); } } ## perform final section write push (@output,"
Description
Inspected Element
Audit Type
Match Status
" . $details[3] . "" . $details[5] . "" . $details[2] . "" . $details[4] . "/g; my $subDetail = ""; my $z = 0; my @headers = ("ServerName","SectionName","AuditType","Description","MatchStatus","InspectedElement","MatchString","Output"); foreach my $detail (split(/\|/,$line)) { $subDetail .= "
  • $headers[$z] : $detail"; $z++; } $subDetail = "
  • $subDetail
    \n"); $output[0] =~ s/HEADERCLASS/$headerClass/g; print OUTHTML @output; ## print out nice closing HTML code print OUTHTML < EOM close (OUTHTML); } ############################################################################################### ## FUNCTION: ## writeTAB () ## ## ## DESCRIPTION: ## uses the @globalOutput array and goes through it line by line and outputs the results to a ## tab-delimited file. ## ## Example: ## writeTAB (); ## ############################################################################################### sub writeTAB { ## Get incoming variables my %incoming = (); ( $incoming{'arrayPointer'}, $incoming{'destination'}, ) = @_; my @globalCopy = @globalOutput; if ($incoming{'destination'} eq "SCREEN") { } elsif (! open (OUTTAB,">$conf{'tabOutput'}") ) { printmsg ("ERROR: Cannot open tab-delimited file for writing: $!",0); return (2); } my $header = "UNDEF"; ## flag to indicate whether headers have been printed yet my $headerline = "SERVERNAME\tSECTIONNAME\tAUDITTYPE\tDESCRIPTION\tMATCHSTATUS\tInspectedElement\tMatchString\tOutput\n"; if ($incoming{'destination'} eq "SCREEN") { print $headerline; } else { print OUTTAB $headerline; } foreach my $line (@globalCopy) { printmsg ("globalCopy Line: [$line]",3); if ($line =~ /^:::/) { ## This line indicates a group header to be processed. ## do nothing printmsg ("Group header, doing nothing",3); } ## if CMD output, we won't display the output because it's an array elsif ($line =~ /\|CMD\|/) { printmsg ("processing CMD: [[$line]]",3); $line =~ s/(.*)\|.*$/$1\|ARRAY-therefore not displayed/gs unless ($line !~ /\n/g); #$line =~ s/\n/\\n/g; } ## format it with tabs $line =~ s/\|/\t/g; if ($incoming{'destination'} eq "SCREEN") { print "$line\n" unless ($line =~ /^:::/); } else { print OUTTAB "$line\n" unless ($line =~ /^:::/); } } if ($incoming{'destination'} eq "SCREEN") {} else {close (OUTTAB);} }