English 中文(简体)
TSQL: How to get a list of groups that a user belongs to in Active Directory
原标题:

I have two queries that retrieve all groups and all users in a domain, Mydomain

--; Get all groups in domain MyDomain
select  *  
from    OpenQuery(ADSI,  
    SELECT  samaccountname,mail,sn,name, cn, objectCategory
    FROM      LDAP://Mydomain/CN=users,DC=Mydomain,DC=com   
    WHERE   objectCategory=  group   
    ORDER BY cn
     )

--; Get all users in domain MyDomain
select  *  
from    OpenQuery(ADSI, 
    SELECT objectCategory, cn, sn, mail, name, department,samaccountname
    FROM   LDAP://Mydomaindomain/CN=users,DC=Mydomain,DC=com   
    WHERE objectCategory=  user   
    ORDER BY cn
     )
--  where   samaccountname= mylogin 

What I would like to find out is,

How do you retrieve a list of all groups in MyDomain that a particular user belongs to?

[UPDATE] I was able to get the opposite result
Given the group name, retrieve all users

select  *  
from    OpenQuery(ADSI,
     SELECT objectCategory, cn, sn, mail, name, department
    FROM   LDAP://Mydomain/CN=users,DC=wl-domain,DC=com   
    WHERE MemberOf=  cn=_____GROUPNAME_____,CN=users,DC=Mydomain,DC=com  
    ORDER BY cn  
    )
最佳回答

I think this is one of the limitations of the T-SQL based AD interface - you cannot retrieve multi-valued attributes, e.g. attributes (like memberOf for the user) that have more than one value in them.

You can retrieve single-valued attributes like "sn" (surname = last name) or "givenName" and "mail" and so forth, but the SQL-based interface isn t capable of handling attributes like "memberOf" with several values assigned to them.

So I m afraid you ll have to go another way for this problem - e.g. find and populate the group membership in managed code (separately outside of SQL Server, or possibly as a CLR assembly inside SQL Server).

UPDATE: see here (MSDN Support) for an explanation of limitation of the OPENQUERY AD provider:

Limitations
The process of using the OPENQUERY statement to pull information from an LDAP server does suffer from some limitations. The limitations can be circumvented in some cases, but in others the application design must be altered. An external application or COM object that uses ADSI to retrieve the information from the LDAP server and then build a table in SQL by using ADO or other data access methods is another viable method.

The first limitation is that multivalued properties cannot be returned in the result set to SQL Server. ADSI will read schema information from the LDAP server that defines the structure and syntax of the classes and attributes used by the server. If the attribute that is requested from the LDAP server is defined in the schema as being multi-valued it cannot be returned in an OPENQUERY statement.

问题回答

Stored procedure below, execute using example:

Get_ADGroups_ForUser Beau.Holland --AccountName

Note: replace LDAP://DC=Domain,DC=local with your own domain.

CREATE PROCEDURE dbo.Get_ADGroups_ForUser
(
    @Username NVARCHAR(256) 
)
AS
BEGIN

    DECLARE @Query NVARCHAR(1024), @Path NVARCHAR(1024)

    -- Find the fully qualified CN e.g: CN=Beau Holland,OU=Users,OU=Australia,OU=NSO,OU=Company,DC=Domain,DC=local
    -- replace "LDAP://DC=Domain,DC=local" with your own domain
    SET @Query =  
        SELECT @Path = distinguishedName
        FROM OPENQUERY(ADSI,   
            SELECT distinguishedName 
            FROM     LDAP://DC=Domain,DC=local    
            WHERE 
                objectClass =     user     AND
                sAMAccountName =       + @Username +      
          )
     
    EXEC SP_EXECUTESQL @Query, N @Path NVARCHAR(1024) OUTPUT , @Path = @Path OUTPUT 

    -- get all groups for a user
    -- replace "LDAP://DC=Domain,DC=local" with your own domain
    SET @Query =  
        SELECT cn,AdsPath
        FROM OPENQUERY (ADSI,   <LDAP://DC=Domain,DC=local>;(&(objectClass=group)(member:1.2.840.113556.1.4.1941:=  + @Path + ));cn, adspath;subtree  ) 

    EXEC SP_EXECUTESQL @Query  

END
GO

You can achieve this by fetching all groups that contain the user in their member attribute, or better the user s LDAP path (distinguishedName). Here s a simple procedure doing that job.


CREATE PROCEDURE dbo.GetLdapUserGroups
(
    @LdapUsername NVARCHAR(256)
)
AS
BEGIN
    DECLARE @Query NVARCHAR(1024), @Path NVARCHAR(1024)

    SET @Query =  
        SELECT @Path = distinguishedName
        FROM OPENQUERY(ADSI,   
            SELECT distinguishedName 
            FROM     LDAP://DC=domain,DC=com    
            WHERE 
                objectClass =     user     AND
                sAMAccountName =       + @LdapUsername +      
          )
     
    EXEC SP_EXECUTESQL @Query, N @Path NVARCHAR(1024) OUTPUT , @Path = @Path OUTPUT 

    SET @Query =  
        SELECT name AS LdapGroup 
        FROM OPENQUERY(ADSI,  
            SELECT name 
            FROM     LDAP://DC=domain,DC=com    
            WHERE 
                objectClass=    group     AND
                member=      + @Path +      
          )
        ORDER BY name
     
    EXEC SP_EXECUTESQL @Query

END

-- Hilbert

Actually, retreiving the list of all groups to which a user belongs is not as straight-forward / easy as it seems. As far as I know neither PowerShell nor other scripts can deliver completely accurate results, even when retrieving the tokenGroups attribute, because in order to make this determiantion, one also has to consider membership in Builtin Groups, which are domain specific.

There is a very useful thread on ActiveDirSec.org that I think you might find useful - How to enumerate the list of all Active Directory domain security groups that a user belongs to?

In my experience, I have learnt that this isn t as easy as it seems, and unless you have a way to verify the output for sure, there is also no way to know if your script is delivering the right results.

You can use that (on MS SQL server):

EXEC master..xp_cmdshell  dsquery user -samid username | dsget user -memberof 

It will result all groups for username

The Microsoft Technet Script Center is a great resource for scripts

http://technet.microsoft.com/en-us/scriptcenter/default.aspx

Here is a script that claims to give out exactly what you want:

http://gallery.technet.microsoft.com/ScriptCenter/en-us/ab5400e2-489a-4738-9b85-508bcb5b75f8





相关问题
How to write this T-SQL WHERE condition?

I ve got two tables: TableA Col1 Col2 TableB Col3 Col4 I want to join them together: SELECT * from TableA join TableB ON (...) Now, in place of ... I need to write an expression ...

Customer and Order Sql Statement

TSQL query to select all records from Customer that has an Order and also select all records from customer that does not have an Order. The table Customer contains a primary key of CustomerID. The ...

Recommended way of querying multiple Versioned tables

Have a win 2003 box with MSSQL 2005 running on it. There is a database which is populated every morning with new/modified SalesOrder made the previous day. The database has several tables: SalesOrder, ...

update duplicate record

I have a table with the following fields Id Name IsPublic i need to write a sql query that updates IsPublic to false where name has a duplicate. Only one of the duplicates should have IsPublic = ...

Define variable to use with IN operator (T-SQL)

I have a Transact-SQL query that uses the IN operator. Something like this: select * from myTable where myColumn in (1,2,3,4) Is there a way to define a variable to hold the entire list "(1,2,3,4)"? ...

Selecting records during recursive stored procedure

I ve got a content management system that contains a hierarchical structure of categories, with sub-categories subject to different ordering options at each level. Currently, that s retrieved by a (...

热门标签