Querying Active Directory Data from SQL Server

By:   |   Comments (42)   |   Related: 1 | 2 | 3 | > Linked Servers


Problem

My boss is asking for a list of email addresses and phone numbers for all users in the company. I know this data exists in Active Directory, so how can I access this data from SQL Server?  In this tip we walk through how you can query Active Directory from within SQL Server Management Studio.

Solution

In this tip I'll show you how to query Active Directory using linked servers and the OPENQUERY command.

Create Linked Server

First thing we'll do is create our linked server, Active Directory Service Interface also known as ASDI, to Active Directory using the code below:

USE [master]
GO 
EXEC master.dbo.sp_addlinkedserver @server = N'ADSI', @srvproduct=N'Active Directory Service Interfaces', @provider=N'ADSDSOObject', @datasrc=N'adsdatasource'
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'ADSI',@useself=N'False',@locallogin=NULL,@rmtuser=N'DOMAIN\USER',@rmtpassword='*********'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'collation compatible',  @optvalue=N'false'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'data access', @optvalue=N'true'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'dist', @optvalue=N'false'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'pub', @optvalue=N'false'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'rpc', @optvalue=N'false'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'rpc out', @optvalue=N'false'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'sub', @optvalue=N'false'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'connect timeout', @optvalue=N'0'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'collation name', @optvalue=null
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'lazy schema validation',  @optvalue=N'false'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'query timeout', @optvalue=N'0'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'use remote collation',  @optvalue=N'true'
GO 
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'remote proc transaction promotion', @optvalue=N'true'
GO

Make sure you change the @rmtuser and @rmtpassword variables to a login and password that has access to your Active Directory.


Querying Active Directory

Once the linked server is created we can now setup our query to return the information we need.

First, you'll need to ask your Network/Systems Administrator for your LDAP info then we can continue to the query. 

Here is how the LDAP connection is broken down:

  • For our example it looks like this: LDAP://DOMAIN.com/OU=Players,DC=DOMAIN,DC=com
  • LDAP://Domain.com - is the name of a domain controller
  • /OU=Players - this is the Organization Unit, in our case (Players)
  • ,DC - this is the Domain Name broken up by domain and extension name
  • So....LDAP://DomainControllerName.com/OU=OrganizationalUnit,DC=DOMAIN,DC=NAME

According to the problem, this user needs to return the companies email addresses and phone numbers. To do this we can use the code below:

(note - you will need to change your domain information for this to work)

SELECT * FROM OpenQuery ( 
  ADSI,  
  'SELECT displayName, telephoneNumber, mail, mobile, facsimileTelephoneNumber 
  FROM  ''LDAP://DOMAIN.com/OU=Players,DC=DOMAIN,DC=com'' 
  WHERE objectClass =  ''User'' 
  ') AS tblADSI
ORDORDER BY displayname

As you can see this query will return Active Directory's Display Name, Telephone Number, Email Address, Mobile Number, and Fax Number. Also note, that when you query Active Directory it actually creates the SELECT statement backwards. I started the SELECT statement with SELECT displayname... but in the results pane it displayed displayName last as shown below.

use sql server to query active directory

If you wanted to view more columns for each user we can use the below code to display fields such as: FirstName, Office, Department, Fax, Mobile, Email, Login, Telephone, Display Name, Title, Company, Pager, Street Address, and more.

SELECT * FROM OpenQuery
  ( 
  ADSI,  
  'SELECT streetaddress, pager, company, title, displayName, telephoneNumber, sAMAccountName, 
  mail, mobile, facsimileTelephoneNumber, department, physicalDeliveryOfficeName, givenname 
  FROM  ''LDAP://DOMAIN.com/OU=Players,DC=DOMAIN,DC=com''
  WHERE objectClass =  ''User'' 
  ') AS tblADSI
ORDER BY displayname

querying active directory from sql server management studio

You can also filter out columns using a WHERE clause. In this example I only want to return results where users have a fax number.

SELECT * FROM OpenQuery
  ( 
  ADSI,  
   'SELECT streetaddress, pager, company, title, displayName, telephoneNumber, sAMAccountName, mail,  
  mobile, facsimileTelephoneNumber, department, physicalDeliveryOfficeName, givenname
  FROM  ''LDAP://DOMAIN.com/OU=Players,DC=DOMAIN,DC=com''   
  WHERE objectClass =  ''User'' 
  ') AS tblADSI
WHERE facsimileTelephoneNumber IS NOT NULL
ORDER BY displayname

writing a query to selectively query active directory from sql server
Next Steps
  • To view all the Active Directory attributes click here
  • To view how to get Active Directory Users and Groups with SSIS check out this tip from Ray Barley


sql server categories

sql server webinars

subscribe to mssqltips

sql server tutorials

sql server white papers

next tip



About the author
MSSQLTips author Brady Upton Brady Upton is a Database Administrator and SharePoint superstar in Nashville, TN.

This author pledges the content of this article is based on professional experience and not AI generated.

View all my tips



Comments For This Article




Friday, March 19, 2021 - 4:36:23 AM - Rr Back To Top (88443)
Great article thanks for sharing your knowledge
I am experiencing an issue with the aptostorpe while trying to get the group level info based on distinguish name from a open query
When I give two single quotes query is breaking , does anyone has a solution for this

Monday, June 29, 2020 - 4:53:35 AM - Rave Back To Top (86066)

Hi Experts,

I am trying to fetch the records from Linked server I have completed with all the users now able to see Users in SQL Table.

Now facing issue when I try to get each group and respective Users from each group.

Please assist.


Tuesday, March 31, 2020 - 3:11:46 AM - Rave Back To Top (85222)

Hi,

How to retrieve all the columns and all the Organization units from a single query??

Regards,

Rave


Thursday, February 20, 2020 - 7:20:49 AM - Xst Back To Top (84665)

It works with LDAPS Server in following Format

FROM 'LDAP://xxx.yyy.zz:636'


Wednesday, February 19, 2020 - 4:53:17 AM - Xst Back To Top (84630)

Hi All

We use this solution to Query our LDAP from SQL Server. This use LADP TCP Port 389.
For future I have to use a connection over LDAPS / TCP Port 636

How can i do this?
I've found some ideas like

FROM 'LDAP://DC=xx,DC=xx,DC=xx:636'    ...or
FROM 'LDAPS://DC=xx,DC=xx,DC=xx'

But nothing works for me. Sure we implemented the Certificates for DC trust and all this stuff

The error is like

""An error occurred while preparing a query for execution against OLE DB provider 'ADSDSOObject'""

How can I proper Query my Active Directory over LDAPS TCP 636 from my SQL Server?

Thansk for any help
Xst


Thursday, November 14, 2019 - 4:33:21 AM - Timo Riikonen Back To Top (83090)

AD has a limit of 9901 lines for the response, so you need to divide queries beyond that into parts. Here I have divided the main query into three parts.

SELECT *, 1 AS [Internal] FROM OpenQuery (
ADSIlim,
'SELECT sAMAccountName, employeeNumber, givenName, mail, company, department, manager, ADsPath
FROM ''LDAP://OU=User_Accounts,OU=COMPANY,DC=DOMAIN3,DC=DOMAIN2,DC=DOMAIN1''
WHERE objectCategory = ''Person'' AND objectClass = ''User'' AND ''userAccountControl:1.2.840.113556.1.4.803:''<>2 AND SAMAccountName < ''Jzz''
') 
UNION ALL
SELECT *, 1 AS [Internal] FROM OpenQuery (
ADSIlim,
'SELECT sAMAccountName, employeeNumber, givenName, mail, company, department, manager, ADsPath
FROM ''LDAP://OU=User_Accounts,OU=COMPANY,DC=DOMAIN3,DC=DOMAIN2,DC=DOMAIN1''
WHERE objectCategory = ''Person'' AND objectClass = ''User'' AND ''userAccountControl:1.2.840.113556.1.4.803:''<>2 AND SAMAccountName >= ''Jzz'' AND sAMAccountName < ''Pzz''
') 
UNION ALL
SELECT *, 1 AS [Internal] FROM OpenQuery (
ADSIlim,
'SELECT sAMAccountName, employeeNumber, givenName, mail, company, department, manager, ADsPath
FROM ''LDAP://OU=User_Accounts,OU=COMPANY,DC=DOMAIN3,DC=DOMAIN2,DC=DOMAIN1''
WHERE objectCategory = ''Person'' AND objectClass = ''User'' AND ''userAccountControl:1.2.840.113556.1.4.803:''<>2 AND SAMAccountName >= ''Pzz''
') 
UNION ALL
SELECT *, 0 AS [Internal] FROM OpenQuery (
ADSIlim,
'SELECT sAMAccountName, employeeNumber, givenName, mail, company, department, manager, ADsPath
FROM ''LDAP://OU=User_Accounts_External,OU=COMPANY,DC=DOMAIN3,DC=DOMAIN2,DC=DOMAIN1''
WHERE objectCategory = ''Person'' AND objectClass = ''User'' AND ''userAccountControl:1.2.840.113556.1.4.803:''<>2
')

Thursday, June 6, 2019 - 4:06:22 PM - Philip Ankrah Back To Top (81353)

Hello,

How can I do this operation with multiple OU's and multiple locations within those OU's? I want to retrieve all user data from the users folder in all OU's and all folders that may contain the users folder.


Thursday, February 21, 2019 - 1:28:16 PM - Dan Back To Top (79083)

This code worked great using SQL Server 2012! It is much appreciated!


I noticed the use of OPENQUERY; where you cannot use variable fields to create a query and then execute it on the fly.


Below is what to do in being able to do this with ADSI. I made this so you could floow it, but you could expand it by using cursors to fetch fields from your database and attach that to the query against AD :)


When you are creating the Linked Server, change the following lines as shown (they MUST BE true; otherwise it will fail)

EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'rpc', @optvalue=N'true'
GO
EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'rpc out', @optvalue=N'true'
GO


Next, write the query:


declare @ADQuery nvarchar(max) = 'select mail, sAMAccountName from ''LDAP://OU=OrgUnit,DC=dcpart1,DC=dcpart2,DC=dcpart3'' where '
set @ADQuery = @ADQuery + 'sAMAccountName = ''accountname1''
set @ADQuery = @ADQuery + 'and sAMAccountName = ''accountname2''

execute (@ADQuery) at ADSI


Finally, execute the query

It is important to note the use of nvarchar() and not the use of varchar(). This is because the execute command requires nvarchar, not varchar.
The LDAP is vital, but if you have the OP version working, then this will work as expected with that LDAP.


Wednesday, August 22, 2018 - 10:17:16 AM - Jared Back To Top (77269)

 This is how I got around the limit of 901 rows.  Essentially, I cycle through valid characters and add/remove characters testing what works and doesn't work.  I was able to extract over 93,000 rows from AD in about 2 minutes.

https://jaredacarter.blogspot.com/2018/08/solved-how-do-i-query-active-directory.html


Monday, March 19, 2018 - 11:08:30 AM - Maria Hernandez Back To Top (75462)

 Hi Brady,

I'm looking for a way to tie my $SQLLogins in powershell to the Active Directory "Display Name" of the user.  We use a number for the login name so getting the Display Name is helpful for locating the user.  Even email would be helpful.   Do you have anything like that?  

 


Tuesday, January 23, 2018 - 5:15:07 AM - gajendran Back To Top (75017)

thanks for the detailed post for querying AD. I have a different problem. I need to a particular sAMAccountName is exists in the AD or not. but seems the openquery will not accept variable arguments. How this can be achieved. looking for something like to pass qeury as.. 

'SELECT displayName, sAMAccountName
  mobile, facsimileTelephoneNumber, department, physicalDeliveryOfficeName, givenname
  FROM  ''LDAP://DOMAIN.com/OU=Players,DC=DOMAIN,DC=com''   
  WHERE objectClass =  ''User''
AND sAMAcccountName = @va_login_name
'

 


Thursday, January 26, 2017 - 4:18:53 PM - Ralph Back To Top (45599)

Thanks for the tip on querying active directory from SQL.  It's extremely helpful.  Being able to link to AD eliminates the need for duplicate (which often means wrong) information.  

Except for being a Bama fan, you're allright.

 

 

 


Monday, August 29, 2016 - 5:22:37 PM - richard Back To Top (43211)

 

 GOOD AFTERNOON,

WHY COULD PLEASE HELP ME REGARDING LDAP INTEGRATION WITH SQL ?
I noticed that NO QUERY RETURN , THE LIMIT AND RECORDS 900 . WOULD BE A BETTER WAY THAT?
thank you

Friday, July 8, 2016 - 8:35:35 PM - Rufus Back To Top (41847)

How long did it take for your query to return?  It took me ave 6-7 secs.


Wednesday, June 29, 2016 - 11:19:14 AM - ndemet Back To Top (41787)

Is there any way to query all OU's except one?  Something like: WHERE OU <> ''SOME OU''


Monday, January 25, 2016 - 9:49:16 AM - Nick Back To Top (40491)

This is fine if you have only one domain. If you're a large company with multiple domains, you have to query the Global Catalogue.

FROM  ''GC://DOMAIN.com/OU=Players,DC=DOMAIN,DC=com''  


Friday, May 29, 2015 - 1:06:32 PM - Dan Faustine Back To Top (37332)

Never mind, I found it... You have to right-click on the linked server in SSMS, and go to the Security tab.


Friday, May 29, 2015 - 1:04:31 PM - Dan Faustine Back To Top (37331)

Great article, thanks!

Does anyone know how to update the password of the user once it's entered into the linked server?


Tuesday, December 2, 2014 - 8:18:12 AM - Tomasz Back To Top (35462)

Hi Niraj, maybe this will be helpful. Try to use LDAP://CN=External Users,CN=SDE,CN=execldr,DC=ss,DC=com instead of LADP://xxx/OU=...


Tuesday, December 2, 2014 - 4:32:06 AM - Niraj Back To Top (35456)

 Hi Mr. Brady

I wanted to access maxpwdage (Maximum password age) from the Active directory i am using following query but its getting null can you please give some explanation on it that will help me 

i used follwing query 

SELECT  top 100 *    FROM OpenQuery ( 

 

  ADSI,  

 

  'SELECT  displayName, telephoneNumber, mail, mobile, facsimileTelephoneNumber ,pwdLastSet,name,maxpwdage

 

  FROM  ''LDAP://xxx/OU=External Users,OU=SDE,OU=execldr,DC=ss,DC=COM'' 

 

  WHERE objectClass =  ''User''  

 

  ') AS tblADSI  

 


Monday, December 1, 2014 - 8:20:11 AM - Tomasz Back To Top (35440)

Hi Brady, Very good post but its not working everytime. Many times there is an error 7330 (when LDAP path is wrong like LDAP://DC=Folder,DC=domain,DC=com instead of LDAP://CN=Folder,DC=domain,DC=com) or 7321 (when there is more than 900-1000 rows returned by the query). Could you provide some solution based on above ? Tomasz


Friday, November 7, 2014 - 3:32:35 AM - Dird Back To Top (35217)

Everyone online is using the exact same code snippet which doesn't help with seeing what to change.

 

Am I right in assuming the only things required to be changed are @server (and every other ADSI equivalent), @rmtuser & @rmtpassword?

 

@datasrc and everything else remain unchanged?


Thursday, October 16, 2014 - 3:38:36 PM - eric81 Back To Top (34985)

 

I'm running a query against Active Directory on a SQL 2012 Server and getting the following error. Now I have the same linked server setup on a SQL 2008 Server , but have no issues running this query.

 

Cannot fetch a row from OLE DB provider "ADsDSOObject" for linked server


Tuesday, August 19, 2014 - 3:11:26 PM - bordwalk2000 Back To Top (34200)
WHERE objectCategory = ''User''
Will give you alot better search results than WHERE objectClass = ''User'' because it will strip out all the computer accounts from the list.
 

Tuesday, July 29, 2014 - 12:35:35 PM - Jason Armour Back To Top (33922)

Brady,

 

I am trying to do this within a Trigger... Where do i put the Linked Server Code? Or is it best to have the Trigger exec a Stored procedure, which would then execute the Linked Server, pull the data, and update the record? Otherwise, this is awesome help. Thanks!

 

Thanks

Jason


Wednesday, July 2, 2014 - 11:57:52 AM - rach Back To Top (32515)

I am gettting an error.  I don't understand your setup one.  I am having security issue.

"Once the linked server is created we can now setup our query to return the information we need.

First, you'll need to ask your Network/Systems Administrator for your LDAP info then we can continue to the query. "

Msg 7321, Level 16, State 2, Line 1

An error occurred while preparing the query "SELECT displayName, telephoneNumber, mail, mobile

FROM "LDAP://ad1.peelsb.com/OU=ad1,DC=peelsb,DC=com"

WHERE objectClass = "User"

" for execution against OLE DB provider "ADsDSOObject" for linked server "ADSI".

 


 


Wednesday, May 28, 2014 - 12:01:57 PM - Allen Back To Top (31974)

Thanks for this one!  It brought me one step closer to being able to automate one of my routine tasks.

 

 


Thursday, May 22, 2014 - 11:02:15 AM - maurer Back To Top (30890)
On following your procedure below is the error massage i got can you give me any insight?
 
Msg 7321, Level 16, State 2, Line 1
An error occurred while preparing the query "SELECT displayName, telephoneNumber, mail, mobile, facsimileTelephoneNumber FROM  'LDAP://mydomain.local/DC=mydomain,DC=local'  WHERE objectClass =  'user' " for execution against OLE DB provider "ADSDSOObject" for linked server "ADSI". 
 
 
 
Thank
 
 

Thursday, May 22, 2014 - 9:47:48 AM - maurer Back To Top (30886)

Great post it is insightfull. Please tell me, should the login and password that has access to your Active Directory be an administrator



Wednesday, October 2, 2013 - 6:58:48 AM - Menaka Back To Top (27008)

Can I get the AD user's password also to the database? It may be encrypted format? so the same format that sql server save the passwords?

My requirement is to replicate the AD user + password to Sql server "SQL server logins."

Any helpful comment would be highly appeciate

Thanks

Menaka


Tuesday, July 23, 2013 - 2:45:54 AM - Ahmet Turan YIGIT Back To Top (25949)

SELECT * FROM OpenQuery ( 

  ADSI,  

  'SELECT displayName, telephoneNumber, mail, mobile, facsimileTelephoneNumber 

  FROM  ''LDAP://OGM.GOV.TR'' 

  WHERE objectClass =  ''User'' 

  ') AS tblADSI

ORDER BY displayname

 

Question : How can I do?


Tuesday, October 23, 2012 - 11:19:53 PM - Wanpen_ake Back To Top (20062)

Thank you very much...very helpfull


Monday, October 15, 2012 - 5:55:37 PM - pdtechguru Back To Top (19932)

How to Query Active Directory Objects

 

http://pdtechguru.wordpress.com/2012/10/15/how-to-query-active-directory-objects-3/


Wednesday, June 13, 2012 - 3:30:08 PM - Vaishnav Vinjamuri Back To Top (17974)

Hi

Can anyone help me out in resolving this issue... thanks!!!

 

Msg 7321, Level 16, State 2, Line 1
An error occurred while preparing the query "SELECT samaccountname
  FROM  'LDAP://ARCBRIDGE3.com/DC=ARCBRIDGE3,DC=com'
  WHERE objectClass =  'User'
  " for execution against OLE DB provider "ADSDSOObject" for linked server "ADSI"


Tuesday, February 28, 2012 - 9:52:59 AM - midwest guy Back To Top (16189)

Why not use powershell you get the same results in a few lines of code no linked server needed. Using the Quest free powershell tools makes this a very easy process to implement. 


Wednesday, December 28, 2011 - 5:09:07 AM - Dmytro Back To Top (15456)

Further to my earlier message - sorry, I have misspecified the active directory path. Works a treat. Thousand rows limit is very annoying, but completely understandable - our AD has way over 10k entries!!!


Wednesday, December 28, 2011 - 4:01:45 AM - Dmytro Back To Top (15455)

Hi Brady,

Thank you for an extremely useful article. Tried to give it a go, but get this not very informative error and cannot proceed. Does it make any sense to you?

 Msg 7321, Level 16, State 2, Line 1
An error occurred while preparing the query "SELECT displayName
  FROM  'LDAP://ADINTERNAL.com/OU=sageukie,DC=ADINTERNAL,DC=com'
  " for execution against OLE DB provider "ADSDSOObject" for linked server "ADSI".

Thank you very much in advance,

Happy new year,

Dmytro

 


Tuesday, December 27, 2011 - 4:18:14 PM - Juanita Back To Top (15454)

HI Brady,

What versions of sql server does this work on?


Tuesday, December 27, 2011 - 10:30:09 AM - carlos_sfc Back To Top (15448)

Thanks Brady.

Happy New Year!!


Tuesday, December 27, 2011 - 10:17:25 AM - Casey Back To Top (15447)

The LDAP query limit is set on the domain.  If you can't get your domain admin to increase the limit you can use a filter in the OpenQuery SELECT (e.g. OpenQuery(ADLINK, 'SELECT sAMAccountName FROM ''LDAP://OU=Users,DC=YOUR,DC=com'' where objectClass = ''User''
AND sAMAccountName = ''D*''') returns all user names that begin with the letter D) and union the results.


Tuesday, December 27, 2011 - 10:10:45 AM - Brady Back To Top (15446)

Thanks carlos. I'm glad you can find this useful. Here is something I found on MSDN regarding the 1000 row limitation:

http://blogs.msdn.com/b/ikovalenko/archive/2007/03/22/how-to-avoid-1000-rows-limitation-when-querying-active-directory-ad-from-sql-2005-with-using-custom-code.aspx


Tuesday, December 27, 2011 - 9:56:52 AM - carlos_sfc Back To Top (15445)

Very useful post Brady. How to avoid the limit of page size?, when I execute the openquery it just returns 1000 records and no more.
Thanks

 















get free sql tips
agree to terms