#!/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 < 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], $mday, $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], $mday, $hour, $min; exit; } } =pod =head1 NAME B - who is on the system =head1 SYNOPSIS B [ -H | -b | -B ] =head1 DESCRIPTION The who utility can list the user's name and login time for each current 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 provides without options: C:\> who shoehorn unknown Administrator Jun 22 9:39 Below is an example of the output of B: C:\> who -H USER LOGIN-TIME shoehorn unknown Administrator Jun 22 9:39 Below is an example of the output of B and B: C:\> who -b system boot Jun 21 15:29 =head1 ENVIRONMENT The working of B is not influenced by any environment variables. =head1 BUGS B isn't as nice as I would like, but Win32 isn't Unix, now is it? This I 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::GetTickCount() function, an imprecise mechanism. A better was to derrive the last boot is to query the event log for the most recent 6005 or 6009 event and grab that time. If log files are large, this can be time consuming. B 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 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 was written by Dexter Coffin, I. =head1 COPYRIGHT and LICENSE This program is copyright by Dexter Coffin 2000. This program is free and open software. You may use, copy, modify, distribute, 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 uptime, users

=head1 NEXT TOPIC =cut