A Sample ADSI Application


The best way to learn about using ADSI to program with the Exchange Server directory is to examine a sample application. I developed one that demonstrates how to create custom recipients, query distribution lists, and query for recipient directory information such as user 's names , addresses, and phone numbers .

Setting Up the Application

Before you can install the application, you must have a Windows 2000 Server and a client with the software listed in Table 13-1 installed.

Table 13-1: Installation Requirements for the ADSI Application

Minimum Software Requirements

Installation Notes

Exchange Server 2000 or later

 

Microsoft Internet Information Services (IIS) 5.0 or later with ASP

 

ADSI 2.0 or later

Active Directory Client Extensions (ADSI 2.5) is available as a free download from http://www.microsoft.com/adsi. Windows 2000 and 2003 install ADSI 2.5 by default.

Microsoft ActiveX Data Objects (ADO)

IIS 5.0 installs ADO by default. Visual Basic 6.0 installs ADO 2.0. For more information on ADO, go to http:/www.microsoft.com/data/ .

For the client:

Microsoft Internet Explorer 4.0 or later

 

You can run the client software on the same machine or on a separate machine.

To install the ADSI application, first copy the ADSI folder from the companion content to the Web server where you want to run the application. Start the IIS administration program. Create a virtual directory that points to the location where you copied the ADSI files, and name the virtual directory adsi . Be sure to turn off anonymous access to the virtual directory and enable either NTLM or Basic authentication. You should be able to use the following URL to access your ADSI application: http://<yourservername>/adsi .

The first page displayed in the ADSI application is the logon page, as shown in Figure 13-1. Once a user enters logon information and verifies the dynamically generated Exchange Server information, the application presents a menu of available administrative options for the user, as shown in Figure 13-2.

click to expand
Figure 13-1: The logon page for the ADSI application
click to expand
Figure 13-2: The main menu of the ADSI application

Now let's step through the actual code that makes up these menu items and see how to use the ADSI object library with an Exchange Server directory.

Logging On to ADSI

The most common operation in the code for the menu items is the object binding code for ADSI. This binding code is dispersed throughout all the code modules in the application rather than being centralized and performed only once. This makes it easier for you to browse the code and understand exactly what is happening.

To bind successfully to an object in the Exchange Server directory using ADSI when you don't want to pass a path directly to the GetObject function, you must use the GetObject method to set an object variable to the ADSI library and then call the OpenDSObject method. The OpenDSObject method takes four parameters:

  • AdsPath    The path of the object you want to bind to. You saw how to create this path earlier in the chapter.

  • The Windows username     This is used to attempt authentication against the directory service.

  • The password for the Windows username you specify    

  • A flag that specifies the binding option to use     The &H00000001 flag specifies use of secure authentication, &H00000010 specifies use of encryption, and &H00000200 specifies use of server binding if you pass the name of a server in your LDAP path instead of using rootDSE . There are also other flags you can use in ADSI. See the Platform SDK for information about them.

Depending on the provider used, the flags that specify the binding option might or might not be supported. On the LDAP provider, if you set the secure authentication and the encryption flags and pass in a user name and a password, ADSI will perform a simple bind over Secure Sockets Layer (SSL) sessions, which is a secure authentication over a secure channel. The sample application does not use OpenDSObject for most of its operations; instead, it uses GetObject and passes the directory path in GetObject . If you use OpenDSObject and do not use either of those flags, a will be passed in as the value for the final parameter to indicate that no encryption and no secure authentication should be used.

The following code shows how to set an object variable to the LDAP provider and log on using the OpenDSObject method, as well as how to use the GetObject method with a path:

 Set oIADs = GetObject("LDAP:") oIADs.OpenDSObject(  AdsPath  ,  UserName  ,  Password  , 0) Set oIADs2 = GetObject("LDAP://servername") 

Querying for Information from an Existing Mailbox

The ADSI application also shows how to query for information from an existing Exchange Server mailbox. The user interface, shown in Figure 13-3, allows the user to type the first name of the user to find the mailbox.

click to expand
Figure 13-3: The user can type the first name of the user in the directory to locate the mailbox.

After the user types a name, the application uses ADO to query the directory service using LDAP. You might wonder why ADO is used rather than the OpenDSObject method you saw earlier. The reason is that if you use the OpenDSObject method, the user must know the exact name of the desired object in the directory. ADO is more forgiving ; the user can simply type a portion of the first name. Also, users often do not know the alias of users they are querying, so forcing them to type aliases does not make sense. The code to create the ADO object and perform the query is shown here:

 bstrSearchCriteria = Request.Form("UserName") bstrServer = Session("Server") 'Create an ADO object Set ADOconn = CreateObject("ADODB.Connection") If Err.Number = 0 Then     ADOconn.Provider = "ADSDSOObject"     ADOconn.Open "ADs Provider"     'Create a query using ADO to find all users across all containers     bstrADOQueryString = "<LDAP://" + bstrServer & _         ">;(&(objectClass=organizationalPerson)(cn=" & _         bstrSearchCriteria & "*));cn,adspath;subtree"     Set objRS = ADOconn.Execute(bstrADOQueryString)     If Err.Number = 0 Then         If objRS.RecordCount > 0 Then %>             <p>Please select one of the following names from the             list of names.</p>             <p><em><strong>Returned Names:</strong></em></p>             <SELECT NAME='MailboxPath'>             <%             'Builds the select control of the queried records             While Not objRS.EOF                 bstrSelectStatement = bstrSelectStatement & _                     "<OPTION VALUE='" & objRS.Fields(iCN).Value & _                     "'>" & objRS.Fields(iADSPATH)                 objRS.MoveNext             Wend             Response.Write bstrSelectStatement & "</SELECT>"         Else %>             <B><I>No entries match your search criteria.             Try again using a different value.</I></B>             <%         End If     Else         If Hex(Err.Number) = 80070044 Then             Response.Write "<FONT FACE='Arial, Helvetica' " & _                 "SIZE=2>Error " & Hex(Err.Number) & _                 ":  Too many entries match your search " & _                 "criteria!</FONT>"             Err.Clear         Else         %>         <SCRIPT LANGUAGE="JavaScript">             alert("Error Number: <%=Hex(Err.Number)%> \n                 Error Description: <%=Err.Description%>")             history.back()         </SCRIPT>         <%         Err.Clear         End If     End If Else     %>     <SCRIPT LANGUAGE="JavaScript">         alert("Error Number: <%=Hex(Err.Number)%> \nError Description:             <%=Err.Description%>")         history.back()     </SCRIPT>     <%     Err.Clear End If %> 

This code creates an ADO Connection object and sets the Provider property to ADSDSOObject , which specifies the LDAP provider for ADSI. You can specify any string for the connection string argument to the Open method of the ADO Connection object. In this case, the application specifies ADs Provider as the argument. The code then creates an LDAP query, which consists of four elements separated by semicolons. This is the format:

 <LDAP://  server  /  adsidn  >;  ldapfilter;   attributescsv;   scope  

The server argument specifies the name or the IP address of the server where the directory is hosted. The adsidn argument specifies the distinguished name in the directory where we want to start our query. You should pass in a correctly formed path, which you saw how to create earlier in the chapter. The filter parameter specifies the LDAP filter string to use. In this case, the LDAP filter states that the object class must be organizationalPerson and the name of the object must match the letters typed by the user. The next argument, attributescsv , is a list of attribute names, separated by commas, that you want returned for each row in the recordset. In our application, we want the name of the person and the AdsPath to the object that corresponds to that person returned so we can place this information in the HTML form, as shown in Figure 13-4. The final argument, scope , informs the directory service how deeply in the hierarchy to search for the information being queried. The scope argument can be one of three values: base , onelevel , or subtree . We want to query for all mailboxes that match our specified criteria across all recipient containers in the directory, so we specified subtree for this argument. The subtree argument causes the directory service to search for the information in every subtree under the starting object. The base argument searches only the currently specified object, and onelevel searches one level below the current object in the hierarchy.

click to expand
Figure 13-4: After the query runs, the HTML form is populated with the corresponding records so a user can select the person she wants more information about.

If the query successfully returns records that match the filter, the code uses the standard ADO methods to scroll through the recordset and place the records in the HTML form.

After the user selects the name of the person she wants more information about in the HTML form, the application opens the directory object for that person and retrieves information such as the address, phone number, manager, and direct reports . This information is represented using a DHTML tabbed dialog box in the browser, as shown in Figure 13-5.

click to expand
Figure 13-5: The tabbed dialog box that shows the directory information for a specific person

The next section of code retrieves the information about the specific person from the directory. I intentionally left out some of the DHTML code from the listing to highlight how ADSI is used in the code. Also, only a portion of the ADSI code is shown here because the structure of the code throughout this part of the application is similar. Only the specific properties retrieved from the directory using ADSI are different. The full code is included with the companion content.

 On Error Resume Next      If Request.QueryString("Path") = "" Then     bstrMailboxPath = Request.Form("MailboxPath") Else     bstrMailboxPath = Request.Querystring("Path") End If bstrServer = Session("Server")      Set objIADs = GetObject(bstrMailboxPath)    <TR> <TD VALIGN=MIDDLE ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2> First Name:</TD> <TD VALIGN=TOP><FONT FACE="Arial, Helvetica" SIZE=2><B><%=Server.HTMLEn code(objIADs.Get("givenName"))%></B></FONT> </TD>      <TD VALIGN=MIDDLE ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2> Initials:</TD> <TD VALIGN=TOP><FONT FACE="Arial, Helvetica" SIZE=2><B><%=Server.HTMLEn code(objIADs.Get("initials"))%></B></FONT> </TD>      <TD VALIGN=MIDDLE ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2> Last Name:</TD> <TD VALIGN=TOP><FONT FACE="Arial, Helvetica" SIZE=2><B><%=Server.HTMLEn code(objIADs.Get("sn"))%></B></FONT></TD> </TR>      <TR> <TD VALIGN=MIDDLE ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2> Display Name:</TD> <TD VALIGN=TOP><FONT FACE="Arial, Helvetica" SIZE=2><B><%=Server.HTMLEn code(objIADs.Get("cn"))%></B></FONT></TD> <TD>&nbsp;</TD> <TD>&nbsp;</TD> <TD VALIGN=MIDDLE ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2> Alias:</TD> <TD VALIGN=TOP><FONT FACE="Arial, Helvetica" SIZE=2><B><%=Server.HTMLEn code(objIADs.Get("mailNickname"))%></B></FONT> </TD> </TR>      <TR> <td width="100%" colspan="10">&nbsp;<hr> </TD> </TR>      <TR> <TD VALIGN=TOP ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2> Address:</FONT></TD> <TD VALIGN=TOP><FONT FACE="Arial, Helvetica" SIZE=2><B><%=Server.HTMLEn code(objIADs.Get("streetAddress"))%></B></FONT> </TD>      <TD>&nbsp;</TD> <TD>&nbsp;</TD>      <TD ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2>Title:</FONT></TD> <TD ALIGN=LEFT><FONT FACE="Arial, Helvetica" SIZE=2><B><%=Server.HTMLEncode(objIADs.Get("title"))%></B></FONT></TD> </TR>      <TR> <TD>&nbsp;</TD> <TD>&nbsp;</TD> <TD>&nbsp;</TD> <TD>&nbsp;</TD>      <TD ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2>Company:</FONT> </TD> <TD><FONT FACE="Arial, Helvetica" SIZE=2><B><%=Server.HTMLEn code(objIADs.Get("Company"))%></B></FONT> </TD> </TR>      <TR><TD ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2>City:</FONT> </TD> <TD VALIGN=TOP><FONT FACE="Arial, Helvetica" SIZE=2><B><%=Server.HTMLEn code(objIADs.Get("l"))%></B></FONT></TD>      <TD>&nbsp;</TD> <TD>&nbsp;</TD>      <TD ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2>Department:</FONT> </TD> <TD><FONT FACE="Arial, Helvetica" SIZE=2><B><%=Server.HTMLEn code(objIADs.Get("department"))%></B></FONT> </TD>      </TR>      <TR> <TD ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2>State:</FONT></TD> <TD><FONT FACE="Arial, Helvetica" SIZE=2><B> <%=Server.HTMLEncode(objIADs.Get("st"))%></B></FONT></TD>      <TD>&nbsp;</TD> <TD>&nbsp;</TD>      <TD ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2>Office:</FONT></TD> <TD><FONT FACE="Arial, Helvetica" SIZE=2><B> <%=Server.HTMLEncode(objIADs.Get("physicalDeliveryOfficeName"))%> </B></FONT></TD> </TR>      <TR> <TD ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2>Zip Code:</FONT> </TD> <TD><FONT FACE="Arial, Helvetica" SIZE=2><B> <%=Server.HTMLEncode(objIADs.Get("postalCode"))%></B></FONT></TD>      <TD>&nbsp;</TD> <TD>&nbsp;</TD>      <TD ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2>Assistant:</FONT> </TD> <TD><FONT FACE="Arial, Helvetica" SIZE=2><B> <%=Server.HTMLEncode(objIADs.Get("secretary"))%></B></FONT></TD> </TR>      <TR><TD ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2>Country:</FONT> </TD> <TD><FONT FACE="Arial, Helvetica" SIZE=2><B> <%=Server.HTMLEncode(objIADs.Get("co"))%></B></FONT></TD>      <TD>&nbsp;</TD> <TD>&nbsp;</TD>      <TD ALIGN=RIGHT><FONT FACE="Arial, Helvetica" SIZE=2>Phone:</FONT></TD> <TD><FONT FACE="Arial, Helvetica" SIZE=2><B> <%=Server.HTMLEncode(objIADs.Get("telephoneNumber"))%></B></FONT></TD> </TR> </TABLE> </DIV> 

The mailbox that the user wants to query is passed to the ASP page. Using the GetObject method, the code opens the mailbox in the Exchange Server directory and sets an object variable, objIADs , to that mailbox. Throughout much of the remaining code, the Get method of the objIADs object is used to retrieve specific attributes on the mailbox.

The most interesting pieces of code besides the code for retrieving attributes include those that retrieve the person's manager and direct reports from the directory. In the application, the manager's name is displayed as a hyperlink on the Organization tab so users can quickly look up the manager's directory information. The person's direct reports are also displayed as hyperlinks on the Organization tab so users can look at the direct report's directory information as well. Figure 13-6 shows a sample of these hyperlinks .

click to expand
Figure 13-6: The Organization tab for a queried mailbox displays the manager and direct reports as hyperlinks.

The following code implements the hyperlink functionality:

 <TABLE border=0> <TR> <TD ALIGN=LEFT NoWrap><FONT FACE="Arial, Helvetica" SIZE=2> Manager Name:</FONT></TD> <TR>&nbsp;</TR> <%     strManager = objIADs.Get("manager")     strManagerPath = "LDAP://" & Session("Server") & "/" & strManager     Set oIADsManager = GetObject(strManagerPath)     strManagercn = Server.HTMLEncode(oIADsManager.Get("cn")) %>     <TR> <TD><FONT FACE="Arial, Helvetica" SIZE=2><B> <A Href='MBINFOTABS.ASP?Path=<%=strManagerPath%>'><%=strManagercn%></A> </B></FONT></TD> </TR> <TR><TD>&nbsp;</TD></TR> <TR><TD ALIGN=LEFT><FONT FACE="Arial, Helvetica" SIZE=2>Direct Reports:</ FONT></TD></TR>      <%     Err.clear     strReports = objIADs.GetEx("directReports")     If lBound(strReports) <0 Then %>     <TR><TD><FONT FACE="Arial, Helvetica" SIZE=2><B>&nbsp;      No Direct Reports Found      </B></FONT></TD></TR> <%     Else         For i = LBound(strReports) To UBound(strReports)             'Get each DS object to return the friendly name             strDirectPath = "LDAP://" & Session("Server") & _                 "/" & strReports(i)             Set oIADsReports = GetObject(strDirectPath)             strReportscn = Server.HTMLEncode(oIADsReports.Get("cn")) %>             <TR><TD><FONT FACE="Arial, Helvetica" SIZE=2><B>             <img src="mailboxs.jpg" ALIGN="Middle">&nbsp;            <A Href='MBINFOTABS.ASP?Path=<%=strDirectPath%>'>                 <%=strReportscn%></A>             </B></FONT></TD></TR> <%         Next     End If     %> </TR> </TABLE> 

When you retrieve the manager property from the Exchange Server directory, the directory returns the distinguished name of the manager. To retrieve the display name of the manager, the code uses the distinguished name to create a full AdsPath to the directory object that corresponds to the manager. Then the code opens that object and retrieves the display name of the manager.

To retrieve the direct reports, the code uses the GetEx method in ADSI. (Recall that the reports attribute is a multivalued property. You must use GetEx when you retrieve multivalued properties from Active Directory.) The GetEx code returns an array of distinguished names for all of the person's direct reports. The code loops through each direct report in the array and displays as a hyperlink an image and the full name of each direct report.

Creating a Custom Recipient

Creating a custom recipient is straightforward. A custom recipient has contact as the object class, and you must set the targetAddress property of the custom recipient, which specifies the actual e-mail address of the recipient.

The following code creates a custom recipient using ADSI:

 On Error Resume Next Err.Clear smtp = Request.Form("SMTP") fn = Request.Form("FN") ln = Request.Form("LN") dn = Request.Form("DN") al = Request.Form("AL")      Set oIADs = GetObject("LDAP:") bstr1 = "LDAP://" + Session("Server") + "/CN=" + Session("CN") + _     "," + Session("DC") bstr2 = Session("bstr2") bstr3 = Session("bstr3")      Set oContainer = GetObject(bstr1) Set oIADs = oContainer.Create("contact", "cn=" + CStr(dn))      oIADs.Put "mail", CStr(SMTP) oIADs.Put "targetAddress", CStr(SMTP)      oIADs.Put "givenName", CStr(fn) oIADs.Put "sn", CStr(ln) oIADs.Put "displayName", CStr(dn) oIADs.SetInfo 

Displaying the Members of a Distribution List

The sample application allows you to display the members of a distribution list in an HTML table, as shown in Figure 13-7. This table is generated by using a For Each construct to scroll through the collection returned by the Members method of the IADsGroup interface. After retrieving the object that corresponds to each member, the code checks the object class and displays the correct identifier for each member, such as mailbox, distribution list, or custom recipient. Remember that distribution lists can hold different types of objects. The code that displays the members of a distribution list is shown here:

click to expand
Figure 13-7: An HTML table of the members in a specific distribution list
 <HTML> <HEAD> <TITLE>Display Users in a DL</TITLE> </HEAD> <BODY> <h1>The members of this DL are:</h1>      <hr>      <form METHOD="POST" NAME="INFO" ACTION=""> <input TYPE="button" VALUE="Back to Main Menu"   OnClick='window.location="menu.asp";'>   <input TYPE="button" VALUE="Select different container" OnClick='window.loca tion="logon.asp?diffcont=1";'> </FORM> <P> <TABLE BORDER=1 bgcolor="#79AA86"> <%      Dim oIADs Dim MyContainer Dim objRecipients Dim item On Error Resume Next Err.Clear strDLName = Request.Form ("DLSELECT")      Set oIADs = GetObject("LDAP:") bstr1 = strDLName bstr2 = Session("bstr2") bstr3 = Session("bstr3")      Set objDL = GetObject(bstr1)      Response.Write "<TR><TD><B>Class</TD><TD><B>Display Name</TD><TD><B>Alias</ TD><TD><B>Directory Name</TD></TR>"      For Each item In objDL.Members     Set objitem =  GetObject(item.ADSPath)     strClass = objitem.Get("class")     Select Case strClass         Case "organizationalPerson"             Response.Write "<TD>MailBox</TD><TD>" & objitem.Get("cn") & _                            "</TD><TD>" & objitem.Mail & "</TD><TD>" & _                            objitem.Name & "</TD></TR>"         Case "person"             Response.Write "<TD>Custom Recipient</TD><TD>" & _                            objitem.Get("cn") & "</TD><TD>" & _                            objitem.Get("mailNickname") & "</TD><TD>" & _                            objitem.Name & "</TD></TR>"         Case "group"             Response.Write "<TD>Distribution List</TD><TD>" & _                            objitem.Get("cn") & "</TD><TD>" & _                            objitem.Get("mailNickname") & "</TD><TD>" & _                            objitem.Name & "</TD></TR>"         Case Else             Response.Write "<TD>" & item.Class & "</TD><TD>" & _                            objitem.Get("cn") & "</TD><TD>" & _                            objitem.get("mailNickname") & "</TD><TD>" & _                            objitem.Name & "</TD></TR>"         End Select Next %> </TABLE> 
Note  

By default, Active Directory returns only 100 results, so you might want to increase the number of results returned for LDAP queries. If you are using ADO with the Active Directory OLEDB provider, you can do this by increasing the PageSize property.




Programming Microsoft Outlook and Microsoft Exchange 2003
Programming MicrosoftВ® OutlookВ® and Microsoft Exchange 2003, Third Edition (Pro-Developer)
ISBN: 0735614644
EAN: 2147483647
Year: 2003
Pages: 227
Authors: Thomas Rizzo

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net