25.6 Migrating Your ADSI Scriptsfrom VBScript to VB

If you decide you need a GUI-based application instead of a web-based application, it is time to start thinking about coding in a different language. VB is an easy language with the capabilities of great complexity. The VB language itself is very similar to VBScript, so you can port code quickly from your existing scripts. However, there is so much that you can do with VB that the bewildering array of interfaces and methods can easily get confusing. The simplest solution to this is to get a book on VB. There are many dozens of books that already exist on the complexities of writing in VB, and we do not intend to provide an introduction here. If you are seriously considering writing in VB, your best option is to pick up a book on it.

This section covers what you need to do to write ADSI code with VB after having written ADSI code in VBScript. This includes a brief look at the major differences between VBScript and VB, the options that need to be set, and the Platform SDK, which you will need to compile your code. We also briefly cover a series of examples that are available from the O'Reilly web site. The notes that we present in this section are with respect to Microsoft Visual Basic Professional Version 6.0. However, these examples should also work with future versions of VB as well.

25.6.1 Platform Software Development Kit

To access the ADSI interfaces and libraries, you need to be able to reference the appropriate component of the Microsoft Platform Software Development Kit (SDK) in your code. You can either download the appropriate component or obtain the full SDK, which includes all components.

The full SDK provides developers with a single, easy-to-use location from which to download current and emerging Microsoft technologies; it includes tools, headers, libraries, and sample code. The Platform SDK is the successor to the individual SDKs, such as the Win32, BackOffice, ActiveX/Internet Client, WMI, ADSI, and DirectX SDKs.

You can get the full SDK build environment or just the ADSI component in a number of ways:

  • If you purchase an MSDN Professional-level subscription, you will be shipped all of the SDKs that you require.

  • If you purchase an MSDN Enterprise-level subscription, you will be shipped all of the SDKs and all of the Visual Studio products, which includes Microsoft Visual Basic Enterprise Edition as well.

  • If you purchase Visual Basic 6.0 Enterprise Edition, you receive the full MSDN set of CDs and the SDK build environment.

You can download the parts of the platform SDK by following going to http://www.microsoft.com/msdownload/platformsdk/sdkupdate/.

If you wish to make use of ADO from the next chapter, you need Microsoft Data Access Components (MDAC) as well. You can download these from the Downloads section of the Universal Data Access site: http://www.microsoft.com/data/download.htm.

Once the SDK has been downloaded and installed, start VB and in any new project that you write make sure that you go to Project References and check items according to Table 25-1.

Table 25-1. When to use relevant references in VB


To use

Active DS Type Library


Microsoft ActiveX Data Objects 2.5 Library


You can see the References window in Figure 25-2, with both items checked.

Figure 25-2. Visual Basic references

25.6.2 The Differences Between VB and VBScript

There are many differences between VBScript and VB, but the three major ones that you will come into contact with when porting your scripts can be quickly explained. Screen functions

The code will not be executing under the WSH any more so Wscript.Echo is not appropriate. While MsgBox still works, these lines should be replaced either by Debug.Print or by directly passing results into TextBox controls. Variables

In VBScript, every variable is of the type Variant and does not have to be declared. In VB, every variable must be declared at the beginning, just as if you were using Option Explicit in VBScript. In addition, each variable must be declared to be of a particular type. Here are some examples for VB:

'VB code
Dim objUser as IADsUser
Dim objRoot as IADsContainer
Dim objMember as IADsMember

In addition, CreateObject is not needed. Instead, you use the New keyword and declare the object created prior to the main code. The following VBScript code:

'VBScript code
Set objConn = CreateObject("ADODB.Connection")

is replaced with the following code in VB:

'VB code
Dim objConn as New ADODB.Connection

For another important point, look at these declarations:

'VB code
Dim objUser as IADsUser
Dim objUser2 as IADs

If we want to use the IADsUser methods and properties, we have to use the variable objUser. If we want to use the IADs methods and properties, we have to use objUser2. This is how it works:

'VB code
Dim objUser as IADsUser
Dim objUser2 as IADs
Set objUser = GetObject("LDAP://cn=Administrator,cn=Users,dc=mycorp,dc=com")
Set objUser2 = objUser
Debug.Print objUser.Description
Debug.Print objUser2.Class

The first Debug::Print statement prints the IADsUser::Description property, and the second prints the IADs::Class property. We have to include the second Set command to make sure that objUser2 points to the same object as objUser. Loop constructs

The syntax for loops changes slightly. Here, for example, are two loops in VBScipt:

'VBScript code
While (condition)
  'Do something
For Each objMember In objGroup.Members
  WScript.Echo objMember.Name & vbCrLf & objMember.ADsPath

Here they are again in VB:

'VB code
While (condition) Do
  'Do something
For Each objMember In objGroup.Members
  Debug.Print objMember.Name & vbCrLf & objMember.ADsPath
Next objMember

We now can move on to some proper VB coding.

25.6.3 Getting Help from VB When Coding in ADSI

When you begin to code in VB, the interface tries to help you code by providing you with the appropriate methods and properties for the object you are manipulating.

For example, if we started declaring a variable in VB, then as soon as we had stated something like this:

'Declare use variable
Dim objUser As

the interface would pop up a box displaying all the variable types so we could pick one. We'll say that we chose IADsUser from the list at this point. Now in my code we wish to use a method on the object, so we start typing:

'Declare use variable
Dim objUser As IADsUser
'Use IADsUser method

As soon as we have typed the dot, VB knows we wish to use a method, so it pops up all the possible methods that we could use at this point. This is a great help, so that you do not have to remember the names of the methods and properties all the time.

You also can use View Object Browser (or use the F2 key), which shows you all the possible methods and properties available in any SDKs that are currently included as references to your project.

25.6.4 A Simple Password Changer in VB

This is a variation on the password changer we introduced earlier. This changer is for use by a help desk to set a user's password and automatically unlock the account if it is locked. All the users are presumed to be in the Users container for this simple project, which makes use of one form, shown in Figure 25-3.

Figure 25-3. The change password script result

The entire project can be downloaded from the O'Reilly web site.

The form (the window) contains the following controls (objects that sit on the window):

  • One PictureBox control, the O'Reilly logo

  • Three Label controls, the text fields that cannot be edited

  • Three TextBox controls (txtUsername, txtPass1, and txtPass2), the three data entry fields

  • One CommandButton control (cmdChangePassword), the Change Password button

Some of the properties for fields have been set as follows:

  • To make sure that using the Tab key cycles properly through the three TextBox controls and the CommandButton control, the TabIndex property is set for each control in the order that the Tab key is to cycle through, e.g., txtUsername=1, txtPass1=2, txtPass2=3, cmdChangePassword=4.

  • The two password boxes have the PasswordChar property set to "*" so that the password is not displayed in plain text on the form.

  • The ToolTipText property specifies the text that will appear when the cursor hovers over each TextBox and CommandButton. The text for the second password field is displayed in Figure 25-3.

The command button needs some code to tell it what to do when the button is clicked. This is known as an event procedure, as it is triggered when an event (clicking the button) occurs. No code is attached to anything other than the command button. The code that sits behind the command button looks like this:

Private Sub cmdChangePassword_Click(  )
Dim objUser As IADsUser
If txtUsername.Text <> "" Then
  If txtPass1.Text = txtPass2.Text Then
    Set objUser = GetObject("LDAP://cn=" + txtUsername.Text _
      + ",cn=Users,dc=mycorp,dc=com")
    objUser.SetPassword txtPass1.Text
    objUser.pwdLastSet = 0
    If objUser.IsAccountLocked Then objUser.IsAccountLocked = False

    'Reset everything
    txtUsername.Text = ""
    txtPass1.Text = ""
    txtPass2.Text = ""
    MsgBox "Password changed!"
    MsgBox "Passwords are not the same, please try again!"
  End If
  MsgBox "A username must be specified!"
End If

You can see that we are using the text typed into the TextBox::Text property for each TextBox control as necessary. We don't declare these controls as we do with variables, as the very fact that they're on the form is enough to declare them.

There is a procedure that is attached to the CommandButton called cmdChangePassword, and it is executed when a single-click event occurs on that button. When that button is clicked, we check that the txtUsername field has had a username typed in, and if it has, then we check that the two passwords are the same. If they are, we concatenate the username with the domain string and get a handle to the user object. We then use the IADsUser::SetPassword method with one of the two passwords as the parameter and also set the pwdLastSet property to 0 to indicate that the password is expired. This means the user has to change it when he next logs on. We then unlock the account if it was locked, because otherwise the user will be unable to make use of the new password. We then write out the property cache. You can also see that we are not checking that the password was set properly or later that the other properties were set. It would be simple to put in if desired.

25.6.5 The ModifyUserDetails Program in VB

Let's take one more example by extending the previous one to modify a variety of user details. Take a look at Figure 25-4.

Figure 25-4. The Modify User Details screen

Figure 25-4 is another simple user querying and modification tool. This one has a number of different features. To start with, the username is typed into the top TextBox. When the user clicks on the Find User! command button, an ADO search function retrieves the full ADsPath of the user. This ADsPath then is used to bind to the user and to retrieve the full name, the expiry date, the group memberships, the last logon and last logoff times, and whether the account is disabled or locked. The group membership's TextBox automatically displays vertical scrollbars if the results cannot be displayed in the space available.

The administrator then can use the Set Password! button to set the password. This time, no confirmation is requested; the password is just accepted as is. The Change Date! button can set the expiration date. The two account status checkboxes in the bottom right can enable/disable the account or unlock it if it gets locked.

Actually, the unlock checkbox should never give the option to lock an account; instead, it should be grayed out (disabled) by default. Then it can be enabled only when an account is locked. Clicking the checkbox on a locked account would unlock the account and then disable the checkbox again immediately. Obviously this means that a user could never change his mind and relock an account, which is fairly nonsensical, but in that case it can simply be disabled instead.

While the code is not particularly complex, it is quite long, and for that reason, we've made it available for download from the companion O'Reilly web site for this book.

    Part II: Designing an Active Directory Infrastructure
    Part III: Scripting Active Directory with ADSI, ADO, and WMI