In the VBScript solutions, my intention was to provide the answer in as few lines of code as necessary. Since this book is not a pure programming book, I did not want to provide a detailed explanation of how to use ADSI or WMI. If you are looking for that, I recommend Part 3 of Active Directory, Second Edition. The intent of the VBScript code is to provide you the basics for how a task can be automated and let you run with it. Most examples only take some minor tweaking to make them do something useful for you.
Just as with the GUI and CLI solutions, there are some important issues to be aware of when looking at the VBScript solutions.
I mentioned earlier that in the GUI and CLI examples I did not provide instructions for targeting a specific domain controller to perform a task. Instead, I rely on serverless binds in most cases. The same applies to the API solutions. A serverless bind for the RootDSE looks like the following in VBScript:
set objRootDSE = GetObject("LDAP://RootDSE")
That code will query the RootDSE for a domain controller in the domain of the currently logged on user. You can target a specific domain instead by simply specifying the domain name in the ADsPath:
set objRootDSE = GetObject("LDAP://apac.rallencorp.com/RootDSE")
And similarly, you can target a specific domain controller by including the server name in the ADsPath:
set objRootDSE = GetObject("LDAP://dc1/RootDSE")
So depending on how your environment is set up and what forest you want to query, you may or may not need to specify a domain or server name in the code.
Just as you might need to
the GUI and CLI tools with alternate credentials, you may also need
to run your scripts and programs with alternate credentials. One way
is to use the
runas method described earlier when
invoking the script. A better option would be to use the Scheduled
Tasks service to run the script under credentials you specify when
creating the task. And yet another option is to hardcode the
credentials in the script. Obviously, this is not very appealing in
some scenarios because you do not want the username and password
contained in the script to be easily viewable by others.
Nevertheless, it is a necessary evil, especially when developing
against multiple forests, and I’ll describe how it
can be done with ADSI and ADO.
With ADSI, you can use the
IADsOpenDSObject::OpenDSObject method to specify
alternate credentials. You can quickly turn any ADSI-based example in
this book into one that authenticates as a particular user. For
example, a solution to print out the description of a domain might
look like the following:
set objDomain = GetObject("LDAP://dc=apac,dc=rallencorp,dc=com") WScript.Echo "Description: " & objDomain.Get("description")
OpenDSObject, it takes only one additional
statement to make the same code authenticate as the administrator in
set objLDAP = GetObject("LDAP:") set objDomain = objLDAP.OpenDSObject( _ "LDAP://dc=apac,dc=rallencorp,dc=com", _ "firstname.lastname@example.org", _ "MyPassword", _ 0) WScript.Echo "Description: " & objDomain.Get("description")
It is just as easy to authenticate in ADO code as well. Take the
following example, which queries all
objects in the apac.rallencorp.com domain:
strBase = "<LDAP://dc=apac,dc=rallencorp,dc=com>;" strFilter = "(&(objectclass=computer)(objectcategory=computer));" strAttrs = "cn;" strScope = "subtree" set objConn = CreateObject("ADODB.Connection") objConn.Provider = "ADsDSOObject" objConn.Open "Active Directory Provider" set objRS = objConn.Execute(strBase & strFilter & strAttrs & strScope) objRS.MoveFirst while Not objRS.EOF Wscript.Echo objRS.Fields(0).Value objRS.MoveNext wend
Now, by adding two lines (shown in bold), we can authenticate with the administrator account:
strBaseDN = "<LDAP://dc=apac,dc=rallencorp,dc=com>;" strFilter = "(&(objectclass=computer)(objectcategory=computer));" strAttrs = "cn;" strScope = "subtree" set objConn = CreateObject("ADODB.Connection") objConn.Provider = "ADsDSOObject"
objConn.Properties("User ID") = "email@example.com"
objConn.Properties("Password") = "MyPassword"objConn.Open "Active Directory Provider" set objRS = objConn.Execute(strBaseDN & strFilter & strAttrs & strScope) objRS.MoveFirst while Not objRS.EOF Wscript.Echo objRS.Fields(0).Value objRS.MoveNext wend
To authenticate with ADO, you need to set the
User ID and
Password properties of the ADO
connection object. I used the UPN of the administrator for the user
ID. With ADSI and ADO, you can use a UPN, NT 4.0 style account name
(e.g., APAC\Administrator), or distinguished name for the
An important part of any script is error checking. Error checking allows your programs to gracefully identify any issues that arise during execution and take the appropriate action. Another best practice is to define variables before you use them and clean them up after you are done with them. In this book, most of the programmatic solutions do not include any error checking, predefined variables, or variable clean up. While admittedly this is not setting a good example, if I included extensive error checking and variable management, it would have made this book considerably longer with little value to the reader. Again, the goal is to provide you with a code snippet that shows you how to accomplish a task, not provide robust scripts that include all the trimmings.
Error checking with VBScript is pretty straightforward. At the beginning of the script include the following declaration:
On Error Resume Next
This tells the script interpreter to continue even if errors occur.
Without that declaration, anytime an error is encountered the script
will abort. When you use
Next, you need to use the
object to check for errors after any step where a fatal error could
occur. The following example shows how to use the
On Error Resume Next set objDomain = GetObject("LDAP://dc=rallencorp,dc=com") if Err.Number <> 0 then Wscript.Echo "An error occured getting the domain object: " & Err.Description Wscript.Quit end if
Two important properties of the
Err object are
Number, which if non-zero signifies an error, and
Description which will contain the error message.
As far as variable management goes, it is always a good practice to include the following at the beginning of every script:
When this is used, every variable in the script must be declared or
an exception will be generated when you attempt to run the script.
Variables are declared in VBScript using the
keyword. After you are done with a variable, it is a good practice to
set it to
Nothing so you release any resources
bound to the variable, and don’t accidentally re-use
the variable with its previous value. The following code shows a
complete example for printing the display name for a domain with
error checking and variable management included:
Option Explicit On Error Resume Next Dim objDomain set objDomain = GetObject("LDAP://cn=users,dc=rallencorp,dc=com") if Err.Number <> 0 then Wscript.Echo "An error occured getting the domain object: " & Err.Description Wscript.Quit end if Dim strDescr strDescr = objDomain.Get("description") if Err.Number <> 0 then Wscript.Echo "An error occured getting the description: " & Err.Description Wscript.Quit end if WScript.Echo "Description: " & strDescr objDomain = Nothing strDescr = Nothing