John Deretich <[EMAIL PROTECTED]> writes:
> Hi Patrick,
>
> I tried using the following snippet
> of code in my script to determine
> who's logged on to there machine:
>
> if ( Win32::Lanman::NetWkstaGetInfo( $Machine, \%Info, $bExtendedInfo ) ) {
> print " $Info{computername} \n";
> print " $Info{logged_on_users} \n";
> }
>
> my manager wants me to go this way instead of sending a logoff
> message. But I am getting more than one user logged on to one
> machine, which it should be showing only one user logged on. Would
> you know why?
Yes. To paraphrase the Bard: "There are more users in heaven and hell
than are dreamt of in your philosophy."
I am attaching (once again) my little instances.pl script, which
enumerates all instances of any WMI class you pass on the command
line. Hm, maybe I should put this script up on the Web somewhere...
Anyway, if you run "instances.pl Win32_LoggedOnUser" on an XP system
named HOST in domain DOMAIN, you will see output like this:
Antecedent \\.\root\cimv2:Win32_Account.Domain="HOST",Name="SYSTEM"
Dependent \\.\root\cimv2:Win32_LogonSession.LogonId="999"
Antecedent \\.\root\cimv2:Win32_Account.Domain="HOST",Name="LOCAL SERVICE"
Dependent \\.\root\cimv2:Win32_LogonSession.LogonId="997"
Antecedent \\.\root\cimv2:Win32_Account.Domain="HOST",Name="NETWORK SERVICE"
Dependent \\.\root\cimv2:Win32_LogonSession.LogonId="996"
Antecedent \\.\root\cimv2:Win32_Account.Domain="DOMAIN",Name="luser"
Dependent \\.\root\cimv2:Win32_LogonSession.LogonId="1934903"
This represents four instances of the Win32_LoggedOnUser class. As
you can see, each of the SYSTEM, LOCAL SERVICE, and NETWORK SERVICE
accounts is logged on, and so is the normal user account DOMAIN\luser.
If you now run "instances.pl Win32_LogonSession", you will see
something like this:
AuthenticationPackage NTLM
Caption <undefined>
Description <undefined>
InstallDate <undefined>
LogonId 999
LogonType 0
Name <undefined>
StartTime 20030131091542.968750-300
Status <undefined>
AuthenticationPackage Negotiate
Caption <undefined>
Description <undefined>
InstallDate <undefined>
LogonId 997
LogonType 5
Name <undefined>
StartTime 20030131091546.187500-300
Status <undefined>
AuthenticationPackage Negotiate
Caption <undefined>
Description <undefined>
InstallDate <undefined>
LogonId 996
LogonType 5
Name <undefined>
StartTime 20030131091545.562500-300
Status <undefined>
AuthenticationPackage NTLM
Caption <undefined>
Description <undefined>
InstallDate <undefined>
LogonId 1934903
LogonType 2
Name <undefined>
StartTime 20030203130112.515463-300
Status <undefined>
You can use the LogonId field to line up the Win32_LoggedOnUser
records above with these Win32_LogonSession records. Here, for
example, the session for DOMAIN\luser has LoginId 1934903, and the
corresponding session has LogonType 2, which means "interactive". (By
contrast, logon type 5 means "service". See
http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_logonsession.asp
for all of the possible types.)
You can use "instances.pl -r <machinename> <class>" to query a remote
machine like this. You will find that the interactive session
vanishes when the normal user logs off. But remember, the catch is
that these classes were introduced with XP, so none of this will work
on NT or 2000. There are probably some traditional Win32 API calls to
obtain similar information, but I do not know what they are, nor how
you might access them from Perl.
- Pat
use warnings;
use strict;
use Getopt::Long;
use Pod::Usage;
use Win32::OLE;
# Your usual option-processing sludge.
my %opts;
GetOptions (\%opts, 'help|h|?', 'remote=s')
or pod2usage (2);
(exists $opts{'help'})
and pod2usage ('-exitstatus' => 0, '-verbose' => 2);
# Ensure exactly one argument after options.
scalar @ARGV == 1
or pod2usage (2);
my ($class) = @ARGV;
# Bomb out completely if COM engine encounters any trouble.
Win32::OLE->Option ('Warn' => 3);
# Get a handle to the SWbemServices object of the machine.
my $computer = Win32::OLE->GetObject (exists $opts{'remote'}
? "WinMgmts://$opts{'remote'}/"
: 'WinMgmts:');
# Get the SWbemObjectSet of all objects of the class.
my $instances_set = $computer->InstancesOf ($class);
# Convert set to Perl array.
my @instances = Win32::OLE::Enum->All ($instances_set);
# Display all properties of an object.
sub dump_obj ($) {
my ($obj) = @_;
# Get set of properties of the class.
my $props_set = $obj->{'Properties_'};
# Convert set to Perl array.
my @props = Win32::OLE::Enum->All ($props_set);
foreach my $prop (@props) {
my $name = $prop->{'Name'};
printf "%32s ", $name;
my $value;
if ($prop->{'IsArray'}) {
$value = '<array>';
}
else {
$value = $prop->{'Value'};
defined $value
or $value = '<undefined>';
}
print "$value\n";
}
}
foreach my $instance (@instances) {
dump_obj ($instance);
print "\n";
}
exit 0;
__END__
=head1 NAME
instances.pl - Dump all instances of a WMI class
=head1 SYNOPSIS
instances.pl [ options ] <WMI class name>
Options:
--help Display help and exit
--remote <host> Operate on <host> instead of local machine
=head1 SEE ALSO
http://msdn.microsoft.com/library/en-us/wmisdk/wmi/wmi_classes.asp