Using ADSI scripting
In the fifth installment of our seven-part series on scripting in Windows 2000 Active Directory, we will use ADSI to create users and populate properties of their object.
Using ADSI scripting
by Jim Hudson
This article is derived from Special Edition Using Active Directory, by Jim Hudson and Sean Fullerton (Que Publishing, November 2000).
Active Directory Services Interface (ADSI) is a COM-based interface to the power of the Windows 2000 Active Directory. Because we are using the exact same COM DLLs with ADSI scripts that we use with the Active Directory Users and Computers tool, there is practically no limit to the functionality exposed with ADSI.
In this section, we are going to look at ADSI scripting with the goal of automating some mundane administrator tasks.
We can use the ADSI COM interface from both Visual Basic and Visual C++. However, in this book, we are going to use a subset of Visual Basic, VBScript. We will use VBScript in both WSH and ASP.
Windows Script Host
WSH is a scripting host that supports both VBScript and Jscript. Using WSH, you can write logon and logoff scripts for users, write startup and shutdown scripts for computers, and access COM DLLs. It is the capability to touch COM that makes WSH perfect for our needs in this chapter. Also, you may or may not own Visual Basic, but if you own Windows 2000, you have a copy of WSH already installed by default on every Windows 2000 computer in your enterprise. You can create these scripts in Notepad, save them with a .vbs extension, and run them from the command line by executing the filename.
Creating a User
In our example, we are going to create a user. This is a fairly straightforward process that demonstrates the basics of much of ADSI programming. In Listing 1, we see a simple script to create a user in a specified context and assign a password. We will step through this example to view and apply basic concepts of ADSI scripts.
`set error handling on error resume next `enable command line arguments set objargs=wscript.arguments username=objargs(0) contextpath=objargs(1) pwd=objargs(2) `bind to LDAP server set context=getobject("LDAP://" & contextpath) `set up the creation and schema type set usr=context.create("user", "CN=" & username) `set mandatory attributes for user object usr.put "samaccountname",username usr.put "useraccountcontrol","0020" `commit the change usr.setinfo `error handling and feedback if err.number=0 then usr.setpassword(pwd) wscript.echo "created user: cn=" & username & "," & contextpath else wscript.echo err.number, err.description end if
`set error handling
The first two sections are not really ADSI programming, but they simply the code necessary to use command-line parameters with our scripts and an error-handling directive. The on error resume next line allows our script to continue if it encounters errors. This allows our error-handling code to run because otherwise the script would simply exit with a VBScript error. Because some scripts can encounter real errors and still accomplish work, this is critical.
Be careful about setting error handling when debugging your code. If you have on error resume next set, your code may run, fail, and never return an error. You can turn this command on and off selectively during the debugging process by commenting it out with a single quote. Make sure that it is a single quote, and not an apostrophe. An apostrophe will cause the VBScript runtime to terminate with an error.
`enable command line arguments
Although we could use input boxes with our scripts, because this is designed to be a command-line tool, we will use the arguments property of the wscript object. This will allow us to execute the command shown in Listing 2 and to create a user named Mike in the Sales organizational unit of the fis.local domain; we also will set his password to qwerty.
C:\>createuser mike ou=sales,dc=fis,dc=local qwerty
`bind to LDAP server
The first event of virtually any ADSI operation is binding to AD. There are several ways to do this, including methods that work with NT domains and Novell NDS, but here we will focus on binding to an LDAP server on whatever domain controller the DNS service returns to us. The contextpath variable in Listing 1 is our LDAP path to the container that we want to create our user in. The command in Listing 2 has set this to the Sales OU of fis.local.
`set up the creation and schema type
The create method prepares AD to create an object of a given type and name. The type must be a valid class in the schema. In our example, we have used class user, but the code could be easily modified to create an instance of class computer or group.
`set mandatory attributes for user object
There are scores of attributes that can be set on a user object, and because the schema is extensible, we could add more. The only two that are required in this scenario are cn and samaccountname. Because we set the cn in our createobject call, we have to set only one other attribute, samaccountname with the put method. However, because the default behavior is for ADSI to create the user with a disabled account, the second put method sets the useraccountcontrol to 0020, which enables the account.
`commit the change
Although we have used the create method, the addition is not persisted to AD until we call setinfo. Then our object is written to the database.
If you are curious about what is happening under the hood with any of these examples, run the code snippets on a workstation or member server, and use Network Monitor to capture the packets during code execution. You will quickly see that mainly what we are doing is using COM and VBScript to manipulate LDAP. Because LDAP is responsible for finding, adding, changing and deleting objects in AD, and because it sends many of its commands in clear text over the network, there is much that can be learned here.
`error handling and feedback
This last section of code simply checks to see that there were no errors and then sets the password to the third command-line parameter. It also echoes a message box with the information that the object was created. If there is an error, the error number is sent in a message box also. The successful output message from the command executed in Listing 2 is shown in Figure 1.