package DBD::WMI; use strict; use parent 'DBD::File'; use DBI; our $ATTRIBUTION = 'DBD::WMI by Max Maischein '; our $VERSION = '0.11'; =head1 NAME DBD::WMI - interface to the Windows WMI =head1 ABSTRACT This module allows you to issue WQL queries through the DBI. =head1 SYNOPSIS use DBI; my $dbh = DBI->connect('dbi:WMI:'); my $sth = $dbh->prepare(<execute(); while (my @row = $sth->fetchrow) { my $proc = $row[0]; print join "\t", $proc->{Caption}, $proc->{ExecutablePath} || ""; # $proc->Terminate(); print "\n"; } The WMI allows you to query various tables ("namespaces"), like the filesystem, currently active processes and events: SELECT * FROM Win32_Process The driver/WMI implements two kinds of queries, finite queries like the query above and potentially infinite queries for events as they occur in the system: my $query = q{ SELECT * FROM __instanceoperationevent WITHIN 1 WHERE TargetInstance ISA 'Win32_DiskDrive' } This query returns one row (via ->fetchrow_arrayref() ) whenever a disk drive gets added to or removed from the system (think of an USB stick). There is currently no support for selecting specific columns instead of C<*>. Support for selecting columns that then get returned as plain Perl scalars is planned. =cut # Investigate System.Management.MethodData to get at the methods and properties my $drh; sub driver { return $drh if $drh; my ($package,$attr) = @_; $package .= "::dr"; $drh = DBI::_new_drh( $package, { Attribution => $ATTRIBUTION, Version => $VERSION, Name => 'WMI', }, ); $drh }; package DBD::WMI::dr; use strict; use Win32::WQL; our $imp_data_size = 0; sub connect { my ($drh, $dr_dsn, $user, $auth, $attr) = @_; $dr_dsn ||= "."; $dr_dsn =~ /^([^;]*)/i or die "Invalid DSN '$dr_dsn'"; my $machine = $1 || "."; my @args; if ( defined $user and $user ne '') { my $locator = Win32::OLE->new("WbemScripting.SWbemLocator"); my $ole_con=$locator->ConnectServer($machine,'root/cimV2',$user,$auth); @args = $ole_con; } else { @args = (machine => $machine); } my $wmi = Win32::WQL->new(@args); my ($outer, $dbh) = DBI::_new_dbh( $drh, { Name => $dr_dsn }, ); $dbh->{wmi_wmi} = $wmi; #$dbh->STORE('Active',1); $outer } sub data_sources { my ($drh) = @_; my $wmi = Win32::WQL->new(); my $sth = $wmi->prepare(<execute(); my @res; while (my $ev = $sources->fetchrow()) { push @res, $ev->Path_->Class }; @res } package DBD::WMI::db; use strict; our $imp_data_size = 0; sub prepare { my ($dbh, $statement, @attribs) = @_; my $own_sth = $dbh->{wmi_wmi}->prepare($statement); my ($outer, $sth) = DBI::_new_sth($dbh, { Statement => $statement, wmi_sth => $own_sth, wmi_params => [], }, ); my $columns = __PACKAGE__->parse_columns($statement); $sth->STORE('wmi_return_columns', $columns); $sth->STORE('NUM_OF_PARAMS', ($statement =~ tr/?//)); return $outer; } =head2 C<< DBD::WMI::db::parse_columns STATEMENT >> This routine parses out the requested columns from the WQL statement and returns an array reference with the names of the columns. Currently, this only works for C and the values of the object properties when columns are specified. These columns are then case sensitive. =head1 FUN QUERIES =head2 List all printers SELECT * FROM Win32_Printer =head2 List all print jobs on a printer SELECT * FROM Win32_PrintJob WHERE DriverName = 'HP Deskjet 6122' =head2 Return a new row whenever a new print job is started SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_PrintJob' =head2 Finding the default printer SELECT * FROM Win32_Printer WHERE Default = TRUE =head2 Setting the default printer (untested, WinXP, Win2003) use DBI; my $dbh = DBI->connect('dbi:WMI:'); my $sth = $dbh->prepare(<execute; while (my @row = $sth->fetchrow) { # We get Win32::OLE objects back: my $printer = $row[0]; printf "Making %s the default printer\n", $printer->{Name}; $printer->SetDefaultPrinter; }; =head2 Find all network adapters with IP enabled SELECT * from Win32_NetworkAdapterConfiguration WHERE IPEnabled = True =head2 Find files in a directory ASSOCIATORS OF {Win32_Directory.Name='C:\WINNT'} WHERE ResultClass = CIM_DataFile =head2 Find printers on a remote machine use DBI; my $machine = 'dawn'; my $dbh = DBI->connect('dbi:WMI:'.$machine); my $sth = $dbh->prepare(<execute; while (my @row = $sth->fetchrow) { my $printer = $row[0]; printf "Making %s the default printer on %s\n", $printer->{Name}, $machine; $printer->SetDefaultPrinter; }; =head2 Get method names of objects use Win32::OLE qw(in); ... SELECT * FROM Win32_Process $sth->execute; while (my @row = $sth->fetchrow) { for my $method (in $row[0]->Methods_) { print "Can call $method() on the object\n" }; }; =head1 TODO =over 4 =item * Implement placeholders and proper interpolation of values =item * Need to implement DSN parameters for remote computers, credentials =back =head1 SEE ALSO WMI is Microsofts implementation of the WBEM standard (L) except that it uses DCOM and not CIM-XML as the transport medium. The MS WMI main page at L The WQL documentation at L The "Hey Scripting Guy" column at L Wikipedia on WMI at L List of available Win32 WMI classes at L =head1 REPOSITORY The public repository of this module is L. =head1 SUPPORT The public support forum of this module is L. =head1 BUG TRACKER Please report bugs in this module via the RT CPAN bug queue at L or via mail to L. =head1 AUTHOR Max Maischein C =head1 COPYRIGHT (c) Copyright 2009-2018 by Max Maischein C. =head1 LICENSE This module is released under the same terms as Perl itself. =cut