O'Reilly    
 Published on O'Reilly (http://oreilly.com/)
 See this if you're having trouble printing code examples


The Two-Minute VBScript-to-Perl Tutorial - Automating System Administration with Perl

by David N. Blank-Edelman

Heresy to talk about VBScript in a book largely focused on Perl tools? Perhaps, but if you put down the pitchfork for a second, I’ll explain why it is useful to spend two minutes learning a little VBScript. The following rationale assumes you have some familiarity with machines running Windows-based operating systems. If you’ve never had any contact with Windows machines, and never expect to, please skip to the next appendix. The rest of you, follow me.

System Administration with Perl, Second Edition book cover

This excerpt is from Automating System Administration with Perl, Second Edition . Thoroughly updated and expanded in its second edition to cover the latest operating systems, technologies, and Perl modules, Automating System Administration with Perl will help you perform your job with less effort. The second edition not only offers you the right tools for your job, but also suggests the best way to approach particular problems and securely automate pressing tasks.

buy button

It may border on the tautological to say this, but Microsoft expects administrators to automate their tasks using Microsoft technologies. Perl has been shoehorned into this realm largely thanks to the efforts of Jan Dubois and the other contributors to the Win32::OLE module. This module gives us a way to communicate with other parts of the Microsoft software universe on an almost equal footing with Microsoft scripting languages like VBScript.

Win32::OLE makes communication possible, but it doesn’t always make it easy. Perl doesn’t share the same DWMM (Do What Microsoft Means) language idioms as VBScript, so it’s not always clear how an apparently simple piece of VBScript code that performs some behind-the-scenes magic for the programmer can be translated. This difficulty is compounded by the lack of reference and teaching material written in our native language. Barring a few notable exceptions, like David Roth’s books, the vast majority of the material on Windows scripting is written using VBScript as its implementation language. For example, Microsoft’s excellent Script Center website (based on the equally good Windows 2000 Scripting Guide) would be a perfect reference for us, except that it’s all in icky VBScript.

I’m not a VBScript programmer, nor do I expect you to be one. You won’t even be able to fake it by the end of this appendix. Luckily, you don’t have to know very much about VBScript or even Win32 programming to be able to convert simple VBScripts to Perl using Win32::OLE. This appendix will give you some basic translation hints and demonstrate how they are put into practice on a few of the real scripts posted at Microsoft’s Script Center.

Translation Tactics

The first four tactics that I want to show you can be illustrated by a step-by-step translation of the following simple VBScript:

' Lists all the members of the Managers group in fabrikam.com

Set objGroup = GetObject _
("LDAP://cn=managers,ou=management,dc=fabrikam,dc=com")
For each objMember in objGroup.Members
Wscript.Echo objMember.Name
Next

We’ll look at a few more sample scripts later, but for now let’s see about translating this one into a more palatable language.[144]

Tactic 1: Loading Your Modules

All translated programs begin by loading the Win32::OLE module:

use Win32::OLE;

If you think you are going to be using container and contained objects,[145] you’ll want to either import the in primitive or load Win32::OLE::Enum:

# 'in' is another way to say Win32::OLE::Enum->All()
use Win32::OLE qw(in);
       # or
use Win32::OLE;
use Win32::OLE::Enum;

It can also be helpful to load Win32::OLE::Const and use it to import constants from an application or OS library for use in your programs. We’ll see an example of this later in this appendix.

There are other primitives, such as with and valof, that you might also want to consider importing if you are translating more sophisticated scripts. However, using them typically requires more in-depth knowledge of Windows programming principles. See the Win32::OLE doc for more info on these primitives and their usage.

Tactic 2: Referencing an Object

The translation is straightforward:

my $objGroup =
     Win32::OLE->

       GetObject('LDAP://cn=managers,ou=management,dc=fabrikam,dc=com');

To make the mapping between the VBScript and the Perl as easy as possible, we’ll retain the VBScript variable names, mixed case and all.

Tactic 3: Accessing Object Properties Using the Hash Dereference Syntax

VBScript uses the dot (.) character to access an object’s properties (or attributes, in LDAP or OOP parlance). The Perl equivalent[146] is the hash dereference syntax (i.e., $object->{property}).

So, this VBScript code:

objGroup.Members

becomes this Perl code:

$objGroup->{Members}

Tactic 4: Dealing with Container Objects

Both the original VBScript and the Perl code in the preceding section return a container object. That object contains a set of user objects (the users who are members of the managers group). VBScript accesses the individual objects in the container object using in, and strangely enough, thanks to our import in “Tactic 1: Loading Your Modules,” so will we:

for my $objMember (in $objGroup->{Members}){
    # using the access syntax we saw in tactic #3
    print $objMember->{Name},"\n";
}

And there you have it—your first VBScript-to-Perl program:

# Lists all the members of the managers group in fabrikam.com

use Win32::OLE qw(in);

my $objGroup =
     Win32::OLE->

         GetObject('LDAP://cn=managers,ou=management,dc=fabrikam,dc=com');

for my $objMember (in $objGroup->{Members}){
    print $objMember->{Name},"\n";
}

If that looked simple, that’s a good sign. The goal here is to let you take simple sysadmin VBScript code and convert it to Perl without having to think too hard. If it seemed complicated, don’t worry, you’ll find that this sort of translation will become easier the more you grapple with specific examples. Let’s take a look at another VBScript example from the Microsoft Script Center so we can bring in another translation tactic.

Tactic 5: Converting Method Invocations

' Creates a new global security group -- atl-users02 -- within Active
' Directory.

Set objOU = GetObject("LDAP://OU=management,dc=fabrikam,dc=com")
Set objGroup = objOU.Create("Group", "cn=atl-users02")
objGroup.Put "sAMAccountName", "atl-users02"
objGroup.SetInfo

The first line of code should be an easy rewrite, so let’s look at the remaining lines. In these lines, the dot character (.) is used for a different purpose than we saw in tactic #3: this time the dot is used invoke an object’s methods (i.e., the verbs for the object) rather than to access the object’s properties (i.e., what pieces of data it holds). In a serendipitous twist of fate, like VBScript, Perl uses a similar syntax for method invocations and for hash dereferences. Perl uses the arrow operator (->) for both, so the remaining lines of code in our example get translated to:

my $objGroup = $objOU->Create('Group', 'cn=atl-users02');
$objGroup->Put('sAMAccountName', 'atl-users02')
$objGroup->SetInfo;

Here’s the finished translation:[147]

# Creates a new global security group -- atl-users02 -- within Active
# Directory.

use Win32::OLE;

my $objOU = Win32::OLE->

     GetObject('LDAP://OU=management,dc=fabrikam,dc=com');

my $objGroup = $objOU->Create('Group', 'cn=atl-users02');

$objGroup->Put('sAMAccountName', 'atl-users02')

$objGroup->SetInfo;

Pretty easy, no? The one marginally tricky conversion is the last SetInfo line. How did we know this was supposed to be a method invocation rather than a property access? In this case we got a strong hint because no assignment operator is present. When we access a property we usually expect something to be returned—a value, another object, etc. The VBScript doesn’t indicate that it is going to use any data returned, so we can safely assume this is a method invocation. The other tip here (probably more helpful to native English speakers who would pick up on this naturally) is that “SetInfo” sounds like an action and not a piece of data. If it sounds like it should be doing something rather than holding something, that’s probably what it does. While these tips aren’t foolproof, they can help you hazard a good guess. If worst comes to worst, try the translation as a property access and then, if that doesn’t work, attempt it as a method invocation.

Tactic 6: Dealing with Constants

Let’s look at one last VBScript example to illustrate our final translation tactic:

' Removes user MyerKen from the group Sea-Users.

Const ADS_PROPERTY_DELETE = 4

Set objGroup = GetObject _
  ("LDAP://cn=Sea-Users,cn=Users,dc=NA,dc=fabrikam,dc=com")

objGroup.PutEx ADS_PROPERTY_DELETE, _
  "member", _
    Array("cn=MyerKen,ou=Management,dc=NA,dc=fabrikam,dc=com")

objGroup.SetInfo

The very first line of this code probably jumps out at you. In VBScript, Const is used to define a constant. The constants you need for scripting are defined by OS and application developers and stored in a component’s or application’s type library. One of VBScript’s limitations (as of this writing) is that it can’t read these constants from the library. Instead, VBScript authors have to hardcode operational constants like ADS_PROPERTY_DELETE into their scripts. Perl, thanks to the Win32::OLE::Const module, doesn’t have this limitation. Instead of hardcoding in the constant in our translation (a move always fraught with peril), we can do the following:

use Win32::OLE::Const 'Active DS Type Library';

and the ADSI constants become available to us. The next obvious question is, where did the magic string “Active DS Type Library” come from? How did we know to use it instead of something like “ADSI TypeLib” or even “ADS Constants Found Here”? The string comes from the registration in the Windows registry for the activeds.tlb file found in either HKCR\TypeLib or HKLM\Software\classes\TypeLib. If that doesn’t mean much to you, a more useful answer might be: poke around in your registry, look at the SDK and other documentation Microsoft publishes, and/or search on the Web for someone else’s example code until you find a string that works for you.

The second and fourth lines of the code are things we’ve seen before, so let’s look at the third line. We’ve already seen how to translate a method invocation, and we know how to import constants, so the only remaining concern is how to deal with the Array("cn=MyerKen...") part. The good news is that VBScript’s Array() creation keyword maps nicely to Perl’s anonymous array reference creation syntax:

$objGroup->PutEx(ADS_PROPERTY_DELETE,
                 'member',
                 ['cn=MyerKen,ou=Management,dc=NA,dc=fabrikam,dc=com'];

Here’s the final result of our work:

# Removes user MyerKen from the group Sea-Users.

use Win32::OLE::Const 'Active DS Type Library';

my $objGroup = Win32::OLE->

     GetObject('LDAP://cn=Sea-Users,cn=Users,dc=NA,dc=fabrikam,dc=com');

$objGroup->PutEx(ADS_PROPERTY_DELETE,
                 'member',
                 ['cn=MyerKen,ou=Management,dc=NA,dc=fabrikam,dc=com']);

$objGroup->SetInfo;

These six tactics should get you surprisingly far on the road to your own conversions.

References for More Information

If you haven’t yet, you must download the Microsoft Scriptomatic tool (version 2 as of this writing) from http://www.microsoft.com/technet/scriptcenter/tools/scripto2.mspx. This Windows tool from “the Microsoft Scripting Guys” lets you poke around the WMI namespaces on your machine. When you find something you might be interested in using, it can write a script to use it for you. Really. But even better than that, it can write the script for you in VBScript, JScript, Perl, or Python. I can’t think of a better tool for comparing how one language is translated into another. I’m raving about this tool both here and in the other chapters that mention WMI because I like it so much. If you want to use it under Vista, though, be sure to read the section on Vista in Chapter 1, Introduction.

Finally, I should mention that if you don’t want to do your own translation from VBScript to Perl, there is a commercial product available that can do a much more sophisticated job than you’re likely to be able to manage after only a simple introduction like this. The VBScript Converter is part of ActiveState’s Perl Dev Kit (PDK). More information on the product can be found at http://activestate.com/perl_dev_kit/.



[144] One reason I call VBScript less palatable is that it requires a line continuation character when a single statement spans two lines in a file (and uses the underscore, _, for this purpose). It also uses a single quote (') as its comment character. But hey, who are we to pick on another language’s syntax?

[145] For more on container objects, see the section the section called “Dealing with Container/Collection Objects”.

[146] Just to be clear, this is the Perl 5 equivalent. Perl 6, still in its implementation stages as of this writing, is due to use the dot character as well.

[147] I’ve left it out because this is meant to be a strict translation, but it would be good to add error checking at various places in the script (e.g., checking the value returned from Win32::OLE::LastError()).

If you enjoyed this excerpt, buy a copy of Automating System Administration with Perl, Second Edition .

Copyright © 2009 O'Reilly Media, Inc.