You are on page 1of 17

Active Directory Service

Interfaces
Author: Deepak Shenoy
shenoy@agnisoft.com
Agni Software Pvt. Ltd.

Introduction
Prerequisites
What is ADSI?
Why should you use ADSI?
Where is ADSI used?

ADSI Architecture
Overview
COM Object Model

Using ADSI in Delphi


Binding
Accessing Properties
Searching
- Using ADO
- Using IDirectorySearch Security

ADSI Schema

Providers

Conclusion
References

(Download the code for this article at


http://www.agnisoft.com/adsi/adsicode.zip)
Introduction
Microsoft has released Active Directory Service Interfaces (ADSI) for Windows
9x, NT and Windows 2000, and now it's inbuilt in Windows 2000. The Windows
2000 application specification states that you must use Active Directory when you
can, so now you're thinking: How are YOUR applications going to adapt? What
changes do you need to make? How are you going to use Delphi effectively to make
these changes? This is what I intend to address in this presentation.

Let me first introduce a “directory


service”. A directory service is like a
telephone directory: if you have a
person’s name, you can find his/her
phone number. A directory service
keeps track of “resources”, which could
be anything – a file system is a
directory that keeps track of files and
folders, an email server is a directory
service that indexes users, user groups
etc. There are many directory services
already in place: we already have file
systems and email servers. What’s so
different? Traditionally, you’d have to
use different API’s (Application
Programming Interfaces) to access
different directory services – which :

Limit you to the vendor’s


directory service. For example, if you
wrote an application that extracted
email information from Microsoft Mail
and used the Mail Application
Programmers Interface (MAPI), you
would find it difficult to move to a
different vendor.
Increase development time for
your applications because you need
to learn more API’s to get your
application working.

There is a need to have a common


model that every directory service
would support – similar to the ODBC
programming model that all (or most)
database vendors now support. A
model that will support a hierarchy of
resources, like folders and files, and be
simple to use. Active Directory
provides this model. To access an
Active Directory, you will use Active
Directory Service Interfaces(ADSI).
Where is Active Directory used?
"Active Directory" encapsulates all directory services - a list of printers on a
network, a set of services on an NT server etc. Directory services are very useful in
an enterprise where one might know what he wants, may not know what that
resource is named. (like, "give me a list of printers in the 2nd floor").
Any directory service can choose to publish itself as an Active Directory, so that a
common querying mechanism can be used. At this point the following products
support Active Directory:

1. Microsoft Exchange Server: Allows queries for email ids, names and a
number of other attributes of people or groups across an enterprise.
2. Microsoft Site Server: Stores the list of users as an Active Directory.
3. Microsoft Windows NT: This gives you uniform access to users (earlier
through User Manager for Domains), services (earlier through service
manager) and network resources (computers, printers etc.)

Active Directory also provides bridges to access other similar directory services, like
LDAP, NDS (Novell Directory Services) etc.
Active Directory is also an integral part of Windows 2000. In a large organization,
Windows NT server has been used as a Primary or Backup Domain Controller, but it
was difficult to integrate many such controllers to be able to provide security and
privileges across the organization. Active Directory makes it simpler by allowing you
to structure your organization into units which seamlessly (or so they say) integrate
with each other. Which also means lesser problems when you expand, add more
servers, more users etc.
To know more about how you can use Active Directory effectively in your
organization, please visit
http://www.microsoft.com/windows2000/library/technologies/activedirectory/defaul
t.asp
Here's a list of places ADSI would be best used in:

1. User/Groups:Adding/Deleting users , Finding out if a user is a member of a


group.
2. Changing a user's password
3. Starting and stopping services.
4. Getting printer information (jobs in print queue etc.)
5. Adding/Deleting web or FTP sites from Microsoft Internet Information server.
6. Getting user attributes from Microsoft Exchange Server, like email ids,
Addresses, web directories etc.

These are just a few applications, and I'm sure there will be more as time goes on.

Prerequisites – What do you need to know?


This presentation assumes readers know COM (Component Object Model) and a
working knowledge of using COM in Delphi.

What is ADSI?
Directory Services and Namespaces
There could be many objects within a namespace (users in an email server, files in
a file system) which need to be uniquely identifiable by name. But you might have
a user in the email server with the same name as a file in the file system:and they
have no idea about each others existance. To maintain uniqueness, object names
are prefixed with the name of the Directory Service they belong to. This name
identifies a "namespace", with a namespace identifier like "WinNT:", "LDAP:" etc.
(The ":" means that it's a namespace, and therefore, a directory service)

Object names are prefixed by the namespace identifier, and "//".


Note:This has analogies in the Internet, where you'd have Web pages identified by
"http://..." and files on FTP servers by "ftp://..." etc.
ADSI in a nutshell
As Microsoft puts it, “ADSI is a set of COM programming interfaces that will make it
easy for customers and Independent Software Vendors (ISVs) to build applications
that register with, access, and manage multiple directory services with a single set
of well-defined interfaces” (Ref.1) Active Directory Service Interfaces abstract the
capabilities of individual directory services: which means you, as a developer, could
access a file system the same way you access an email server or any other service
that supports ADSI.
ADSI objects are Component Object Model (COM) Objects. You needn’t learn
a new API for ADSI programming. You can develop for ADSI using simple
Automation concepts. All ADSI objects support (and must support) IDispatch, so
you can choose to use Late Binding or Early Binding. (Delphi supports both, quite
magnificently) Here’s a small example of how to create a user on Windows NT 4.0
using Early Binding.

var
Container : IADsContainer;
NewObject : IADs;
User : IADsUser;
hr : HREsult;
begin
// COM must be initialized
CoInitialize(nil);

// Bind to the container.


hr := ADsGetObject('WinNT://YOURDOMAIN',IADsContainer,Container);
if Failed(hr) then exit;
// Create the new Active Directory Service Interfaces User object.
NewObject := Container.Create('User','ActiveDirectoryUser') as IADs;

// Get the IADsUser interface from the user object.


NewObject.QueryInterface(IID_IADsUser, User);

// Set the password.


User.SetPassword('Borland');

// Complete the operation to create the object.


User.SetInfo;

// Cleanup.
Container._Release;
NewObject._Release;
User._Release;
CoUninitialize;
end;

Note: The ADsGetObject function is declared in AdsHlp.pas that is included with


this article. The interface definitions are imported from ActiveDS.tlb in the
WinNT/System32 folder. You will need to install ADSI 2.5 from
http://www.microsoft.com/ntserver/nts/downloads/other/ADSI25/default.asp.
I will explain the architecture in more detail in the Architecture section. Active
Directory Service Interfaces can be used easily in Delphi, though all the examples
and support in the http://www.microsoft.com/adsi are in Visual Basic or C++ code.
With this paper, you will find all the translations of the header files, some samples
and some new Delphi translations. (A copy will be maintained at
http://www.agnisoft.com/adsi)
A Directory Service Provider is a module that gives a user access to a certain
directory service. For instance, we were able to add a user to the Windows NT user
manager because Microsoft has written an ADSI provider for the user manager.

This doesn't sound very great, you might say. What's the difference between doing
this and using native Windows NT calls to add users? First, this is COM based so if
Microsoft decides to change the entire implementation of the user architecture,
your applications are safe, because there will still be an ADSI provider supporting
the same interfaces. (Note: this kind of thing might not be about to happen.)
Second, consider your gains in extensibility. You can now add a user on a Netware
Server using very similar code, except you'd have to use the ADSI provider for
Netware. As we will see later, the code will follow a similar pattern for doing
different activities: creating a web site, adding an email user etc.
Take a look at the next section for more benefits.

Why should you use ADSI?

Feature Benefit

Open Any directory provider can


implement an Active Directory
Service Interfaces provider; users
can easily move to a different
provider of the same service with a
minimum rewrite.

Security ADSI supports both Authentication


and Authorization programming
model - You can give even role
based security for your applications.

Simple As you will see, the COM model is


Programming very easy to understand. The model
Model remains standard for all providers:
there's no need to understand
vendor specific APIs.

Automation Any Automation Controller (for


Server example, Delphi, Visual Basic,
C/C++ and others) can be used to
develop directory service
applications. Administrators and
developers can use the tools they
already know.
Functionally Rich ISVs and sophisticated end users can
develop serious applications using
the same Active Directory Service
Interfaces models that are used for
simple scripted administrative
applications.

Extensible Directory providers, ISVs, and end


users can extend Active Directory
Service Interfaces with new objects
and functions to add value or meet
unique needs.

The Architecture of ADSI


This section deals with the core concepts of ADSI. There will be
a description of the COM object model and
an introduction to the various interfaces

Overview
Most directory services are hierarchical in nature and thus lend themselves to a
hierarchical object model. ADSI abstracts this concept by defining Container
Interfaces and leaf interfaces. A container object (that implements a Container
Interface) will contain zero or more ADSI objects - which could be other containers
or leaf objects. As I've said before, access to directory services is through ADSI
providers - so each provider is identified by a unique namespace identifier. A
provider implements a Namespace object which is a COM Object that is a one-
stop-shop: you can access any object in the namespace through this object.

These namespace objects are stored in an Active Directory Namespace Container


object which is identified by the name "ADS:". (See Figure).
Each Namespace object is itself a container - it contains the root nodes of the
directory service objects. Every container object and leaf object support a common
set of methods - so that users can interact with it uniformly. These common
methods are part of the IADs interface for all nodes, and IADsContainer interface
for container nodes.

These common methods do not expose all the functionalities of a provider - simply
because the domain of a "directory service provider" is too large to be able to
abstract everything. To allow providers to extend functionality, ADSI supplies a
schema model that I will describe later.

COM Object Model


There are many ADSI Interfaces that have been defined for specific purposes. Here
is a list:

IADs Object Identification


Fundamental interface required on all ADSI objects. You use this
interface to get and set properties.
IADsContainer Object Lifetime Management and Detection
Fundamental interface to be supported on all ADSI container
objects. Manages object creation, deletion, copying and moving,
binding, and enumeration.
IADsPropertyList Object Property Management
Manages an objects properties in the property cache. You can
use this to get and set properties. (Alternatively from IADs)
IDirectoryObject Direct Object Access
Low-level object access for clients that do not want to use
Automation (Early binding) . Really useful when you want to
get/set many properties in one call, instead of using multiple
IADs.Get or IADs.Set calls..
IUnknown COM Object Management
Required on all COM objects.
IDispatch Type Library Information and Method Invocation
Required on all Automation objects. ADSI Objects must support
this interface.

As an analogy, consider any Delphi application. There's a global object called


Screen that contains information about all the forms created(Screen.Forms). Each
form has a set of standard properties (Name, Tag for example).

Each form could contain many components in it, each of which has the standard
properties (Name, Tag) at least. So a Form is analogous to a "container" in ADSI.
In congruence, Screen is also a container.

Taking this further, a "Form" is a namespace - Any object in this namespace is


derived from TForm and thus supports everything that TForm does. One more
thing: ADSI requires that any object has a unique name: if we assume that all
forms had unique names (which they usually will), then I could identify any object
(Form ) by using its name. If I had to register this globally - I would prefix the
name with "Form:". (Form:MainForm for instance). So "Form:" is handled by the
Screen object which figures out where "Mainform" is. (You could have other
namespaces handled by other containers)

To translate this to ADSI, we would have to have TForm support :


IADs (All ADSI objects)
IADsContainer (All ADSI Container objects)

All components (hosted on TForms) should support


IADs ((All ADSI objects)

TScreen should support


IADs (All ADSI objects)
IADsContainer (All ADSI Container objects)
IADsOpenDSObject (All ADSI Namespace container objects)

(This is only an example to demonstrate the ADSI object model. It might not be the
best way to have your application support ADSI.)
If this was implemented, you can create any form by calling
Screen.OpenDSObject('Form:MainForm');. With ADSI, there are libraries
present so that you can open an object directly, given its path. You don't need to
create the namespace container in order to create an object. A few functions here
are:
ADsGetObject(Path, Interfacename, Object) - returns an instance of the object
who's name is Path. To avoid round trips with QueryInterface, (See Effective COM
by Don Box et. al) the second parameter is an Interface ID that determines which
interface will be returned.
ADsOpenObject - Similar to ADsGetObject, except you can log on using a
different identity to get the parameters. The security model in ADSI works with NT
User security, so you can have role based security work for you.
ADsBuildEnumerator, ADsEnumerateNext, ADsFreeEnumerator - Helper
functions for the IEnumVARIANT interface, which allows Visual Basic developers
to use the for each syntax.
Using ADSI in Delphi
In this section I will talk about how you can use ADSI in Delphi. I've used a number
of samples from the Windows Platform SDK as a reference. If you take a look at
this, most examples you will find will use late binding : Visual Basic code or
VBScript/ASP code. I'll use a combination of Late and Early Binding - Delphi can use
both - to demonstrate various features.

Binding to an ADSI object and enumeration


Binding string
A directory may contain a large number of items. Each item must be uniquely
identifiable. ADsPath is a property available on any ADSI object which uniquely
identifies it, both on a particular provider and across providers. Each provider
corresponds to a namespace: Consider a few ADSI providers that ship with ADSI.
1. WinNT: - The Windows NT provider for Windows NT 4.0 (and Windows 2000)
domain controllers.
2. LDAP: - For communication with LDAP servers like Exchange Server 5.5.
3. NDS: - Provider for Netware Directory Services
(The initial elements of the ADsPath string are the namespace identifier (progID) of
the ADSI provider, followed by "//", followed by whatever syntax is dictated by the
provider namespace)

With this information at hand, lets consider a few ADsPaths that could identify
objects.

1. WinNT://MyDomain/Adminstrator - identifies the Administrator user on


MyDomain, a Windows NT domain.
2.
2. LDAP://EXCHSVR/CN=info,DC=AGNISOFT,DC=COM - the
info@agnisoft.com account on EXCHSVR

To find all the providers installed on your machine, you can enumerate the
namespaces in "ADs:". Here is some Visual Basic code that does it:

Set x = GetObject("ADs:")
For Each provider In x
provider.Name
Next

Since we do not have the "For Each" syntax in Delphi, I will use the helper functions
provided by ADSI to enumerate containers.

var x : IADsContainer;
e : IEnumVariant;
hr, i : integer;
varArr : OleVariant;
lNumElements : ULONG;
item : IADs;
begin
hr := ADsGetObject( 'ADs:', IID_IADsContainer, x); // bind to the object
hr := ADsBuildEnumerator(x,e); // start enumerating
while SUCCEEDED(hr) do
begin
// get the next contained object
hr := ADsEnumerateNext(e,1,varArr,lNumElements);
if (lNumElements<=0) then // are we done?
break;

//varArr contains an IDispatch pointer to the contained object.


IDispatch(varArr).QueryInterface(IADs, item) ;
ShowMessage(item.ADsPath);
end;
if e<>nil then
hr := ADsFreeEnumerator(e);
end;

The binding code is in ADsGetObject( 'ADs:', IID_IADsContainer, x);


This code is a bit complex and troublesome to do everytime. I've added a funtion
that allows easy enumeration.

procedure ADsEnumerateObjects(Container : IADsContainer;


Func : TADsEnumCallback);
var
e : IEnumVARIANT;
varArr : OleVariant;
lNumElements : ULong;
obj : IADs;
hr : integer;
begin
hr := ADsBuildEnumerator(Container,e);
while(Succeeded(Hr)) do
begin
hr := ADsEnumerateNext(e,1,
varArr ,lNumElements);

if (lNumElements=0) then
break;

IDispatch(varArr).QueryInterface(IADs, obj);
if obj<>nil then
begin
Func(obj);
end;
varArr := NULL;
end;
// do not call ADsFreeEnumerator(e); since e will be released
by Delphi
end;

You can use this in a Delphi form like so:

procedure TForm1.Button2Click(Sender: TObject);


begin
ADsEnumerateObjects('ADs:', Callback);
end;

procedure TForm1.Callback(Obj: IADs);


var
s : string;
begin
ShowMessage(Obj.name);
end;

You may also use ADsOpenObject for binding, the only difference being that you
can choose to bind as a different user instead.

hr := ADsOpenObject('IIS://localhost', 'Admin','Admin',
ADS_SECURE_AUTHENTICATION , IADs, obj );

Connection Caching
ADSI caches connections to servers - on all objects not yet destroyed. So, if you
will bind to many objects, you can create a dummy object that binds to some object
on the server, perform your set of operations using a different set of objects and
finally, released the dummy object.

Accessing properties.
Once Binding is established, you will want to get or set properties of the object. The
steps involved are:

a) Bind to the object


b) Set properties
c) Call SetInfo
d) Release the object

(b) and (c) are required because ADSI caches the properties on the client side and
updates the server only when you call SetInfo. (Saves a lot of network traffic this
way).

Here's an example.

// Late Binding
var obj : Variant;
begin
obj := ADsHlp.GetObject('WinNT://AGNISOFT/Deepak'); // bind to the object
obj.Put( 'FullName', 'Deepak'); // set properties
obj.SetInfo;
obj := NULL; // release the object
end;

Note: In 'WinNT://AGNISOFT/Deepak', AGNISOFT is the Active Directory Domain


and Deepak is the user name. FullName is a property of every user.(earlier
accessible using User Manager for Domains)

Properties could also have multiple values, like additional phone numbers. You
would use the PutEx and GetEx functions to set or access these properties.

var obj : IAds;


begin
ADsGetObject('LDAP://CN=deepak,CN=Users,DC=AGNISOFT,DC=COM',
IAds, Obj);
// assume there was '111-1111' and '222-2222'
obj.PutEx(ADS_PROPERTY_APPEND, 'otherHomePhone',
VarArrayOf(['333-3333']) );
obj.SetInfo; //now there will be '111-1111',
//'222-2222' and '333-3333'

obj.PutEx(ADS_PROPERTY_DELETE, 'otherHomePhone',
VarArrayOf(['111-1111', '222-2222']));
obj.SetInfo; //now there will be only '333-3333'

obj.PutEx(ADS_PROPERTY_UPDATE, 'otherHomePhone',
VarArrayOf(['888-8888','999-9999']));
obj.SetInfo; //now there will be '888-8888'
//and '999-9999'

obj.PutEx(ADS_PROPERTY_CLEAR, 'otherHomePhone', NULL);


obj.SetInfo;//now there will be nothing
end;

Searching Active Directory

1. Using ADO

Active Data Objects is Microsoft's latest Database Access solution. It works with
OLE DB providers, and ADSI comes with a provider named "ADsDSOObject". In
Delphi, all you need to do is to drop a TADOConnection and set its provider to
"ADsDSOObject". Then, drop a TADOQuery, connect it to the TADOConnection
and query ADSI - this is a method for simple searching.
Here's how I've got all the users, their user names and their last names from my
machine's Active Directory.

The SQL syntax is :

SELECT [ALL] select-list FROM 'ADsPath' [WHERE search-condition]


[ORDER BY sort-list]

The Query I have used in the form is

SELECT AdsPath, CN, SN FROM 'LDAP://DC=AGNISOFT,DC=COM' WHERE


objectClass='user' ORDER BY sn

The ADSI provider is read-only at this time. Microsoft plans to ship a read-write
provider in future. To modify data, you can:

a. Get the ADsPath from the Query


b. Use ADsGetObject to bind to the AdsPath
c. Get/Set properties

At this point, only the LDAP and the NDS providers support searching using ADO.
You cannot use ADO to search for user in a Windows NT (Or 2000) domain.

2. Using COM Interfaces - IDirectorySearch

If you don't want to use ADO, you can use the IDirectorySearch Interface. The
steps involved are:

a. Bind to the object


b. Call QueryInterface on the object for IdirectorySearch
c. Call IDirectorySearch.ExecuteSearch, passing the search query and get a
search handle
d. Call IDirectorySearch.GetNextRow and for each row, call
IDirectorySearch.GetColumn(columnName) to get the columns.

// bind to the object


AdsGetObject(edtObjectPath.Text, IDirectorySearch, search);
try
// set parameters
opt[0].dwSearchPref := ADS_SEARCHPREF_SEARCH_SCOPE;
opt[0].vValue.dwType := ADSTYPE_INTEGER;
opt[0].vValue.Integer := ADS_SCOPE_SUBTREE;
search.SetSearchPreference(@opt[0],1);
// search
p[0] := StringToOleStr('Name');
search.ExecuteSearch('(objectCategory=Group)',@p[0], 1, ptrResult);
// get records
hr := search.GetNextRow(ptrResult);
while (hr <> S_ADS_NOMORE_ROWS) do
begin
hr := search.GetColumn(ptrResult, p[0],col);
if Succeeded(hr) then
begin
ShowMessage(col.pAdsvalues^.CaseIgnoreString);
search.FreeColumn(col);
end;
Hr := search.GetNextRow(ptrResult);
end;
search.CloseSearchHandle(ptrResult);
finally // free memory
search._Release;
end;

Security
ADSI supports Authentication using a login name and a password. If you use
ADsGetObject then the user currently logged on is used to authenticate the login.
You can specify a user name by using ADsOpenObject.
Example:

hr := ADsOpenObject('IIS://localhost', 'testuser','pwd',
ADS_SECURE_AUTHENTICATION , IADs, obj );

ADS_SECURE_AUTHENTICATION specifies that Kerberos or NTLM is used to


authenticate the password. You can even specify password encryption (if your
server supports it).

Role based security to properties - You might need to secure ADSI itself -
control who can read/write certain properties etc. The properties of ADSI are
controlled by Access Control Entries (ACEs) in Windows 2000. You can create an
ACE and add it to the Discretionary Access Control List (DACL) of the
SecurityDescriptor of an object. ( Use obj.Get('ntSecurityDescriptor') to get the
security descriptor) The ACE can allow or deny access to one or all properties of an
object. The security is inherited - so if you change the access control list of a
container, all its descendants will inherit it.

Supporting ADSI
In the Windows 2000 application specification, it is recommended that you use
ADSI in your applications in specific instances.

1. If your application will use a known directory service, you must use ADSI to get
or set properties in the Active Directory service. For instance, if you need to add
or modify a user, you must use ADSI to do so.

2. In a client-server or multi-tier application, you are suggested to publish server


attributes in the Active Directory. Which means that the client applications
should be able to use ADSI to get all the information about the server
application.

To do this, you need to be able to extend ADSI. I'll talk about two ways you could
extend ADSI. But first, lets see how the ADSI Schema works.

ADSI Schema
The predefined ADSI objects have very few properties: these may not be enough
for a particular provider. So, ADSI allows your provider to extend the basic interface
by adding properties to objects within your namespace. The schema objects are
special ADSI objects : They allow you to :

Browse the definition of objects


Extend the definition of objects

The schema object contains definitions of :

1. What kind of objects will be present (eg. in WinNT:, you have Users, Groups,
Services etc),
2. What properties these objects will have (For Users in WinNT:, FullName,
Description etc. are properties) and which properties are mandatory and which
are optional.
3. The syntax of these properties (FullName is a String, UserFlags is an
integer etc.)

(1) above is represented by a Class Object.


(2) by a Property Object
(3) by a Syntax object
These three are placed in the Active Directory as follows:

To browse the schema of an object, you must:

1. Get the ADsPath of the schema - The IADs.Get_Schema call does the job
2. create the schema object and browse it.

Here's an example that gets the list of Mandatory and optional properties of all
Users in the LDAP namespace.

var obj : IAds;


s : WideString;
cls : IADsClass;
cont : IADsContainer;
i : integer;
begin
AdsGetObject('LDAP://CN=Users,DC=AGNISOFT,DC=COM', IADs, obj );
s := obj.Get_Schema;
AdsGetObject(s, IADsClass, cls );
if VarIsArray(cls.MandatoryProperties) then
begin
for i := VarArrayLowBound(cls.MandatoryProperties,1) to
VarArrayHighBound(cls.MandatoryProperties,1) do
begin
s := cls.MandatoryProperties[i];
ShowMessage('MANDATORY:' + s);
end;
end;
if VarIsArray(cls.OptionalProperties) then
begin
for i := VarArrayLowBound(cls.OptionalProperties,1) to
VarArrayHighBound(cls.OptionalProperties,1) do
begin
s := cls.OptionalProperties[i];
ShowMessage('Optional:' + s);
end;
end;

Here's a small application screenshot that does this:

ADSI Extensions
ISVs or corporate developers can extend the object semantics by adding interfaces
to the existing ADSI interfaces. ADSI combines the COM Aggregation model and
directory technology to bring a powerful extension model. You can thus support
more functions than provided by any of the standard ADSI interfaces.
Anyone that needs to extend ADSI can do so by writing an extension - which is
nothing but a COM object. A backup vendor, for instance, could write an extension
that supports "Backup" and "Restore" functions that extend the IADsComputer
interface - This would be useful for administrator to write scripts for automatically
backing up computers to a tape drive.

Writing Providers
To provide access to a totally new namespace, you must implement an ADSI
provider. An ADSI provider could just be a single COM DLL containing many COM
classes that you implement. Any provider needs to support:
1. A top level namespace object that supports IADsOpenDSObject and
IParseDisplayName. (And of course, IADs) YOu will need to parse any
AdsPath given and detect syntax errors, if any.
2. A few other interfaces-IADsPropertyList, IADsPropertyEntry,
IADsPropertyValue, IDirectoryObject. (I won't go into detail on these
interfaces) IDispatch - this is very important because you must support
late binding.
3. IADsContainer on all object containers.
4. IEnumVariant on all enumeratable objects (containers, collections).- You
need to support those Visual Basic and VBScript users using for each.
5. A schema class container object with appropriate class, syntax and
property objects for your namespace.
This seems like quite a big task, and though there is a sample in the Windows 2000
platform SDK, it isn't quite easy. I have written a sample in order to make it easier
for you to begin - it's available along with this article. Please check
www.agnisoft.com/adsi for updates.

Conclusion.
Windows 2000 supports Active Directory natively-there are four providers
(WinNT:, LDAP:, IIS:, NDS:) already present in the Windows 2000 server install. At
the time of writing this paper, the other applications supporting ADSI are Microsoft
Exchange Server 5.5 and Microsoft Site Server 3.0. Many third-party products are
coming out with ADSI support.
There will be a lot of focus on ADSI in the future - you will see a number of
components that will give you easier access to ADSI objects. You can begin to
perform administrative tasks using ADSI, and identify areas of your applications
where it will be better to use ADSI rather than a native Directory provider.
Active Directory is not something to be ignored because it forms a part of the most
recent operating system that you will support - Windows 2000.

References
1. ADSI White Papers - part of the Windows Platform SDK
2. Windows 2000 Developers Readiness Kit.
3. Newsgroups : (at msnews.microsoft.com)
- microsoft.public.adsi.general
- microsoft.public.platformsdk.adsi

You might also like