This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


Cutting Edge
cutting@microsoft.com
Dino Esposito

ADSI Overview
A
long with their countless advantages, networks introduce a number of new problems, such as how to quickly and reliably locate the resources you need. Modern distributed operating systems implement something called "directory services" to enable users to locate network resources. Most of us associate the word "directory" with a list of files on disk. However, this is just one way to look at it. The actual content of a directory depends upon its namespace. When the namespace is the file system, the directory is a repository for file names and attributes. But a namespace can be virtually any resource on a network: shared hardware components (printers, faxes, or scanners), users, applications, folders, archives, views, and even individual procedures.

    Windows® 2000 offers Active Directory™ directory services. Active Directory Services (ADS) offers scalable, integrated, Internet-oriented services to meet the problem of information sharing and network resource management in an enterprise.

The ABCs of Directory Services

    In its simplest form, a directory service is a database that keeps track of all the attributes and locations of shared objects across a network. Users who want to reach any of these objects (often referred to as resources) may interrogate the service using a special syntax. A directory service that's been assigned a syntax is also called a namespace. For example,


 //Expoware/Dino 
is the syntax that Windows 2000 uses to identify a workstation and a logged-in user. The collection of all the workstations and users across a network that can be accessed this way from a namespace. A directory service provides a way to manage the data stored in internal tables and to read and set security flags and descriptions.

    A directory service is a type of stripped-down database that, like a telephone directory, is optimized to work best for read-only operations. A directory service must handle a very high volume of requests, always providing precise and concise answers that are valuable to the requester. While a directory is subject to updates, these are relatively infrequent and don't require transaction management, referential integrity, or other complex features (but can support them). A directory server is much simpler than a database server. Nevertheless, it has to manage large amounts of interrelated data and support nontrivial queries. It is more powerful than a desktop database, but less powerful than a full-blown database system like SQL Server™.

    A directory service called the Lightweight Directory Access Protocol (LDAP) was invented some years ago at the University of Michigan. Take a look at http://www.umich.edu/~dirsvcs/ldap for more information. In 1995, LDAP became a standard widely supported by today's network products and operating systems.

The Importance of a Directory Service

    Perhaps the best introduction to the world of directory services and Active Directory I've ever read is the one contained in the book Professional DCOM Application Development, by Jonathan Pinnock (Wrox Press, 1998). If you're a member of MSDN Online, you can view an excerpt of this book at http://msdn.microsoft.com/library/partbook/dcom/professionaldcomapplicationdevelopment.htm. To demonstrate the importance of a directory service, Jonathan describes the troubles you encounter when registering a DCOM component.

    You need to register the remote server name independently on every client machine that may use it. This means that any change in the server's name forces you to update the configuration on all the client machines. This is a situation in which a centralized service to perform a registry search would help considerably.

Figure 1: DCOM Directory Service Layout
Figure 1: DCOM Directory Service Layout

    Figure 1 shows a possible layout for this pseudo-directory service using DCOM. Client machines ask the hypothetical DCOM directory service to return the name of the closest remote machine where the component with the specified CLSID is installed. This would make it unnecessary to store the remote server name locally, and the deployment of DCOM applications would probably be easier. While the performance of such a DCOM directory service is always a challenge, it illustrates the importance of directory services in distributed systems.

    Almost all software that runs over a network—from operating systems to email managers and groupware products—offers services to help users locate shared resources quickly and reliably. As always seems to be the case, different vendors' products don't integrate very well. Administrators have to cope with several similar tools, each of which is tailored to particular specifications and may not be extensible. Here is where ADS can help.

What's Different with Active Directory

    The ideal directory service would include tight integration with the underlying operating system, a centralized console from which to administer user accounts and resource visibility, a unique filter to validate logons, and an open interface that would let people build extensions. It would also need an extremely flexible structure so it could promptly modify the overall network design to reflect structural changes in the enterprise. ADS provides all this and more.

    At its most basic, ADS is a layer of system code designed to normalize existing directory services by hiding differences and providing a uniform interface to the external world. This interface lets it more easily integrate services and add new ones without breaking a user's view of the data.

    A number of existing technologies have been integrated into ADS, including LDAP (for directory access), Dynamic DNS (for host management), TCP/IP (for network transportation), and Kerberos (for security). In addition, Microsoft® is working to add support for other directory services that you may have on your systems—in particular, Novell Netware Directory Service (NDS) and AppleShare for Macintosh.

    ADS is an open architecture. Active Directory Service Interfaces (ADSI) is an object that exposes interfaces. Using ADSI, you can access any compliant directory service, or write your own. What does ADS add to Windows 2000?

    ADS plugs what many considered a gap in previous versions of the Windows NT® platform (specifically, in the handling of large distributed systems) by providing a powerful and extensible mechanism for directory services.

The Active Directory Architecture

    Active Directory is part of the Microsoft Open Directory Service Interface (ODSI) initiative, which is aimed at identifying a standard set of functions for directory-enabled applications that accommodates different vendors' implementations and APIs. Everything involving the underlying network is exposed through ADSI, the programming interface of ADS. Figure 2 shows the relationship between client applications and ADSI, and the path a request follows to link to the desired network resource.
Figure 2: Clients, ADSI, and Network Resources
Figure 2: Clients, ADSI, and Network Resources

    As with any other directory service, Active Directory is a namespace—a portion of the system in which a given name corresponds to a precise and unique object. Each object has some information associated with it. When a client references an object through its name, it is actually interested in the data it contains or the service it provides.

    The concept is not far removed from using variables in source code. If you consider a C++ program that uses a namespace keyword, the analogy is even stronger. A variable is identified by a name that has a scope and belongs to a namespace. Using these two pieces of information, the compiler can link the variable to some address in memory where it finds the desired data. Extend this idea to a network and you will understand Active Directory. The process of converting a name into specific, usable information is called name resolution.

    An Active Directory object is nothing more than a collection of attributes that describe and qualify a shared resource. The attributes of a printer might be its name, driver, building, and color. Likewise, a user might be identified by name, title, and email address.

    Objects always belong to containers. Containers are collections of attributes that don't point to something concrete, but simply contain other containers or objects. The concepts of container and object are parallel to the more familiar concepts of folder and file. In Active Directory jargon, a hierarchy of containers is called a Directory Information Tree. The full path that traverses the tree up to the object is said to be a distinguished name (as opposed to a relative name). Distinguished and relative names correlate to full and relative path names; a distinguished name is unique to a directory, while a relative distinguished name is unique only to the container it lives in.

    An Active Directory domain is the same as a domain in a Windows NT-based network. When domains share the same schema and are linked by trust relationships, you have domain trees. See Figure 3 for a view of domains in Active Directory.
Figure 3: Active Directory Domains
Figure 3: Active Directory Domains

    A schema is like a dictionary. It defines every type of object a directory service knows. The schema is stored inside the directory and exposes its own object model so applications can browse it. A pleasant side effect is that the schema is highly dynamic. Applications can extend it with new attributes and classes and make the extensions immediately available.

    Every object in Active Directory contains its own Access Control List (ACL). An ACL is, in its simplest form, the list of the users allowed to see the object and the actions they can perform on it. This mechanism lets a system administrator hide the existence of an object from unauthorized users.

A Common Interface for Directory Services

    ADSI is the set of COM interfaces needed to write Active Directory-based client applications. With ADSI, programs can communicate with any available namespace that provides an ADSI implementation.

    ADSI is a common and uniform layer of code that shields applications from the details of network-specific API calls. The idea behind this interface is much like OLE DB. In fact, an early name for this technology was OLE DS, where DS stands for Directory Services. Figure 4 depicts how ADSI relates to actual services.
Figure 4: From ADSI to Directory Services
Figure 4: From ADSI to Directory Services

    ADSI is a COM-based layer of code and exposes automation interfaces that can be used in Visual Basic®, the Java language, Windows Scripting Host (WSH), or ASP scripts, as well as providing nonautomation interfaces for C++. In addition, ADSI can be programmed via OLE DB and ADO through the provider named ADSDSOObject.

    Figure 4 shows how the role of ADSI providers parallels that of OLE DB providers or ODBC drivers. ADSI comes with support for LDAP, NDS, NetWare 3.x, and Windows NT namespaces, and third-party vendors can provide support for other systems. Figure 5 shows a more complete picture of ADSI and its client applications.
Figure 5: ADSI and its Clients
Figure 5: ADSI and its Clients

    Both administrators and developers can take advantage of ADSI to enumerate and access any resource in any available directory service, no matter what kind of network hosts it. Typical tasks that ADSI makes easier are adding new users or changing their account details, and enabling, disabling, or changing printers.

    This is particularly important in light of two development environments, one emerging and one in widespread use: WSH and ASP. ADSI provides a single set of directory service interfaces, regardless of the installed directory services. WSH and ASP are the most natural ways to write quick and easy script code, whether you're targeting a client machine (with WSH) or your intranet (with ASP).

Identifying Objects via ADSI

    ADSI is meant to work on top of both existing and new directory services. Every service has its own set of APIs and its own naming conventions to identify objects. Thus, a uniform approach to object identification would be valuable. To unambiguously determine which object you're referring to in a heterogeneous network environment, ADSI introduces a name strategy called ADsPath strings.

    ADsPath strings are expressed as follows:

 ADS:
 NamespaceIdentifier:
 NamespaceIdentifier://ProviderSpecificPath
The prefix "ADS:" refers to the global container of all the namespaces for which an ADSI provider is available. The collection contains any number of namespace identifiers. NamespaceIdentifier: points to the namespace in question. It's the root of the namespace and ADSI uses it to identify the provider that will handle the rest of the path. The namespace identifier plays the same role as the protocol string in a URL. For example, the namespace identifier "NW41:" identifies the NetWare 4.1 provider.

    The third ADsPath string identifies a specific object in the given namespace. The content of ProviderSpecificPath is provider-specific. The typical string for the Windows NT namespace would be:


 WINNT://WorkGroup/Expoware/Administrator
This example points to the administrator of the WorkGroup/Expoware domain.

Programming ADSI

    The programming interface of Active Directory provides two general categories of COM interfaces: automation interfaces whose names follow the pattern IADsXxx, and nonautomation interfaces whose names are in the form IDirectoryXxx. For nonautomation clients, there are also a number of functions like ADsGetObject that let you bind seamlessly to ADSI objects and get the pointer to the needed COM interface.

    Let's see how to build the world's simplest ADSI-aware application. All the sample programs discussed here are taken from the ADSI 2.5 SDK, available by installing the latest version of the Microsoft Platform SDK.

    The first thing to take into account is binding to ADSI objects. This can be accomplished by using the ADsGetObject function or the GetObject function from Visual Basic. In C++ you would write:


 IADsUser *pUser;
 BSTR bstrName;
 HRESULT hr;
 hr = ADsGetObject(L"WinNT://WorkGroup/Expoware/Administrator", 
                   IID_IADsUser, (void**) &pUser); 
With Visual Basic or VBScript you would write:

 Dim oProvider As IADs 
 Set oProvider = GetObject("WinNT://WORKGROUP/EXPOWARE/Administrator")
Of course, if you're writing VBScript code, remember that you should omit the type declaration "As IADs" since it is not supported by VBScript.

    By using ADsGetObject or its Visual Basic counterpart, you connect to the object using the credentials of the currently logged on user. If you use AdsOpenObject, you can get a different behavior and bind to the object by impersonating another user. If you do this, you must specify both the user ID and the password. In Visual Basic this becomes:


 Dim openDS As IADsOpenDSObject
 Dim usr As IADsUser
 Set openDS = GetObject("LDAP:")
 openDS.OpenDSObject("LDAP://CN=Bob,DC=ArcadiaBay,DC=com", _
                             "Administrator", "password", _
                             ADS_SECURE_AUTHENTICATION)
In this code snippet I've also shown the use of the LDAP namespace. Notice how LDAP uses a completely different syntax for object identification and naming. Once you've bound to an ADSI object, you can navigate its namespace, search for specific information, modify the data, or impersonate a user.

    Programming with ADSI is no more difficult than programming Dynamic HTML or XML. After you bind to an object, you suddenly find lots of simple-to-understand collections of objects with their methods and properties. The reference guide is available through MSDN™ and the Platform SDK.

Figure 6: A Sample ADSI Application
Figure 6: A Sample ADSI Application

    Figure 6 shows one of the Visual Basic sample programs that comes with the ADSI SDK running under Windows 2000. ADSI components have a set of attributes that map to the properties of connected COM objects. Properties are cached in memory for better performance. Enumerating objects in WSH is as easy as this:

 Dim MyObject 
 Dim Child  
 Dim Container  
 Dim strNS

 Set MyObject = GetObject("ADs:")
 Set Container = MyObject 
 For Each Child in Container
     strNS = strNS + Child.Name + vbCrLf    
 Next 

 WScript.Echo strNS
 WScript.Quit
On my machine, this code generates a dialog box like the one in Figure 7.
Figure 7: WSH Objects
Figure 7: WSH Objects

With Visual Basic, you should add types to the variables:

 Dim MyObject as IADs
 Dim Child as IADs
 Dim Container as IADsContainer
ADSI also builds a schema object for every root node in its Namespace collection. To know about the items of a given namespace, you enumerate the schema object and get a list of its mandatory and optional properties:

 Dim obj As IADs
 Dim cls As IADsClass
 Set obj = GetObject("WinNT://Workgroup/Expoware/
                     Administrator")
 Set cls = GetObject(obj.Schema)
 For Each p in cls.MandatoryProperties
      MsgBox "Must-have property: " & p
 Next
 For Each p in cls.OptionalProperties
     MsgBox "May-have property: " & p 
 Next
Among other things, ADSI provides an answer to a couple of frequently asked programming questions: how do you list the computers on a Windows NT domain, and how do you manage file shares on a Windows NT domain? For more details, please refer to the Knowledge Base articles Q194115 (http://support.microsoft.com/support/kb/articles/q194/1/15.asp) and Q169398 (http://support.microsoft.com/support/kb/articles/q169/3/98.asp).

A Word about Migration

    Windows 2000 will involve major changes at all levels, including system administration. One component is Active Directory, which is meant to simplify and empower your network organization. When you upgrade to Windows 2000, migrating to Active Directory will be a must, but you can make the complete changeover gradually. Initial migration can be realized quickly by using your existing structure. Simply map the existing domains into their corresponding Active Directory trees. You can then take the time to thoroughly study how to modify the directories.

    There are a couple of preliminary things to consider. First and foremost, make TCP/IP the protocol of your network. TCP/IP is the only protocol that Windows 2000 installs by default, even if NetBEUI or IPX/SPX are supported. Second, Windows 2000 requires DNS names to locate servers. Assigning NetBIOS names that are compatible with standard DNS names (using only the characters A-Z, a-z, 0-9, and the dash) is a good starting point.

Summary

    Active Directory is designed to help enterprise networks evolve from a closed and internal-only solution to an open and Internet-ready structure. This transition won't be painless, but your efforts will be rewarded. This column just scratches the surface in its description of the Active Directory support for network administration and the directory services. There's still much more to explore. Refer to the Windows 2000 beta information and the Microsoft Platform SDK for more complete ADSI coverage.


From the May 1999 issue of Microsoft Internet Developer.