Subscribe to Windows IT Pro
February 26, 2001 12:00 AM

Progressive Perl for Windows: Using WMI to Request Data About Disk Drives

Windows IT Pro
InstantDoc ID #19828
Rating: (0)
Downloads
19828.zip

Step 4
The last step is to use the Win32::OLE->in() function to enumerate the class instances. This function returns an array that contains each class instance found in the COM collection object. You might recall that you imported the in() function in Step 1. Because you imported the function at that time, you can simply refer to the function as in() in this step.

You pass the in() function the collection of instances ($DriveCollection), as Listing 1 shows. With each iteration of the foreach loop, the $Drive variable contains a COM-based instance of the Win32_DiskDrive class. In this case, you're just enumerating the drives, but you can query properties and call methods on $Drive as you would any other COM object.

These four steps provide a script with disk-drive information from a remote machine. Let's now look at a real-world example of how you can use the Win32_DiskDrive class in a script.

A Practical Example
Listing 2 contains a real-world script called WDiskDrives.pl. The Win32_DiskDrive class doesn't contain any writable properties or methods. Thus, WDiskDrives.pl explores the target machine's disk drives by querying 7 of the class's 48 properties:

  • Capabilities (returns a list of the drive's capabilities)

  • InterfaceType (returns the type of interface the drive uses, such as SCSI or IDE)

  • MediaType (returns the type of media that the drive uses)

  • Model (returns the drive's model number)

  • Name (returns the OS's physical path to the drive)

  • Partitions (returns the number of partitions on the drive)

  • Size (returns the drive's size in bytes)

Let's begin exploring WDiskDrives.pl by finding the four steps just discussed. In Listing 2, callouts A, B, C, and D highlight the code for Steps 1, 2, 3, and 4, respectively.

The code between callouts A and B in Listing 2 prepare the script for querying. For example, the portion of the code that starts with

my @CAPABILITIES =

defines the friendly names of the possible values that the Capabilities property returns, and the line

my $TotalSize = 0;

initializes the $TotalSize variable. The code

my $Machine = shift @ARGV || ".";

tells the script to accept a machine name that the user passes in through the command line; if a user doesn't pass in a machine name, the script defaults to the local machine (which the period specifies). Finally, the line

$Machine =~ s/^[\\\/]+//;

removes any forward slashes or backslashes that might be in the machine name. This removal prevents an error if the user specifies a machine such as \\MyMachine.

The code at callout D in Listing 2 queries each instance of the Win32_DiskDrive class for the six properties. The Capabilities property is the most interesting. It returns a COM object that contains an array of strings. However, if the array is empty, the property doesn't return a COM object. Instead, the code

my $CapabilityList = $Drive->{Capabilities} || [];

assigns an empty anonymous array to the $CapabilityList variable to prevent an error. Note that the next line

foreach my $Cap ( @{$CapabilityList} )

casts $CapabilityList as an array. If $CapabilityList is an empty anonymous array, casting it as an array simply dereferences it. If $CapabilityList is a COM array object, the object's list of properties is returned as a Perl array reference. Either way, the result is an array.

To use WDiskDrives.pl, you need to have WMI installed. Win2K and Windows Millennium Edition (Windows Me) come with WMI. For earlier platforms (Windows NT 4.0 and Windows 9x), you can download the WMI service from http://msdn.microsoft.com/downloads/c-frame.htm?/downloads/sdks/wmi/default.asp and install it.

To run WDiskDrives.pl on the local machine, use the command

perl WDiskDrives.pl

If you want to run the script on a remote machine called \\MyMachine, use the command

perl WDiskDrives.pl MyMachine

Another approach is to specify the IP address of \\MyMachine instead of MyMachine in that command.

Give WMI a Test Drive
If you were unfamiliar with WMI before you read this column, you might be thinking, "WMI can do all that?" Indeed, it can—and I've only shown you the tip of the proverbial iceberg. Next month, I'll show you more uses for WMI. Until then, give WMI a test drive. You might be surprised at what information it can provide.

Related Content:

ARTICLE TOOLS

Comments
  • Anonymous User
    7 years ago
    Feb 20, 2005

    no comment

  • Rahul Bhiide
    8 years ago
    Jun 24, 2004

    We can find the drives on a machine using Win32_LogicalDisk and can find target lun bus numbers using Win32_DiskDrive . but how to find the mapping between the drive letters and targets/lun/bus .

  • Dave Roth
    10 years ago
    Aug 23, 2002

    You can use the ExecQuery() method off of the WMI Services script object to solve this. The query is very similar to SQL and would allow you to specify that you want all Win32_LogicalDisk instances where the DeviceID is greater than or equal to "C:". You could make more sophisticated queries such as collect all instances between drives D: and L:, if you like. Try this Perl code:




    use strict;

    use Win32::OLE qw( in );

    $Machine = ".";

    my $WMIServices = Win32::OLE->GetObject

    ( "winmgmts:{impersonationLevel=impersonate,

    (security)}//$Machine/root/cimv2" ) || die;

    my $DriveCollection = $WMIServices->ExecQuery

    ( 'select * from Win32_LogicalDisk where

    DeviceID >= "C:"' ) || die "Query Failed";

    foreach my $Drive ( in( $DriveCollection ) )

    {

    my $FreePercent = int( ( $Drive->{FreeSpace} / $Drive->{Size} ) * 100 );

    print "$Drive->{DeviceID}\\n";

    print "\\tVolume: $Drive->{VolumeName}\\n";

    print "\\tDisk Size: " . FormatNumber( $Drive->{Size} ) . "\\n";

    print "\\tAvailable: " . FormatNumber( $Drive->{FreeSpace} ) . "

    ($FreePercent%)\\n";

    print "\\n";

    }



    sub FormatNumber

    {

    my($Number) = @_;

    my $Suffix = "";

    if( $Number > 1024 * 1024 * 1024 )

    {

    $Number /= (1024 * 1024 * 1024);

    $Suffix = "G";

    }

    elsif( $Number > 1024 * 1024 )

    {

    $Number /= (1024 * 1024);

    $Suffix = "M";

    }

    elsif( $Number > 1024 )

    {

    $Number /= 1024;

    $Suffix = "K";

    }

    $Number = sprintf( "%0.2f", $Number );

    while( $Number =~ s/^(-?\\d+)(\\d{3})/$1,$2/ ){};

    return( $Number . $Suffix );

    }



  • Sanjeev Shukla
    10 years ago
    Jun 17, 2002

    I am using WMI with Perl, but whenever I access the logical disks using Logical_disk class, the script scans the floppy drives as well. I am trying to find a way so that I can get data only about logical disk without scanning floppy drives every time script runs (as this may damage floppy drives on the server, if I run the script very frequently).

You must log on before posting a comment.

Are you a new visitor? Register Here

advertisement

advertisement

Windows is a trademark of the Microsoft group of companies. Windows IT Pro is used by Penton Media Inc. under license from owner.