#!/usr/local/bin/perl -w
#-*-perl-*-
#
use strict;
use Win32::NetAdmin;
use Win32API::Net;
use vars qw ( @WhoList %UserInfo $UserName %Option );
use Getopt::Std;
use Win32::EventLog;
my ($VERSION) = '$Revision: 1.0 $' =~ /([.\d]+)/;
my $warnings = 0;
# Print a usuage message on a unknown option.
$SIG {__WARN__} = sub {
if (substr ($_ [0], 0, 14) eq "Unknown option") {die "Usage"};
require File::Basename;
$0 = File::Basename::basename ($0);
$warnings = 1;
warn "$0: @_";
};
$SIG {__DIE__} = sub {
require File::Basename;
$0 = File::Basename::basename ($0);
if (substr ($_ [0], 0, 5) eq "Usage") {
die <<EOF;
$0 (NT Perl bin utils) $VERSION
$0 [ -H | -b | -B ] [ -h ]
EOF
}
die "$0: @_";
};
# Get the options.
getopts (
'HhbB',
\%Option
); # -h, -H, -B & -b take no option
die "Usage" if ( $Option{'h'} || scalar keys %Option > 1 );
my $Server = "";
my $Level = "11";
my @Month = (
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
);
LastReboot() if $Option{'b'};
EventID6005() if $Option{'B'};
Win32::NetAdmin::LoggedOnUsers (
$Server,
\@WhoList
)
or die "$^E\n";
printf "%s%30s\n", "USER", "LOGIN-TIME" if $Option{'H'};
foreach $UserName ( @WhoList ) {
UserGetInfo();
}
sub UserGetInfo {
my $LastLogon;
my $Length;
my $UserNameLength = length $UserName;
if ( Win32API::Net::UserGetInfo (
$Server,
$UserName,
$Level,
\%UserInfo
) ) {
my (
$sec,
$min,
$hour,
$mday,
$mon,
$year,
$wday,
$yday,
$isdst
) = localtime ( $UserInfo{lastLogon} );
$Length = 27 - $UserNameLength;
printf "%s%${Length}s %2d %2d:%2d\n",
$UserName,
$Month[$mon],
$mday,
$hour,
$min;
}
else {
$Length = 31 - $UserNameLength;
printf "%s%${Length}s\n", $UserName, "unknown";
}
}
sub LastReboot {
my $Reboot = time - ( Win32::GetTickCount() / 1000 );
my (
$sec,
$min,
$hour,
$mday,
$mon,
$year,
$wday,
$yday,
$isdst
) = localtime ( $Reboot );
printf "%22s %4s %2d %2d:%2d\n", "system boot", $Month[$mon], $mda
+y, $hour, $min;
exit;
}
sub EventID6005 {
my (
$EventLog,
$First,
$Count,
$Event,
%Data
);
Win32::EventLog::Open($EventLog , "System", "")
or die ("EventLog Open() failed");
$EventLog->GetOldest($First)
or die ("EventLog GetOldest() failed");
$EventLog->GetNumber($Count)
or die ("EventLog GetNumber() failed");
$EventLog->Read (
(EVENTLOG_SEEK_READ | EVENTLOG_BACKWARDS_READ),
$First+$Count,
$Event
);
for my $i (0 .. $First+$Count-1) {
$EventLog->Read (
(EVENTLOG_SEQUENTIAL_READ|EVENTLOG_BACKWARDS_READ),
0,
$Event
)
or die ("EventLog Read() failed at event $i");
%Data = %{$Event};
$Data{"EventID"} = $Data{"EventID"} & 0xffff;
next unless $Data{"EventID"} == 6005;
my (
$sec,
$min,
$hour,
$mday,
$mon,
$year,
$wday,
$yday,
$isdst
) = localtime ( $Data{"TimeGenerated"} );
printf "%22s %4s %2d %2d:%2d\n", "system boot", $Month[$mon], $mda
+y, $hour, $min;
exit;
}
}
=pod
=head1 NAME
B<who> - who is on the system
=head1 SYNOPSIS
B<who> [ -H | -b | -B ]
=head1 DESCRIPTION
The who utility can list the user's name and login time for each curre
+nt system user.
The general format for output is:
name time
where:
=over
=item name
user's login name.
=item time
time since user's login.
=back
=head2 OPTIONS
The following options are supported:
=over 4
=item -b
Indicate the approximate time and date of the last reboot.
=item -B
Indicate a more exact but slower to acquire time and date of the last
+reboot.
=item -H
Output column headings above the regular output.
=item -h
Display syntax.
=back
=head1 EXAMPLE
Below is an example of the output B<who> provides without options:
C:\> who
shoehorn unknown
Administrator Jun 22 9:39
Below is an example of the output of B<who -H>:
C:\> who -H
USER LOGIN-TIME
shoehorn unknown
Administrator Jun 22 9:39
Below is an example of the output of B<who -b> and B<who -B>:
C:\> who -b
system boot Jun 21 15:29
=head1 ENVIRONMENT
The working of B<who> is not influenced by any environment variables.
=head1 BUGS
B<who> isn't as nice as I would like, but Win32 isn't Unix, now is it?
+ This I<really> doesn't like Samba domain controllers, which is whi
+I added the 'unknown' entry in the output.
The B<-b> option returns an approximate uptime. It uses the Win32::Ge
+tTickCount() function, an imprecise mechanism. A better was to derri
+ve the last boot is to query the event log for the most recent 6005 o
+r 6009 event and grab that time. If log files are large, this can be
+ time consuming.
B<printf> does not seem to want to pad numbers with '0's.
=head1 STANDARDS
It does not make sense to talk about standards in a B<who> manual page
+.
=head1 REVISION HISTORY
who
Revision 1.0 2000/06/22 07:14:57 idnopheq
Initial revision
=head1 AUTHOR
The Perl implementation of B<who> was written by Dexter Coffin, I<idno
+pheq@home.com>.
=head1 COPYRIGHT and LICENSE
This program is copyright by Dexter Coffin 2000.
This program is free and open software. You may use, copy, modify, dis
+tribute,
and sell this program (and any modified variants) in any way you wish,
provided you do not restrict others from doing the same.
=head1 SEE ALSO
=for html
<a href="uptime.html">uptime</a>, <a href="users.html">users</a><p>
=head1 NEXT TOPIC
=cut
|