860 lines
27 KiB
Perl
860 lines
27 KiB
Perl
#-----------------------------------------------------------------//
|
|
# Script: WMIFE.pm
|
|
#
|
|
# (c) 2001,2002 Microsoft Corporation. All rights reserved.
|
|
#
|
|
# addresses the generic OLE->WMI interface to test various stuff
|
|
# defined on the given remote box
|
|
#
|
|
# Version: <2.01> 06/11/2002 : Serguei Kouzmine
|
|
#
|
|
#-----------------------------------------------------------------//
|
|
|
|
package WMIFE;
|
|
use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts";
|
|
use lib $ENV{RAZZLETOOLPATH};
|
|
use PbuildEnv;
|
|
use Logmsg;
|
|
|
|
require Exporter;
|
|
use vars qw( @ISA @EXPORT_OK );
|
|
@ISA = ( 'Exporter' );
|
|
@EXPORT_OK = qw( $verbose );
|
|
|
|
my $hPrivileges = {"SeBackupPrivilege" => "Backup",
|
|
"SeSecurityPrivilege" => "Security",
|
|
"SeRestorePrivilege" => "Restore",
|
|
"SeShutdownPrivilege" => "ShutDown",
|
|
"SeRemoteShutdownPrivilege" => "RemoteShutdown"
|
|
};
|
|
|
|
use strict;
|
|
no strict 'refs';
|
|
use Win32::OLE qw(in with);
|
|
use Win32::OLE::Variant;
|
|
# use 'in' loop for retrieve WQL cursors
|
|
|
|
use vars qw( $verbose
|
|
$NameSpace
|
|
$impersonationLevel
|
|
$authLevel
|
|
$Privileges
|
|
$ComputerName
|
|
$MasterData
|
|
$Provider
|
|
$Query
|
|
$DisplayFields
|
|
$User
|
|
$Password
|
|
$DEBUG
|
|
$TIMEOUT
|
|
$sRootKey
|
|
$sBootTestDataSubKey
|
|
$sLogonUserDataSubKey
|
|
);
|
|
my $VERSION = "1.1";
|
|
$TIMEOUT = 60;
|
|
$DEBUG = 0;
|
|
$verbose = ["NO","YES"];
|
|
my $SEPARATOR = "\n". join("", map{chr(61)} 0..79). "\n";
|
|
$NameSpace = "root\\cimv2";
|
|
$sRootKey = "HKEY_LOCAL_MACHINE";
|
|
$sBootTestDataSubKey = "SOFTWARE\\MICROSOFT\\BOOTTEST";
|
|
$sLogonUserDataSubKey = "SOFTWARE\\MICROSOFT\\WINDOWS NT\\CURRENTVERSION\\WINLOGON";
|
|
$impersonationLevel = "impersonate";
|
|
$authLevel = "pktPrivacy";
|
|
|
|
$Privileges = join(",", values(%$hPrivileges));
|
|
$Provider = q(WbemScripting.SWbemLocator);
|
|
$MasterData=
|
|
q(winmgmts:{impersonationLevel=$impersonationLevel,authenticationLevel=$authLevel, ($Privileges)}!
|
|
\\\\$ComputerName\\$NameSpace);
|
|
|
|
|
|
sub ObjectExecMethod{
|
|
|
|
my ($WbemObjClassName, $MethodName, $ComputerName, $ParameterName, $ParameterValue, $User, $Password) = @_;
|
|
|
|
# play with the command line expansion
|
|
# here.
|
|
$DEBUG and print STDERR
|
|
"ObjectExecMethod: using PROVIDER: ", $Provider, " " , $User, "\n";
|
|
my $WbemLocator = Win32::OLE->new($Provider);
|
|
|
|
OLEerrmsg("Could not instatiate $Provider") unless defined $WbemLocator;
|
|
|
|
my $SWbemServices = ($User =~ /\*/) ?
|
|
$WbemLocator->ConnectServer( $ComputerName, $NameSpace) :
|
|
$WbemLocator->ConnectServer( $ComputerName, $NameSpace, $User, $Password );
|
|
|
|
defined $SWbemServices or
|
|
OLEerrmsg("Cannot connect: $ComputerName, $NameSpace");
|
|
|
|
# Make sure we are using the appropriate security level
|
|
OLEerrmsg("Error setting security level")
|
|
if ( !($SWbemServices->{Security_}->{ImpersonationLevel} = 3) );
|
|
|
|
map {
|
|
$SWbemServices->{Security_}->{Privileges}->AddAsString($_)
|
|
or OLEerrmsg( "Error setting $hPrivileges->$_ privileges");
|
|
} keys %$hPrivileges;
|
|
|
|
# Get the process object on the remote machine
|
|
my $WbemObject = $SWbemServices->Get($WbemObjClassName);
|
|
|
|
my $Result = $WbemObject->SetProperty($ParameterName, $ParameterValue) unless !defined($ParameterName);
|
|
my $ProcessId = \0;
|
|
|
|
#~ $REALDEBUG and
|
|
#~ print $SEPARATOR , $WbemObject->Invoke("GetObjectText_"), $SEPARATOR;
|
|
#~ too much info here
|
|
|
|
my $ResultArrayRef = [(in $WbemObject->Invoke("Methods_"))];
|
|
|
|
$DEBUG and print STDERR
|
|
"$WbemObjClassName: METHODS_:\n";
|
|
|
|
$DEBUG and
|
|
map {&FormatDebugMsg($_->{"Name"}, $_->{"value"})} @$ResultArrayRef;
|
|
|
|
OLEerrmsg("undefined method: $MethodName") unless grep {/$MethodName/i}
|
|
map {$_->{"Name"}} @$ResultArrayRef;
|
|
|
|
defined $WbemObject or
|
|
OLEerrmsg("Could not create remote $WbemObjClassName");
|
|
|
|
# Now invoke the method
|
|
$DEBUG and
|
|
print STDERR $WbemObject->{CommandLine}, "\n";
|
|
OLEerrmsg("At $ComputerName, $ParameterName($ParameterValue) => $Result" )
|
|
if ($Result = $WbemObject->Invoke($MethodName,
|
|
$WbemObject->{CommandLine},
|
|
undef,
|
|
undef,
|
|
$ProcessId)); # ):- $ProcessId not filled up :-(
|
|
|
|
undef $WbemLocator;
|
|
undef $SWbemServices;
|
|
undef $WbemObject;
|
|
Win32::OLE->Uninitialize();
|
|
$DEBUG and print STDERR "OK\n";
|
|
|
|
0;
|
|
}
|
|
|
|
|
|
sub ExecQuery{
|
|
|
|
local ($ComputerName, $Query, $DisplayFields, $User, $Password) = @_;
|
|
# the "local" keyword is necessary to get search/replace able to do /e switch
|
|
|
|
my @MasterData = split (/\n/, $MasterData);
|
|
|
|
my %Caption = map {$_=> $_} @$DisplayFields;
|
|
|
|
# The values of %Caption must not be identical to the retrieved field names
|
|
|
|
my $Caption = \%Caption;
|
|
|
|
grep {s/\$\{?(\w+)\}?/${$1}/ge} @MasterData, $Query;
|
|
# here we replace all the vars with their values
|
|
|
|
$MasterData = join("", @MasterData);
|
|
|
|
$Query =~ s/([^\\])\\([^\\])/$1\\\\$2/g;
|
|
|
|
my $ResultSet = undef;
|
|
$DEBUG and print STDERR
|
|
"ExecQuery: using PROVIDER: ", $Provider, " " , $User, "\n";
|
|
my $WbemLocator = Win32::OLE->new($Provider);
|
|
|
|
OLEerrmsg("Could not instatiate $Provider") unless defined $WbemLocator;
|
|
|
|
my $SWbemServices = ($User =~ /\*/) ?
|
|
$WbemLocator->ConnectServer( $ComputerName, $NameSpace) :
|
|
$WbemLocator->ConnectServer( $ComputerName, $NameSpace, $User, $Password );
|
|
|
|
defined $SWbemServices or
|
|
OLEerrmsg("Cannot connect: $ComputerName, $NameSpace");
|
|
|
|
# Make sure we are using the appropriate security level
|
|
OLEerrmsg("Error setting security level")
|
|
if ( !($SWbemServices->{Security_}->{ImpersonationLevel} = 3) );
|
|
|
|
map {
|
|
$SWbemServices->{Security_}->{Privileges}->AddAsString($_)
|
|
or OLEerrmsg( "Error setting $hPrivileges->$_ privileges");
|
|
} keys %$hPrivileges;
|
|
|
|
$DEBUG and print STDERR
|
|
"\$Query: ", qq($Query), "\n";
|
|
###
|
|
### eval { $ResultSet = Win32::OLE->GetObject($MasterData)->ExecQuery($Query); };
|
|
### $DEBUG and $Query = ""
|
|
eval { $ResultSet = $SWbemServices->ExecQuery($Query); };
|
|
#
|
|
#
|
|
my $ResultArrayRef = [(in $ResultSet)] unless ($@);
|
|
|
|
$ResultArrayRef or
|
|
print STDERR "Win32::OLE::LastError ", Win32::OLE::LastError, "\n";
|
|
|
|
my @ResultCursor;
|
|
# pack ResultSet -> ResultCursor;
|
|
|
|
map {map {push @ResultCursor, {$Caption->{$_} => $ResultArrayRef->[0]->{$_}}}
|
|
@$DisplayFields and shift @$ResultArrayRef}
|
|
(0..$#$ResultArrayRef);
|
|
|
|
Win32::OLE->Uninitialize();
|
|
|
|
\@ResultCursor;
|
|
}
|
|
|
|
|
|
# &IsRunning($ProcMask, $runAtHost);
|
|
# lists processes on the host $runAtHost to
|
|
# find pattern $ProcMask.
|
|
# for all process found, collect the
|
|
# $1 of the search
|
|
# e.g. you get language of the running postbuiild with
|
|
# the pattern:
|
|
# "\\\\POSTBUILDSCRIPTS\\\\PBUILD\\\.CMD\\\"\\s\+\\\-l[: ]\(\\w\{3\}\)";
|
|
#
|
|
# plus some properties of the $ProcessSet
|
|
# return value: array pointer. The arguments are filtered out by default:
|
|
|
|
|
|
# (/S:\\BLD_WNXF1\RELEASE\GER\3562.X86FRE.MAIN.011002-1901\PRO /TEMPDRIVE:D /#T:7)
|
|
# PID= 00220
|
|
# NAME= winnt32.exe
|
|
# CMD= \\bld_wnxf1\release\ger\3562.x86fre.main.011002-1901\pro\i386\winnt32.exe /s:\\bld_wnxf1\release\ger\3562.x86fre.main.011002-1901\pro /tempdrive:d /#t:7
|
|
|
|
|
|
sub IsRunning{
|
|
|
|
my (
|
|
$WMIclass, $ProcMask, $Field, $Fields, $runAtHost) = @_;
|
|
|
|
# filter out arguments
|
|
$ProcMask = $ProcMask."\\\"\? \(\.\+\)\$" unless $ProcMask=~/\(/;
|
|
$DEBUG and print STDERR $ProcMask, "\n";
|
|
|
|
my $ProcessSet;
|
|
my @result;
|
|
my $Moniker = "winmgmts:{impersonationLevel=impersonate}!\\\\HOST\\root\\cimv2";
|
|
$Moniker =~ s/HOST/$runAtHost/;
|
|
|
|
$DEBUG and print STDERR
|
|
"using MONIKER: ", $Moniker, "\n";
|
|
eval {
|
|
$ProcessSet = Win32::OLE->GetObject($Moniker)->InstancesOf ($WMIclass); };
|
|
|
|
unless($@){
|
|
foreach my $ProcessInst (in $ProcessSet){
|
|
push @result, join("\n",
|
|
uc($1), map {"$_=".$ProcessInst->{$_}} @$Fields),
|
|
if $ProcessInst->{$Field} =~ m/$ProcMask/gi;
|
|
}
|
|
}else{
|
|
print STDERR Win32::OLE->LastError, "\n";
|
|
}
|
|
$DEBUG and print STDERR join ("\n", @result) , "\n";
|
|
\@result;
|
|
|
|
}
|
|
|
|
|
|
# supplyRegData
|
|
# usage:
|
|
# $defaultData = {
|
|
# "DEBUG" => $DEBUG,
|
|
# "Lang" => $Lang ,
|
|
# ...
|
|
# }
|
|
# $volatileData = {}
|
|
#
|
|
# &supplyRegData($sTargetcomputer, $REGISTRY_KEY,
|
|
# $defaultData, $volatileData , $FovWrite);
|
|
#
|
|
#
|
|
|
|
sub supplyRegData{
|
|
|
|
my ($sTargetcomputer, $sBootTestDataSubKey, $defaultData, $volatileData, $FovWrite) = @_;
|
|
use strict;
|
|
use Win32API::Registry 0.21 qw(HKEY_LOCAL_MACHINE
|
|
REG_OPTION_VOLATILE
|
|
REG_OPTION_NON_VOLATILE
|
|
KEY_ALL_ACCESS
|
|
KEY_READ
|
|
REG_SZ
|
|
regLastError
|
|
RegConnectRegistry
|
|
RegOpenKeyEx
|
|
RegEnumValue
|
|
RegQueryInfoKey
|
|
RegQueryValueEx
|
|
RegCreateKeyEx
|
|
RegSetValueEx
|
|
RegDeleteValue
|
|
RegCloseKey
|
|
);
|
|
|
|
# This provides fairly low-level access to the Win32 System API calls
|
|
# dealing with the Registry [mostly from WINREG.H]. This is mostly
|
|
|
|
|
|
|
|
my $hRootKey = $sRootKey;
|
|
|
|
{ no strict 'refs';
|
|
$hRootKey =~ s/(\w+)/$1/eeg;
|
|
use strict 'refs';
|
|
}
|
|
|
|
my $sStatusSubKey = "STATUS";
|
|
my $ohKey = undef;
|
|
my $ohSubKey = undef;
|
|
my $ohStatusSubKey = undef;
|
|
my $ocValues;
|
|
my $olValName;
|
|
my $olValData;
|
|
my $olSecDesc;
|
|
my $opValData;
|
|
my $osValName;
|
|
my $sValueNames = [];
|
|
my $sValueName;
|
|
my $nStatus = undef;
|
|
|
|
$DEBUG and print STDERR
|
|
"COMPUTER: ".uc($sTargetcomputer)."\n";
|
|
|
|
&RegConnectRegistry( $sTargetcomputer,
|
|
$hRootKey,
|
|
$ohKey )
|
|
or die "Can't open $hRootKey: ", regLastError(),"\n";
|
|
|
|
|
|
$DEBUG and print STDERR
|
|
"Registry Key: ".$sRootKey."\\$sBootTestDataSubKey\n";
|
|
|
|
|
|
|
|
$nStatus = &RegOpenKeyEx( $ohKey,
|
|
$sBootTestDataSubKey ."\\". $sStatusSubKey,
|
|
0,
|
|
KEY_READ,
|
|
$ohStatusSubKey );
|
|
if (scalar(keys(%$volatileData))){
|
|
$sValueName = (keys(%$volatileData))[0];
|
|
$opValData = undef;
|
|
if ($nStatus){
|
|
|
|
&RegQueryValueEx( $ohStatusSubKey,
|
|
$sValueName ,
|
|
[],
|
|
[],
|
|
$opValData,
|
|
[] );
|
|
# error is ignored.
|
|
$opValData = "(undef)" unless $opValData;
|
|
|
|
&RegCloseKey($ohStatusSubKey);
|
|
|
|
}
|
|
|
|
if ($nStatus ){
|
|
$DEBUG and print STDERR
|
|
"\\\\$sTargetcomputer\\$sRootKey\\$sBootTestDataSubKey\\$sStatusSubKey\\$sValueName: ",$opValData, "\n";
|
|
$FovWrite or return 1;
|
|
}
|
|
}
|
|
|
|
RegCreateKeyEx($ohKey,
|
|
$sBootTestDataSubKey,
|
|
0,
|
|
"",
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
[],
|
|
$ohSubKey,
|
|
[]);
|
|
|
|
RegCloseKey($ohSubKey);
|
|
|
|
&RegOpenKeyEx( $ohKey,
|
|
$sBootTestDataSubKey ,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
$ohSubKey )
|
|
or die "Can't open $sBootTestDataSubKey: \n", regLastError(),"\n";
|
|
|
|
&RegQueryInfoKey($ohSubKey,
|
|
[],
|
|
[],
|
|
[],
|
|
[],
|
|
[],
|
|
[],
|
|
$ocValues,
|
|
$olValName,
|
|
$olValData,
|
|
[],
|
|
[]
|
|
)
|
|
or die "Can't query $sBootTestDataSubKey: ", regLastError(),"\n";
|
|
|
|
$DEBUG and print STDERR
|
|
$ocValues, " values found\n";
|
|
|
|
foreach my $Data (keys(%$defaultData)){
|
|
if ($FovWrite){
|
|
# tsanders: existing values do not get overwritten.
|
|
|
|
&RegDeleteValue($ohSubKey,
|
|
$Data);
|
|
$DEBUG and print STDERR
|
|
"\t\tDeleting Default Data: \"$Data\"\n\t\t$^E\n";
|
|
#ignore the "$^E" here.
|
|
}
|
|
&RegSetValueEx($ohSubKey,
|
|
$Data,
|
|
0,
|
|
REG_SZ,
|
|
$defaultData->{$Data},
|
|
0
|
|
)
|
|
or die "Can't RegSetValueEx($Data,...$defaultData->{$Data}: ", regLastError(),"\n";
|
|
}
|
|
|
|
foreach my $nCnt (0..$ocValues-1){
|
|
&RegEnumValue($ohSubKey,
|
|
$nCnt,
|
|
$osValName,
|
|
0,
|
|
[],
|
|
[],
|
|
$opValData,
|
|
0 );
|
|
push @$sValueNames, $osValName;
|
|
|
|
}
|
|
|
|
foreach $sValueName (@$sValueNames){
|
|
&RegQueryValueEx( $ohSubKey,
|
|
$sValueName ,
|
|
[],
|
|
[],
|
|
$opValData,
|
|
[] )
|
|
or die "Can't read $sValueName: ", regLastError(),"\n";
|
|
|
|
$DEBUG and print STDERR
|
|
"$sValueName=$opValData\n";
|
|
|
|
}
|
|
|
|
|
|
RegCreateKeyEx($ohSubKey,
|
|
$sStatusSubKey,
|
|
0,
|
|
"",
|
|
REG_OPTION_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
[],
|
|
$ohStatusSubKey,
|
|
[]);
|
|
|
|
|
|
foreach my $Data (keys(%$volatileData)){
|
|
&RegSetValueEx($ohStatusSubKey,
|
|
$Data,
|
|
0,
|
|
REG_SZ,
|
|
$volatileData->{$Data},
|
|
0
|
|
)
|
|
or die "Can't RegSetValueEx($Data,...$volatileData->{$Data}: ",
|
|
regLastError(),"\n";
|
|
}
|
|
map {defined($_) and RegCloseKey($_)} ($ohSubKey, $ohKey, $ohStatusSubKey);
|
|
|
|
0;
|
|
}
|
|
|
|
sub OLEerrmsg($)
|
|
{
|
|
my $text = shift;
|
|
errmsg( "$text (". Win32::OLE->LastError(). ")" );
|
|
exit 1;
|
|
}
|
|
|
|
|
|
sub ScheduleTime{
|
|
|
|
use Time::localtime;
|
|
|
|
my $shiftTime = shift;
|
|
|
|
my $tNow = time();
|
|
|
|
$DEBUG and print STDERR
|
|
"Current time: " , &localtime->hour(), ":", &localtime->min(), "\n";
|
|
|
|
$tNow += $shiftTime;
|
|
|
|
my @result = map {sprintf("%02d", $_)} (&localtime($tNow)-> hour(),
|
|
&localtime($tNow)-> min(),
|
|
&localtime($tNow)-> sec(),
|
|
&localtime($tNow)-> mon() + 1,
|
|
&localtime($tNow)-> mday(),
|
|
&localtime($tNow)-> year() + 1900
|
|
);
|
|
|
|
$DEBUG and print STDERR
|
|
"Schedule time: " , $result[0], ":",
|
|
$result[1], ":",
|
|
$result[2], " ",
|
|
$result[3], "/",
|
|
$result[4], "/",
|
|
$result[5], "\n";
|
|
|
|
\@result;
|
|
}
|
|
|
|
|
|
|
|
|
|
sub FormatDebugMsg{
|
|
|
|
format STDERR =
|
|
# field name field value
|
|
@<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
$_[0] $_[1]
|
|
.
|
|
|
|
write STDERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# BackTick
|
|
# sample usage: &BackTick("dir");
|
|
# &BackTick(<<BLOCKBOUNDARY);
|
|
# ...cmd code...
|
|
# BLOCKBOUNDARY
|
|
# passes block of code to the cmd interpreter.
|
|
# lines are concatenated
|
|
# comments thrown away
|
|
# useful stuff when the code is already
|
|
# developed and just needs to be inserted in place
|
|
# has limitations.
|
|
|
|
sub BackTick{
|
|
my ($cmd) = @_;
|
|
my $res = undef;
|
|
$DEBUG and
|
|
print STDERR join(" &", grep (!/^:|REM/i, ($cmd =~ /^(.+)/gm)));
|
|
$cmd = join(" &", grep (!/^:|REM/i, ($cmd =~ /^(.+)/gm)));
|
|
$res=qx ($cmd);
|
|
$res;
|
|
}
|
|
|
|
|
|
|
|
sub pPpPinfo{
|
|
|
|
my @infa = @_;
|
|
my $opBrws = Win32::OLE->new("WScript.Shell");
|
|
$opBrws->Popup(join("\n", @infa), $TIMEOUT ,
|
|
ref($opBrws) . "<- $0,". $VERSION,
|
|
0 + 64);
|
|
undef($opBrws);
|
|
Win32::OLE->FreeUnusedLibraries();
|
|
Win32::OLE->Uninitialize();
|
|
1;
|
|
}
|
|
|
|
1;
|
|
__END__
|
|
#-------------------------------------------------------------//
|
|
|
|
=head1 NAME
|
|
|
|
B<WMIFE> - Interface the query engine exposed by WMI
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use WMIFE;
|
|
|
|
&WMIFE::ExecQuery($ComputerName, $Query, [@Fields]);
|
|
&WMIFE::FormatDebugMsg($Comment, $Field);
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
Generates the WQL (A.K.A. WMI SQL) query on the remote machine against
|
|
its namespace.
|
|
|
|
Sample objects that reside on the remote box $ComputerName are:
|
|
|
|
* local files [/.//ROOT/CIMV2/CIM_DATAFILE],
|
|
* running processes [/.//ROOT/CIMV2/WIN32_PROCESSES],
|
|
* registry entries [/.//ROOT/DEFAULT/STDREGPROV].
|
|
|
|
The WMI is functional even in the absence of logon sessions on $ComputerName.
|
|
|
|
=head1 METHODS
|
|
|
|
=head2 FormatDebugMsg($fieldName, $FieldValue)
|
|
|
|
Nice (?) formatting of the RDB like table field output (A.K.A. browse view):
|
|
|
|
Name perl.exe
|
|
Description perl.exe
|
|
ProcessID 2920
|
|
ParentProce 2692
|
|
ExecutableP d:\ntt\tools\perl\bin\perl.exe
|
|
...
|
|
|
|
|
|
=head2 ExecQuery($ComputerName, $Query, $DisplayFields)
|
|
|
|
Execute the WMI WQL query against the namespace of the remote machine
|
|
where
|
|
$ComputerName is the name of the machine which namespaces are about to be queried.
|
|
$Query the string representing the query, with the dollarsigned names placeholders for parameters
|
|
$DisplayFields reference to the field list to retusn the result
|
|
|
|
The return value is a reference to the like the RDB cursor.
|
|
(array of hashes where keys are described in $DisplayFields array).
|
|
If no data is returned from the query the returned value is a reference to undefined value.
|
|
|
|
=head2 ObjectExecMethod($MethodName, $ComputerName, $ParameterName, $ParameterValue, $User, $Password
|
|
|
|
Access the namespace on the remote box $ComputerName, and execute the method $MethodName of the class
|
|
$WbemObjClassName (currently only for Win32_Process). Supply the parameter(s) via name/value.
|
|
PErfurm the call under $User account, proving the password.
|
|
|
|
=head2 Sample calls:
|
|
|
|
|
|
=head2 To list files in the root directory of the logical disk labeled $Drive of the machine $Machine
|
|
|
|
$Results = &WMIFE::ExecQuery($Machine,
|
|
qq(SELECT * FROM cim_Datafile WHERE Drive="$Drive" AND Path="\\\\" "),
|
|
[qw(Drive Path Name)]);
|
|
|
|
|
|
=head2 To list logical disks of the machine $Machine
|
|
|
|
$Results = &WMIFE::ExecQuery($Machine,
|
|
qq(SELECT * FROM Win32_LogicalDisk WHERE DriveType=3),
|
|
[qw(Name Description)]);
|
|
|
|
=head2 To list the running processes
|
|
|
|
$Results = &WMIFE::ExecQuery($ComputerName,
|
|
qq(SELECT * FROM Win32_Process),
|
|
[qw(Name Description ProcessID ParentProcessId ExecutablePath )]);
|
|
|
|
|
|
|
|
|
|
=head2 To view installed software
|
|
|
|
$Results = &WMIFE::ExecQuery($ComputerName,
|
|
qq(SELECT * FROM Win32_Product),
|
|
[qw(Name Vendor Version)]);
|
|
|
|
|
|
=head2 To verify administrators group
|
|
|
|
$Results = &WMIFE::ExecQuery($ComputerName,
|
|
qq(SELECT * FROM Win32_GroupUser WHERE GroupComponent="Win32_Group.Domain=\\"$ComputerName\\",Name=\\"Administrators\\""),
|
|
[qw(GroupComponent)]);
|
|
|
|
|
|
=head2 To browse the process dependency hierarchy
|
|
$Results = &WMIFE::ExecQuery($ComputerName,
|
|
qq(SELECT * FROM CIM_ProcessExecutable),
|
|
[qw(Antecedent Dependent)]);
|
|
|
|
|
|
=head2 Query who is currently logged to somewhere.
|
|
|
|
|
|
$Results =
|
|
&WMIFE::ExecQuery($ENV{"COMPUTERNAME"}, # interactive session
|
|
qq(SELECT * FROM Win32_LogonSession WHERE LogonType=2),
|
|
[qw(LogonId LogonType)]);
|
|
|
|
foreach my $Result (@$Results){
|
|
|
|
$DEBUG and
|
|
map {&WMIFE::FormatDebugMsg($_, $Result->{$_})} keys (%$Result);
|
|
|
|
push @Ids, $Result->{"LogonId"};
|
|
|
|
}
|
|
|
|
|
|
$Results =
|
|
&WMIFE::ExecQuery($ENV{"COMPUTERNAME"}, # Difficult to build the WHERE condition.
|
|
qq(SELECT * FROM Win32_LoggedOnUser),
|
|
[qw(Antecedent Dependent)]);
|
|
my @Users = ();
|
|
my $User = undef;
|
|
my $LoggedUser = undef;
|
|
my @LoggedUsers = ();
|
|
|
|
# a little bit ugly.
|
|
|
|
foreach my $Id (grep {/\d+/} @Ids){
|
|
|
|
foreach my $Result (@$Results){
|
|
|
|
$User = $Result->{"Antecedent"};
|
|
if ($User =~ /\S/){
|
|
push @Users, $User;
|
|
}
|
|
|
|
if ((grep {/\b$Id\b/} $Result->{"Dependent"})){
|
|
$LoggedUser = pop @Users;
|
|
push @LoggedUsers, $LoggedUser;
|
|
$DEBUG and &WMIFE::FormatDebugMsg("win32_user", $LoggedUser);
|
|
$DEBUG and &WMIFE::FormatDebugMsg("win32_logonSession", $Id);
|
|
}
|
|
}
|
|
}
|
|
|
|
map {($user, $domain) = (/Win32_Account.Domain=\"(\w+)\",Name=\"(\w+)\"/);
|
|
$DEBUG and
|
|
print $user, "\t" , $domain,"\n"; } @LoggedUsers;
|
|
|
|
|
|
|
|
=head2 To list the $Result contents, the following framework may be used:
|
|
|
|
use WMIFE;
|
|
|
|
&WMIFE::ExecQuery($ENV{"COMPUTERNAME"},
|
|
qq(SELECT * FROM Win32_BootConfiguration),
|
|
[qw(Caption BootDirectory Description)]);
|
|
|
|
foreach my $Result (@$Results){
|
|
map {&WMIFE::FormatDebugMsg($_, $Result->{$_})} keys (%$Result);
|
|
}
|
|
|
|
|
|
|
|
=head2 To design the new query
|
|
|
|
please use the %WINDIR%\SYSTEM32\WBEM\wbemtest.exe vendor shell for accessing and
|
|
querying the WMI classes and then use the query string designed in that shell as an argument to the Perl qq()
|
|
[double backslashes]
|
|
|
|
Some queries may take long time to execute, before being sufficiently refined.
|
|
|
|
=head1 SEE ALSO
|
|
|
|
Whole bunch of tools interfacing WMI is in progress. Note that the Perl interface to WMI is not as powerful as
|
|
VBSCRIPT/JSCRIPT since there is no working examples for P/P (A.K.A. object sinking) and in general any
|
|
interface(s) other than SQL. the design of such sample code might prove to be complicated indeed.
|
|
|
|
|
|
=head2 supplyRegData($sTargetcomputer, $Lang, $BldNum, $Sku, $Drive, $BuildName, $Unattend, $FovWrite)
|
|
|
|
Write the data to the REGISTRY of the Boot test machine to start the execution
|
|
of test build installation.
|
|
|
|
The REGISTRY path where the data is stored is:
|
|
|
|
HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\BOOTTEST
|
|
|
|
The data includes the following fields:
|
|
|
|
-------------+-----------------------------------------------------------
|
|
$Lang | fields are used to find the test bits, in the form:
|
|
$BuildName | $Drive\$Lang\$BuildName
|
|
$BldNum | $BldNum, $Sku and $Lang are used to verify the
|
|
$Sku | REGISTRY data is actual for the build being installed.
|
|
$Drive | target drive for winnt32.exe
|
|
$Unattend | location of the answer file
|
|
|
|
The data is written by the postbuild on the build machine (NTDEV\NTBUILD),
|
|
and is later consumed from boot machine side by (NTDEV\<AUTOGENERATED> user).
|
|
The registry access across the network hence the use of HKEY_LOCAL_MACHINE.
|
|
The default REGISTRY key names are:
|
|
|
|
HKLM\SOFTWARE\MICROSOFT\BOOTTEST\_BldNum => $BldNum
|
|
HKLM\SOFTWARE\MICROSOFT\BOOTTEST\_BuildArch => $_BuildArch
|
|
HKLM\SOFTWARE\MICROSOFT\BOOTTEST\LANG => $Lang
|
|
HKLM\SOFTWARE\MICROSOFT\BOOTTEST\_BldSku => $Sku
|
|
HKLM\SOFTWARE\MICROSOFT\BOOTTEST\_BuildType => $_BuildType
|
|
HKLM\SOFTWARE\MICROSOFT\BOOTTEST\_BldDrive => $Drive
|
|
HKLM\SOFTWARE\MICROSOFT\BOOTTEST\Unattend => $Unattend
|
|
HKLM\SOFTWARE\MICROSOFT\BOOTTEST\_BldName => $BuildName
|
|
|
|
Running regedit.exe will show the following data:
|
|
|
|
+-----------------------------------------------
|
|
|Windows Registry Editor Version 5.00
|
|
|
|
|
|[HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\BOOTTEST]
|
|
|"_BuildArch"="x86"
|
|
|"_BuildType"="fre"
|
|
|"_BldSku"="SRV"
|
|
|"_BldName"="3615.x86fre.main.020306-1639"
|
|
|"_BldDrive"="D"
|
|
|"Unattend"="unattend.txt"
|
|
|"LANG"="GER"
|
|
|"_BldNum"="3615"
|
|
|
|
|
|[HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\BOOTTEST\Status]
|
|
|"COMPUTERNAME"="BLD_WNXF1"
|
|
+-----------------------------------------------
|
|
|
|
|
|
The Status subkey is to prevent concurrent execution of the more than one
|
|
test build install on the single test machine. The function will return
|
|
the data observed e.g.
|
|
\\sergueik4\HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\BOOTTEST\STATUS\COMPUTERNAME: SERGUEIK2
|
|
|
|
To ignore the presence of the Status set $FovWrite = 1.
|
|
Booting test machine (but not logging off of the user) will cause Status
|
|
key to disappear.
|
|
|
|
=head2 &ScheduleTime($Delay)
|
|
|
|
Calculate the time/date for execution of the scheduled tasks in
|
|
$Delay secs from NOW.
|
|
Example usage:
|
|
|
|
use WMIFE;
|
|
$WMIFE::DEBUG = 1;
|
|
my $DELAY1 = 1800; # delay in 1800 secs = 30 min
|
|
my $string = "/st %HH%:%MM%:%SS% /sd %mm%/%dd%/%yyyy%" ;
|
|
|
|
my $marker = ["HH" , "MM", "SS", "mm", "dd", "yyyy"];
|
|
# this is the way to set the date/time of scheduled task
|
|
my $ScheduleTime = &WMIFE::ScheduleTime($DELAY1);
|
|
print STDERR "\"$string\"\t";
|
|
map {$string =~ s/\%$marker->[$_]\%/$ScheduleTime->[$_]/g;}
|
|
(0..$#$marker);
|
|
print STDERR "\"$string\"\n";
|
|
|
|
|
|
Current time: 15:51
|
|
Schedule time: 16:21:32 03/25/2002
|
|
"/st %HH%:%MM%:%SS% /sd %mm%/%dd%/%yyyy%"
|
|
"/st 16:21:32 /sd 03/25/2002"
|
|
|
|
=head1 AUTHOR
|
|
Serguei Kouzmine sergueik@microsoft.com
|
|
|
|
=cut
|
|
1;
|