Access and manage user accounts and network resources, no matter what network environment they come from
Do you want to use scripting or Visual Basic (VB) to enhance your user
administration and network resource management? Would you like to use a C
compiler to create utilities that work without modification on both Windows NT and NetWare? Do you want to add 200 user accounts with proper settings in a batch run or print a customized report of your users?
In February, Microsoft released a specification that makes these tasks possible: Active Directory Service Interfaces (ADSI) 1.0. ADSI is not a multivendor or Internet Engineering Task Force (IETF) standard; the copyright belongs solely to Microsoft. With ADSI, you can manage the resources in your directory services--and it doesn't matter which network environments those resources come from.
ADSI works with true directory services, such as NetWare 4.x's Novell
Directory Services (NDS) and NT 5.0's Active Directory (AD). ADSI also works
with network environments that don't have a directory service, such as NetWare
3.x (instead, its Bindery stores user accounts and other objects) and NT 4.0
(instead, its Security Accounts Manager--SAM--stores the user database and
domain models). Of course, you need an ADSI provider for all these environments.
When you have a true directory service, you can create directory-enabled
applications with ADSI, whether you are an inhouse developer or independent
software vendor (ISV). These applications go beyond network administration. They use the directory service as a distributed information store to
add value to current networked applications.
How does ADSI work? NT, NetWare, and other network operating systems have
native APIs for accessing and managing network resources. ADSI just puts a
uniform layer on top of the native APIs so that you don't need to use different
software development kits (SDKs) or learn different APIs to program for multiple
network environments. ADSI abstracts the objects and interfaces of the
underlying directory services and creates component object model (COM) objects
and interfaces for you to use.
Using ADSI might sound difficult, but it's not. You are probably already
familiar with part of ADSI's technology: COM. ADSI uses the same COM technology
as distributed component object model (DCOM) and ActiveX components. You just
need to learn about those technological areas that you might not be too familiar
with: the ADSI environment and ADSI objects.
The ADSI Environment
Both the ADSI application and provider run on your workstation. The target
server does not need any ADSI support or installation. The server just receives
native calls. The main platform for the 32-bit ADSI program is currently NT 4.0,
although ADSI also supports Windows 95, as Figure 1 shows. ADSI talks to four
different providers: ADSNW.DLL for NetWare 3.x, ADSNDS.DLL for NetWare
4.x, ADSNT.DLL for NT 4.0, and ADSLDP.DLL for NT 5.0 and Lightweight
Directory Access Protocol (LDAP) 2.0. These providers convert ADSI calls to
Win32 API, NetWare, or LDAP calls.
Although you can use ADSI with different networks, it has the closest
relationship with NT 5.0's AD. ADSI's and AD's terminology, design, structure,
and name are similar. ADSI will be the primary interface for programming to AD;
Messaging API (MAPI) and the traditional C language API for LDAP will be
secondary.
You can use VB 4.0 (32-bit version), VB 5.0, Visual C++ 4.2, and Visual J++
with the Java Virtual Machine (JVM) to develop applications. According to
Microsoft, you can also use any other application development tools that bind
and invoke interfaces in COM objects or act as an Object Linking and Embedding
(OLE) automation controller. For example, you can use ADSI with NT 5.0 Windows
Scripting Host (WSH) to develop Visual Basic Script (VBScript) batches or
scripts (see the sidebar "Use ADSI with WSH," page 164).
ADSI's Object Architecture
You won't find ADSI's object architecture complicated, but you might find it
confusing because every element in the network directory service is referred to
as an object. The object referral process begins when the network directory
service abstracts its resources by creating objects to represent them. So, for
example, users, servers, and printers become objects in the directory service
(NDS or AD). ADSI, in turn, abstracts these NDS and AD objects into COM objects,
as shown in Figure 2.
AD COM objects include dependent objects. Dependent objects are COM objects
that represent common functions, such as collection handling. Because you can
access dependent objects only through their host AD objects, I will not discuss
them further.
AD COM objects represent elements in the underlying directory service. Two
types exist: AD leaf objects and AD container objects. If an object can contain
another object--just like an electronic folder can contain an electronic
file--the object is an AD container object (herein referred to as simply container).
If an object cannot house another object--just like a file cannot contain a
folder--the object is an AD leaf object (or just leaf). Simply put,
containers can house leafs, but leafs cannot house containers. Table 1 contains
ADSI standard containers and leafs.
A container isn't limited to holding leafs. Just like an electronic folder
can contain other folders, a container can hold other containers. For example,
containers house AD Schema containers, which play an important role in ADSI. An
AD Schema container holds the objects that define the schema for a particular
part of a directory service. This container houses three different types of
objects: AD Schema class objects, AD Property objects, and AD Syntax objects.
AD Schema class objects represent the different types, or classes, of
elements in a directory service. One AD Schema class object exists for each
type, such as user, computer, group, and organization. The AD Schema class
object tells which properties are mandatory and which are optional for the
corresponding object type. For example, the AD Schema class object for user
might have a mandatory property of user name and an optional property of fax
number. The AD Schema class object also tells whether the object's class is
derived from other classes (and thus would support also their properties).
The AD Property object represents one property of the AD Schema class
object. Thus, in this example, you need two AD Property objects: one to
represent the user name and the other to represent the fax number. If two AD
Schema class objects have the same property, they share the AD Property object.
For example, if the AD Schema class objects of user and organization both have
the property of fax number, only one AD Property object of fax number will
exist.
Each property uses a syntax, which is represented by the AD Syntax object.
So, in this example, you need two AD Syntax objects: one to represent the string
syntax of the name property and another to represent the fax number syntax of
the fax number property.
The AD Schema class objects define where containers and leafs belong. A given namespace permits only certain types of containers and certain types of leafs. Similarly, each type of container permits only certain types of containers and leafs. Thus, the schema are the rules of the directory service database because they define what information the database can store.
The schema in NT 5.0's AD and NetWare 4.0's NDS are extensible. You can
define new object classes or redefine existing object classes. Applications are
numerous, but one traditional example is to add payroll information to user
objects.
NT 4.0 and NetWare 3.0, however, have locked schema. With fixed object
classes, only the directory service provider (e.g., Microsoft and Novell) has
the ability to add objects that are not in the standard ADSI object set.
It's Time to Start
Now that you know about ADSI's environment and object architecture, you can
start experimenting with ADSI. But first, you need to download it from
http://www.microsoft.com/win32dev/netwrk/adsi.htm. To create programs or
scripts with ADSI, you need the several-megabyte SDK, which includes the ADSI
specification (a 100-page Word document). Then you need the 500KB-compressed
runtime libraries and possibly a patch for them. You must install these
libraries in each workstation that will execute ADSI applications. (NT 5.0 will
include these runtime libraries.)
After you install the downloaded files, you need to enable VB to use ADSI.
In VB 5.0, simply select Project/References and check Active DS Type Library in
the list of references. In VB 4.0, you first need to use the Tools menu to add
the type library ActiveDS.Tlb (in System32 folder) to your Project menu. These
steps let you use AD COM objects in your application.
For the sake of simplicity, the examples from this point on will focus on
how to implement ADSI on NT rather than NetWare. The examples will deal mostly
with users as the objects, but the same principles apply if the objects are
printers, services, or other elements.
Browse a Little, Report a Lot
Once you have installed the necessary files, you can browse with DSBrowse,
which is in the SDK. This sample application browses your namespaces and shows
objects and properties in them.
Next, you can run several reports that will help you learn about your
directory services. The reports that are most useful are the namespaces, user,
and property reports.
Namespaces correspond to the four providers: WinNT, NWCOMPAT, NDS, and
LDAP. Table 2 (page 166) gives examples of names in different namespaces. To
check which namespaces are installed in your computer system, you can use this
code:
Dim NamespacesObj as IADs Namespaces
Dim obj as IADs
Set NamespacesObj = GetObject("ADS:")
For Each obj in NamespacesObj
Debug.Print obj.Name
Next obj
This exercise not only tells you which namespaces are available, but also
shows you many of the steps in ADSI programming. First, you define the variables
with Dim statements, usually including the letters IADs. Next you use GetObject
to instantiate (or create) the object based on the path given. GetObject is an
ADSI helper function and is not to be confused with a VB function with the same
name. Then on the same line, you assign the object to a variable, after which
you can finally use it. If your object has many elements, you can walk through
them with the For Each loop.
If you want to make a report containing all users and their home directory,
you first need to use the code just given to find out the namespaces. (If you
want, you can skip this step and just assume that you are using NT with the
WinNT: namespace. This assumption isn't too risky.) Next, determine which
domains you have. If your namespace is only WinNT:, you can get a list of the
domains from your network neighborhood. Once you know the domains, use this
code:
Dim Container As IADsContainer
Dim Child As IADs
Set Container = GetObject
("WinNT://SomeDomain")
Container.Filter = Array("user")
For Each Child In Container
Debug.Print Child.Name + Chr$(9) + Child.HomeDirectory
Next Child
This code sets a filter to the container so that it lists only users. It
ignores other objects, such as groups and computers. (You can, however, run
reports on other objects in a domain. The SDK can help you with this task.) The
code then uses a For Each loop to recall each user's name and home directory.
A property report will tell you which optional properties each user
supports. (A printout of mandatory properties would be empty.) Here's how to run
the optional properties report:
Dim Class As IADsClass
Set Class = GetObject("WinNT://SomeDomain/Schema/User")
l = LBound(Class.OptionalProperties)
u = UBound(Class.OptionalProperties)
For i = l To u
Debug.Print Class.OptionalProperties(i)
Next i
Table 3 shows sample output from this procedure.
Another way you can access the properties of AD objects is to use the Get
and Put methods. A benefit of using Get and Put is that, theoretically, you do
not need to know anything about your network objects or properties beforehand.
You can browse the schema and then use the property names found as variables in
the Get and Put statements. (For more information on Get and Put, see the ADSI
specification.)
NT 4.0 has some shortcomings with regard to user properties. It does not
report three properties (PasswordExpirationDate, AccountDisabled, and
IsAccountLocked) in OptionalProperties, so you cannot use them with Get and Put.
Conversely, two properties (PasswordExpired and BadLoginCount) work only with
Get and Put and not the previous procedure. Thus, you might have to use both
approaches.
Another shortcoming is that you can access the properties of
UserCannotChangePassword, PasswordNeverExpires, and Global/Local account type
only through the UserFlags bit field property. So you have to find the right
bits and do some calculations. Finally, you cannot access the dial-in settings
and the properties LogonHours, HomeDirDriveLetter, PasswordLastChanged, and
LastFailedLogin.
Manipulating Objects
When you have done enough browsing and reporting, you will likely be eager
to make some changes. When manipulating objects, you need to identify both the
objects and their paths. To identify the object from its path, you can use the
GetObject function as in the code examples here. To identify the path to an
object, you can use the ADsPath property by typing:
PathToSomeObj = SomeObj.ADsPath.
You can manipulate objects in many ways using Create, Delete, Move, and
Copy. Here's an example of how to use Create to add a new user and its
properties to a container in NT 4.0:
Dim Container As IADsContainer
Dim NewUser As IADsUser
Set Container = GetObject
("WinNT://SomeDomain")
Set NewUser = Container.Create
("user", "Maggie")
NewUser.FullName = "Henderson Maggie"
NewUser.HomeDirectory = "\\Server2\Maggie"
NewUser.SetInfo
NewUser.SetPassword ("secret")
Set NewUser = Nothing
An important element in this code is SetInfo. After you specify the object
you are creating, its name, and its properties (lines 3 through 6 in the code),
the client computer caches this information. The computer creates the object and
adds the property values to the user database only when you use SetInfo (line
7). You do not have to use SetInfo, however, when creating a password because
SetPassword (line 8) is a method and not a property.
Another important element is the Set NewUser = Nothingstatement (line 9).
Use this statement when you finish working with a COM object. Otherwise,
depending on the scope of the object variable, you might not release all the
memory back to the operating system.
NT 5.0 beta includes a VBScript example program, which adds and deletes
users using a Microsoft Excel worksheet. The program uses ADSI and is 170 lines
long, half of which are comment lines.
Deleting, moving, and copying objects in ADSI is as simple as creating
them. The ADSI specification can show you how to perform these and other
procedures. If you have questions, Microsoft has an ADSI news group at
msnews.microsoft.com/microsoft.public.
active.directory.interfaces. In
addition, Microsoft's Knowledge Base will likely contain program examples and
other information. You just need to go to http://
www.microsoft.com/kb and
search on ADSI. The Microsoft Developer Network (MSDN) is another resource to
tap into.
The Best Is Yet to Come
Although the ADSI specification is version 1.0, it performs more like a beta
version. Using ADSI with NT 4.0 or NetWare is more limiting, although easier,
than using the corresponding native APIs.
This situation, however, will change next year for two reasons. First,
Novell will release an ADSI provider for NDS that will likely support the
NetWare environment better than Microsoft's ADSI provider. Novell's ADSI
provider will give NetWare users a way to access NDS via COM programming. This
access will be beneficial because the clients will already be using 32-bit
Windows.
Second, Microsoft will release NT 5.0 next year. ADSI is the chosen
interface for NT 5.0's AD, so ADSI will perform at full capacity. In addition,
although Microsoft designed ADSI and AD at the same time, it released ADSI
earlier. The earlier release will give ADSI time to mature. By the time
Microsoft releases NT 5.0, ADSI's bugs will likely be worked out.
Microsoft has committed to using LDAP 3 in NT 5.0 if the IETF finalizes
this revised protocol in time. The LDAP 3 draft specification calls for an
improved referral process, better support for user authentication,
extensibility, and other improvements. (For more information about LDAP 3 and
how various vendors plan to use it, see Craig Zacker, "LDAP and the Future
of Directory Services, Part 2," page 191.) The use of LDAP 3 in NT 5.0
would likely bring about two changes: ADSI would get an LDAP 3 provider and LDAP
3 would update ADSI.
If AD dominates the industry, ADSI will be beside it. But if a new
programming technique replaces object-oriented COM, ADSI will vanish. However,
ADSI probably won't disappear in this millennium, so you need to take a closer
look at it. ADSI is an object that represents the future.