Audit Share Perl Script
use Getopt::Long;
#use diagnostics;
#use strict;
use Win32::Console;
use Win32::NetAdmin;
use Win32::Lanman;
##################
# main procedure #
##################
my (%config);
p_parsecmdline(%config, @ARGV);
p_checkargs();
# set console codepage
Win32::Console::OutputCP(1252);
# CODE STARTS HERE
if ($config{duration}) {
my $NumberOfPolls = ($config{duration} * 60) / $config{interval};
my $IntervalInSeconds = $config{interval} * 60;
while ($NumberOfPolls) {
p_EnumConnections($config{machine},$config{share});
--$NumberOfPolls;
sleep $IntervalInSeconds;
}
} else {
p_EnumConnections($config{machine},$config{share});
}
# CODE ENDS HERE
exit 0;
##################
# sub-procedures #
##################
# procedure p_help
# displays a help message
sub p_help {
my ($script)=($0=~/([^\/]*?)$/);
my ($header)=$script." v1.5.1 - Authors: suparatuk@gmail.com - August 2007";
my ($line)="-" x length($header);
print <
$header
$line
Used to audit usage of a network share on a remote server.
Usage: $script /[m]achine /[s]hare /[d]uration
/[i]nterval /[l]og /single /domain
/[v]erbose
/machine Hostname of remote server. Default is localhost.
/share Name of share (double quoted if it contains a space).
/duration Number of days for which you want the audit to run.
/interval Number of minutes between each enumeration. Default is 5 minutes.
/log File name where results must be stored. Default is
"Date.Server.Share.AuditShare.log" in the current directory. A new
log file is created every day.
/single Do not create multiple log files (default is one per day).
/domain Specify the name of a Windows domain against which you want to check
all user names contained in session information. If the user is found,
then the script will also display the user full name and the user description.
This option only works with /duration.
/verbose Display entries as they are created in the log file (valid only with /duration).
/help Displays this help message.
EOT
exit 1;
}
# procedure p_parsecmdline
# parses the command line and retrieves arguments values
sub p_parsecmdline {
my ($config) = @_;
Getopt::Long::Configure("prefix_pattern=(-|/)");
GetOptions($config, qw(
machine|m=s
share|s=s
duration|d=i
interval|i=i
log|l=s
single
domain=s
verbose|v
help|?|h));
}
# procedure p_checkargs
# checks the arguments which have been used are a valid combination
sub p_checkargs {
p_help() if defined($config{help});
unless ($config{share}) {
print "nERROR: You MUST specify a share name!nn";
p_help();
}
unless ($config{machine}) {
$config{machine}=Win32::NodeName();
}
unless ($config{interval}) {
$config{interval} = 5;
}
unless ($config{log}) {
my $time = time();
$time = localtime($time);
my @time = split(/s+/,$time);
$config{log} = "$time[4]$time[1]$time[2].AuditShare.$config{machine}.$config{share}.log";
}
}
# procedure p_EnumConnections
# Enumerates connections made to a given share
sub p_EnumConnections {
my ($Server,$Share) = @_;
my (@Connections,$Connection);
$Server = "\\".$Server;
unless (Win32::Lanman::NetConnectionEnum($Server,$Share,@Connections)) {
print "ERROR: Could not enumerate connections: ".Win32::Lanman::GetLastError();
exit 1;
}
if ($config{duration}) {
foreach $Connection (@Connections) {
if (-f $config{log}) {
open (LOG, "$config{log}") or die "nERROR: could not open $config{log}: $^En";
my $Match = 0;
while (defined(my $LogEntry = )) {
my @LogEntryItems = split(",",$LogEntry);
chomp($LogEntryItems[2]);
unless ($Connection->{username}) {
$Connection->{username} = "Not specified";
if ($LogEntryItems[1] and $Connection->{netname}) {
if ($LogEntryItems[1] eq $Connection->{netname}) {
$Match = 1;
}
}
}
if ($LogEntryItems[2] and $Connection->{username}) {
if ($LogEntryItems[2] eq $Connection->{username}) {
$Match = 1;
}
}
}
close (LOG);
unless ($Match) {
p_log($config{log},"$Connection->{netname},$Connection->{username}");
}
} else {
p_log($config{log},"$Connection->{netname},$Connection->{username}");
}
}
} else {
$~ = 'HEADER';
write;
$~ = 'REPORT';
foreach $Connection (@Connections) {
unless ($Connection->{username}) {
$Connection->{username} = "Not Specified";
}
write;
}
}
format HEADER =
Computer Name Username
------------------ ----------------
.
format REPORT =
@||||||||||||||||| @|||||||||||||||
$Connection->{netname},$Connection->{username}
.
}
# procedure p_log
# manages creating log entries
sub p_log {
my ($logfile,$message) = @_;
my ($pdc,$Server,%attribs);
my $time = time();
$time = localtime($time);
unless ($config{single}) {
my @time = split(/s+/,$time);
my $NewLogFile = "$time[4]$time[1]$time[2].AuditShare.$config{machine}.$config{share}.log";
open (LOG, ">>$NewLogFile") or die "nERROR: could not open $NewLogFile: $^En";
} else {
open (LOG, ">>$logfile") or die "nERROR: could not open $logfile: $^En";
}
if ($config{domain}) {
my @Message = split(",",$message);
unless ($Message[1] eq "Not Specified") {
$Server = Win32::NodeName();
if (Win32::NetAdmin::GetDomainController("\\$Server",$config{domain},$pdc)) {
if (Win32::Lanman::NetUserGetInfo($pdc,$Message[1],%attribs)) {
$attribs{'full_name'} =~ s/,+//g;
$attribs{'comment'} =~ s/,+//g;
if ($config{verbose}) {
print "$time,$message,$attribs{'full_name'},$attribs{'comment'}n";
}
print LOG "$time,$message,$attribs{'full_name'},$attribs{'comment'}n";
} else {
if ($config{verbose}) {
print "$time,$messagen";
}
print LOG "$time,$messagen";
}
} else {
if ($config{verbose}) {
print "$time,$messagen";
}
print LOG "$time,$messagen";
}
}
} else {
if ($config{verbose}) {
print "$time,$messagen";
}
print LOG "$time,$messagen";
}
close (LOG);
}

