Solved

Find user's Email address from asp page form with ADSI query

Posted on 2006-07-20
27
2,379 Views
Last Modified: 2008-01-09
We get this error when running this code in asp page. We are windows environment running Exchange 5.5.

Active Directory error '80040e37'

An invalid directory pathname was passed

/onlineforms/samples/Genifax/mnhtest.asp, line 40 (which is this line "Set oRS = oConn.Execute(strQuery)")

Can anyone tell us what to do to correct this?  Or another way to do it?  We need to get a user's Email address when they submit an ASP form (intranet only).

<%@ Language=VBScript %>
<%
      Response.Buffer = True
      Response.ExpiresAbsolute = Now() - 1
      Response.Expires = 0
      Response.CacheControl = "no-cache"

      Dim x
      Dim oSid
      Dim strSid
      Dim strUser
      Const ADS_SID_HEXSTRING = 1
                Const ADS_SID_WINNT_PATH = 5

      strUser = Request.ServerVariables("AUTH_USER")
      
      ' Switch the "\" to a "/" in the user name for later parsing.
      for x = 1 to len(strUser)
         if mid(strUser,x,1)="\" then
            strUser = left(strUser,x-1)+"/"+right(strUser,len(strUser)-x)
         end if
      next
      
        Set oSid = Server.CreateObject("ADSSID")             'From Platform SDK, adssecurity.dll,
        oSid.SetAs ADS_SID_WINNT_PATH, "WinNT://" + strUser       'get the user account SID.
        strSid = oSid.GetAs(ADS_SID_HEXSTRING)              'Convert to binary string.
        set oSid = Nothing

      '// Get ldap configuration
      strLDAPServerName = "MyExchangeServer"

      '// Create the query
      strQuery = "<LDAP://" + strLDAPServerName + ">;(&(objectClass=person)(Assoc-NT-Account=" & strSid & "));cn,mail;subtree"
      dim oConn, oRS, oCommand

      Set oConn = CreateObject("ADODB.Connection") 'Create an ADO Connection
      oConn.Provider = "ADsDSOOBJECT"              ' ADSI OLE DB provider
      oConn.Open "ADs Provider"
      Set oRS = oConn.Execute(strQuery)

      If oRS.BOF And oRS.EOF Then
         Response.Write "Unable to retrieve information."
      Else
         While Not oRS.EOF
            Response.Write "Mailbox :  " & oRS.Fields("cn") & vbLf & "Email : " & oRS.Fields("mail")+"<BR>"
            oRS.MoveNext
         Wend
      End If

      'Clean up.
      oRS.Close
      oConn.Close
      Set oRS = Nothing
      Set oConn = Nothing
%>

Thanks,
Roger
0
Comment
Question by:rd_kellerman
  • 16
  • 11
27 Comments
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17149095
Which is line 40?  You could try the winnt protocol:

Sub PullUserFullname(strDomain,strUser)
    Dim User
    Set User = GetObject("WinNT://" & strDomain & "/" & strUser & ",user")
    Response.write User.Fullname
  End sub


I think there is a user.email or something similar
0
 

Author Comment

by:rd_kellerman
ID: 17149139
line 40 is this  "Set oRS = oConn.Execute(strQuery)") All the code works until it gets here. I get the user name(strUser) and the sid(strSid) from the code but want to find their Email and common name from mail server. There is some kind of error in the query string syntax, I think.
Thanks,
Roger
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17149195
I will post more code in the morning for you....
0
 

Author Comment

by:rd_kellerman
ID: 17204399
Is anyone out there? Should I move this question to another topic area?  I have not gotten anything since the first comment from NovoNordisk.
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17208886
Try this:
<%@language="vbscript" %>
<%
Option Explicit

Dim objRootDSE, strDNSDomain, objConnection, strQuery
Dim objRecordSet, strName, strDN
Dim strBase, strFilter, strAttributes

' Determine DNS domain name from RootDSE object.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")

' Use ADO to search Active Directory.
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Properties("User ID") = "domain\username"
objConnection.Properties("Password") = "password"
objConnection.Open "Active Directory Provider"

' Search for all user objects. Sort recordset by DisplayName.
strBase = "<LDAP://" & strDNSDomain & ">"
strFilter = "(& (objectCategory=person)(objectClass=user
)(sAMAccountName=" &
Session("UID") & "))"
strAttributes = "mail"
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"

Set objRecordSet = objConnection.Execute(strQuery)

If objRecordSet.EOF Then
response.Write "no records"
End If

' Loop through results
Do Until objRecordSet.EOF
response.Write "Email Address: " & objRecordSet.Fields("mail")
objRecordSet.MoveNext
Loop

' Clean up.
objConnection.Close
Set objRootDSE = Nothing
Set objConnection = Nothing
Set objRecordSet = Nothing

%>

You will need to set a username and person in order to query AD.  This will list all users and their email addresses.  To filter it to be a specific user then you could put an If statement in:

IF objRecordSet.Fields("fullname") = "Joe Bloggs" then
do whatever
end if
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17208906
Check out this link too:

http://www.codeproject.com/asp/verify_an_email_adress_in.asp

You could alter it to check an email address of the current logged on user...
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17208915
set oConn = CreateObject("ADODB.Connection")
set oCommand = CreateObject("ADODB.Command")

oConn.Provider = "ADsDSOObject"
oConn.Open "Ads Provider"
strServerName = "Exchange01"    
strEmail = Request.Form("email")

strQuery = "<LDAP://" & strServername & _
           ">;(&(objectClass=*)(mail=" & strEmail & _
           "));ADsPath,sn,givenname,mail,uid;subtree"

oCommand.CommandText = strQuery
set oRS = oCommand.Execute
if not oRS.eof then
   response.write "User: "& oRs("givenname") & oRs("sn") & "Email: " & oRs("mail")
else
   Response.Write "Not found"
end if
0
 

Author Comment

by:rd_kellerman
ID: 17218903
I think I may be getting closer to the solution. When I run This Code:

''Code fragment ************************************
' Determine DNS domain name from RootDSE object.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")

strDomain = "myDomain"
strUser = "Me"

' Use ADO to search Active Directory.
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"

objConnection.Properties("User ID") = strDomain & "\" & strUser
objConnection.Properties("Password") = "password"
''objConnection.Open "Active Directory Provider"
objConnection.Open "ADs Provider"

strBase = "<LDAP://" & strDNSDomain & ">"
' 'strBase = "<LDAP://ExchangeSvr:389>"

' 'Search for all user objects. Sort recordset by DisplayName.
strFilter = "(&(objectClass=person)(Assoc-NT-Account=" + strSid + "))"
strAttributes = "cn,mail"

strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"

Set objRecordSet = objConnection.Execute(strQuery)

' Loop through results
If Not objRecordSet.EOF Then
      Do Until objRecordSet.EOF
      Response.Write "Mailbox :  " & objRecordSet.Fields("cn") & vbLf & "Email : " & objRecordSet.Fields("mail")    & "<BR>"
            objRecordSet.MoveNext
      Loop
Else
      response.Write "no records"
End If
'****** end code fragment******************

I get to the "no records" message from the Else statement, so I assume the syntax is correct. BUT...
I am wondering if  there is something about the environment that I'm in that is causing so many problems... I have tried so many different solutions and still am getting nowhere. I am not real familiar with the server setup, but a LAN admin said that we could not get this info from active directory, but have to query the Exchange server only. Will this change the code? Can it be done using a different method.  I did change the strFilter argument in the code you provided to match some existing code that works with a third party fax program that we use, but it uses it's own code for some of that, so I can't use it for my application.  The link was as close to what I need as anything I have seen, but it won't work either in my situation. I am guessing that the problem is that the code I'm trying to use is for Active Directory and I need to use code for Exchange server 5.5, (we will be upgrading soon to the newer version of software soon). Does this sound right?

Thanks for the help!!
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17218962
Firstly we need to make sure the username you are passing to the code is correct.  What does this code produce when you run it without altering it other than adding in a username and password??
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17218999
Also what about this code?  This searchs exchange.  I think with the new version of exchange it integrates more with Active Directory - you can create the email accounts within AD, so yes I expect you are correct about the problem.  Pls try this code:


set oConn = CreateObject("ADODB.Connection")
set oCommand = CreateObject("ADODB.Command")

oConn.Provider = "ADsDSOObject"
oConn.Open "Ads Provider"
strServerName = "Exchange01"    
strEmail = Request.Form("email")

strQuery = "<LDAP://" & strServername & _
           ">;(&(objectClass=*));ADsPath,sn,givenname,mail,uid;subtree"

oCommand.CommandText = strQuery
set oRS = oCommand.Execute
if not oRS.eof then
   response.write "User: "& oRs("givenname") & oRs("sn") & "Email: " & oRs("mail")
else
   Response.Write "Not found"
end if
0
 

Author Comment

by:rd_kellerman
ID: 17219044
I get to the "no records" message from the Else statement. The code that is commented is stuff I was trying for testing. I am running this code with the user & password changed to my credentials.

I am getting the sid using this code:
''*** this works if that helps  ********
 Const ADS_SID_HEXSTRING = 1
   Const ADS_SID_WINNT_PATH = 5
    strUser = Request.ServerVariables("AUTH_USER")
        ' Switch the "\" to a "/" in the user name for later parsing.
         for x = 1 to len(strUser)
      if mid(strUser,x,1)="\" then
          strAuthUser = left(strUser,x-1)& "/" & right(strUser,len(strUser)-x)
      end if
         next
   Set oSid = Server.CreateObject("ADSSID")      'From Platform SDK, adssecurity.dll,
   oSid.SetAs ADS_SID_WINNT_PATH, "WinNT://" & strAuthUser       'get the user account SID.
   strSid = oSid.GetAs(ADS_SID_HEXSTRING)      'Convert to binary string.
   set oSid = Nothing
'***** end code ******
It returns a sid that looks right.
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17219081
Sorry which code are you running when you get the no records message?  Also the code you are using is using the WinNT:// protocol which is basically querying Active Directory but you cant get much info from it - certainly not the email address.
0
 

Author Comment

by:rd_kellerman
ID: 17219130
The code I am running when I get the no records:

''Code fragment ************************************
' Determine DNS domain name from RootDSE object.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")

strDomain = "myDomain"
strUser = "Me"

' Use ADO to search Active Directory.
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"

objConnection.Properties("User ID") = strDomain & "\" & strUser
objConnection.Properties("Password") = "password"
''objConnection.Open "Active Directory Provider"
objConnection.Open "ADs Provider"

strBase = "<LDAP://" & strDNSDomain & ">"
' 'strBase = "<LDAP://ExchangeSvr:389>"

' 'Search for all user objects. Sort recordset by DisplayName.
strFilter = "(&(objectClass=person)(Assoc-NT-Account=" + strSid + "))"
strAttributes = "cn,mail"

strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"

Set objRecordSet = objConnection.Execute(strQuery)

' Loop through results
If Not objRecordSet.EOF Then
     Do Until objRecordSet.EOF
     Response.Write "Mailbox :  " & objRecordSet.Fields("cn") & vbLf & "Email : " & objRecordSet.Fields("mail")    & "<BR>"
          objRecordSet.MoveNext
     Loop
Else
     response.Write "no records"
End If
'****** end code fragment that produces the "no records"  message ******************

NOW I tried the last code you suggested as below:

set oConn = CreateObject("ADODB.Connection")
set oCommand = CreateObject("ADODB.Command")

oConn.Provider = "ADsDSOObject"
oConn.Open "Ads Provider"
strServerName = "Exchange01"    
strEmail = Request.Form("email")

strQuery = "<LDAP://" & strServername & _
           ">;(&(objectClass=*));ADsPath,sn,givenname,mail,uid;subtree"

oCommand.CommandText = strQuery
set oRS = oCommand.Execute
if not oRS.eof then
   response.write "User: "& oRs("givenname") & oRs("sn") & "Email: " & oRs("mail")
else
   Response.Write "Not found"
end if

NOW I get this Error ( I changed the variables for my server etc..):

ADODB.Command error '800a0e7d'

The connection cannot be used to perform this operation. It is either closed or invalid in this context.

/onlineforms/Form_Work/roger/Query5.asp, line 21

line 21 is  "set oRS = oCommand.Execute"

Sorry for the confusion We were both sending email at the same time as I was testing the code.



0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17219161
OK I have another suggestion for you:

for this line:"<LDAP://server_name/dc=ee,dc=com,dc=ee>  use this format:

servername.domain.com i.e. servername/dc=domain,dc=com

search for email address of users
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"

Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection


objCommand.CommandText = "<LDAP://server_name/dc=ee,dc=com,dc=ee>;(&(objectClass=person));name,mail;subtree"

Set objRecordSet = objCommand.Execute
While Not objRecordSet.EOF
    strADEmail = objRecordSet.Fields("mail")
    strADName = objRecordSet.Fields("name")
    objRecordSet.MoveNext
Wend
objRecordSet.Close
Set objRecordSet = Nothing
Set objCommand = Nothing
' END search for email address of users
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17219181
Sorry I missed some code:

 search for email address of users
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"

Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection


objCommand.CommandText = "<LDAP://server_name/dc=ee,dc=com,dc=ee>;(&(objectClass=person));name,mail;subtree"

Set objRecordSet = objCommand.Execute
While Not objRecordSet.EOF
    strADEmail = objRecordSet.Fields("mail")
    strADName = objRecordSet.Fields("name")
    objRecordSet.MoveNext
Wend
objRecordSet.Close
Set objRecordSet = Nothing
Set objCommand = Nothing
' END search for email address of users
0
 

Author Comment

by:rd_kellerman
ID: 17219195
I am trying it now.  Will let You know ASAP.
0
 

Author Comment

by:rd_kellerman
ID: 17219513
Now I get this error:

Provider error '80040e37'

Table does not exist.

/onlineforms/Form_Work/roger/Query5.asp, line 30

line 30 is "Set objRecordSet = objCommand.Execute"

This is really frustrating!  Thanks for hanging in there.  I'll be off line soon, will try this again tommorrow.
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17219551
try:

Set objConnection = CreateObject("ADODB.Connection")
objConnection.Properties("User ID") = "domain\user"
objConnection.Properties("Password") = "password"
objConnection.Open "Provider=ADsDSOObject;"

Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection


objCommand.CommandText = "<LDAP://server_name/dc=ee,dc=com,dc=ee>;(&(objectClass=person));name,mail;subtree"

Set objRecordSet = objCommand.Execute
While Not objRecordSet.EOF
    strADEmail = objRecordSet.Fields("mail")
    strADName = objRecordSet.Fields("name")
    objRecordSet.MoveNext
Wend
objRecordSet.Close
Set objRecordSet = Nothing
Set objCommand = Nothing
' END search for email address of users
0
 

Author Comment

by:rd_kellerman
ID: 17219617
Nope, Now I get this:

ADODB.Connection error '800a0c94'

Supplied provider is different from the one already in use.

/onlineforms/Form_Work/roger/Query5.asp, line 19

line 19 is :  objConnection.Open "Provider=ADsDSOObject;"
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17219640
grrrr Ok lets take another look in the morning!!
0
 

Author Comment

by:rd_kellerman
ID: 17219649
sounds good. THANKS!
0
 
LVL 8

Accepted Solution

by:
NovoNordisk earned 500 total points
ID: 17222749
OK this code does work:

You need to know the full name of your exchange server ie if its called EX01 then its fullname would be something like
EX01.mydomain.com

The page also needs to run with administrator rights - this is set in IIS - do you know how to do that?  It should list all users and their email address:

<%

Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"

Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection


objCommand.CommandText = "<LDAP://exchangeserver/dc=domain,dc=com>;(&(objectClass=person));name,mail;subtree"

Set objRecordSet = objCommand.Execute
While Not objRecordSet.EOF
    strADEmail = objRecordSet.Fields("mail")
    strADName = objRecordSet.Fields("name")
response.write "User: "&strADName & "<br>Email: " & strADEmail & "<br><br>"
    objRecordSet.MoveNext
Wend
objRecordSet.Close
Set objRecordSet = Nothing
Set objCommand = Nothing
' END search for email address of users
%>
0
 

Author Comment

by:rd_kellerman
ID: 17228666
OK.  Here's where I'm at today.

I ran basically the code above with this string:
"<LDAP://DC=am,DC=corp,DC=priv>"
(which I got from running this code 'Set objRootDSE = GetObject("LDAP://RootDSE")' )
for LDAP string instead of  "<LDAP://exchangeserver/dc=domain,dc=com>"
and I finally got it to return results. But that ran the query against the Active Directory NOT the Exchange server.
That won't work because we don't have the Email address in AD according to the LAN admin.

I tried this "<LDAP://exchangeserver/DC=am,DC=corp,DC=priv>" too - No Good Either!

I have tried every syntax for the exchange server string I can think of and cannot get it to connect to the Exchange Server.  I think the page permissions are ok or I could not have ran the query against AD, isn't this correct? I'm not sure where to go from here. If you have any other ideas ok, otherwise we'll just give up for now. Thanks for all, I think it's close to what I need. I will keep trying when I have time to work on it.
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17231083
This code does work and it does query exchange and not AD.  What is your full server name?? What error message are you getting?
0
 

Author Comment

by:rd_kellerman
ID: 17237829
I got it to work by using vbscript outside of asp code, I call it with an onsubmit event function. For some reason the query string was not reading right in the asp code. I will be ok using it this way because I need to validate a user (check to see if they are in our exchange address book) before submitting a form. I have learned from this and REALLY appreciate your help!! I'm sure there is a way to do it inside of asp code, but for now I will use what I have.

Thanks,
Roger
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17239799
OK well Im glad I could help.  It most certainly can be done in ASP alone because I do it often!!  You have above the exact code I use except I have another IF statement to check the current user.  The trick with LDAP is always getting the correct syntax.  Once thats resolved its easy!!

Also you must remember if you are running pages with admin rights and submit form items to it from a page running as a normal user - it will loose those form items.  I always use session variables to get around this.
0
 
LVL 8

Expert Comment

by:NovoNordisk
ID: 17240631
Are you going to close this question??
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

I have helped a lot of people on EE with their coding sources and have enjoyed near about every minute of it. Sometimes it can get a little tedious but it is always a challenge and the one thing that I always say is:  The Exchange of information …
This demonstration started out as a follow up to some recently posted questions on the subject of logging in: http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_28634665.html and http://www.experts-exchange.com/Programming/…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

26 Experts available now in Live!

Get 1:1 Help Now