TSQL:如何在Active Directory中获取用户所属组的列表

TSQL:如何在Active Directory中获取用户所属组的列表,sql,sql-server,tsql,active-directory,Sql,Sql Server,Tsql,Active Directory,我有两个查询,检索域中的所有组和所有用户,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 objectCateg

我有两个查询,检索域中的所有组和所有用户,
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'
我想知道的是,

如何检索特定用户所属的
MyDomain
中所有组的列表?

[更新]我得到了相反的结果
给定组名,检索所有用户

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' 
    )

Microsoft Technet脚本中心是一个非常好的脚本资源

下面是一个脚本,它声称提供了您想要的内容:


我认为这是基于T-SQL的广告界面的限制之一-您无法检索多值属性,例如属性(如用户的
memberOf
)中包含多个值

您可以检索诸如“sn”(姓氏=姓氏)或“givenName”和“mail”等单值属性,但基于SQL的接口无法处理诸如“memberOf”等具有多个指定值的属性

因此,恐怕您将不得不采用另一种方法来解决此问题—例如,在托管代码中查找并填充组成员身份(在SQL Server之外单独进行,或者可能作为SQL Server内部的CLR程序集)

更新:有关OPENQUERY广告提供商限制的说明,请参阅:

限制
使用 要拉取的OPENQUERY语句 来自LDAP服务器的信息不起作用 受到一些限制。这个 这些限制可以在实践中规避 在某些情况下,但在其他情况下 必须更改应用程序设计。一 外部应用程序或COM对象 它使用ADSI来检索 来自LDAP服务器和服务器的信息 然后使用ADO在SQL中构建一个表 或使用其他数据访问方法 另一个可行的方法

第一个限制是
多值属性不能是 在结果集中返回给SQL 服务器。ADSI将读取模式 来自LDAP服务器的信息 定义的结构和语法 所使用的类和属性 服务器。如果该属性是 从LDAP服务器请求的是 在模式中定义为 无法在中返回多值属性 OPENQUERY语句


您可以通过获取其成员属性中包含用户的所有组,或者更好地获取用户的LDAP路径(DiscrimitedName)来实现这一点。这里有一个简单的程序来完成这项工作


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

--希尔伯特

实际上,检索用户所属的所有组的列表并不像看上去那么简单。据我所知,无论是PopSeBar还是其他脚本都不能提供完全准确的结果,即使在检索ToKEngEngy属性时,因为为了进行这种确定,还必须考虑构建组中的成员,这些成员是特定于域的。 在ActiveDirSec.org上有一个非常有用的线程,我想你可能会发现它很有用-


根据我的经验,我了解到这并不像看上去那么容易,除非您有办法确定输出是否正确,否则也无法知道脚本是否提供了正确的结果。

下面的存储过程,使用示例执行:

为用户获取ADGroups“Beau.Holland”-帐户名

注意:将LDAP://DC=Domain,DC=local替换为您自己的域

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
为用户创建过程dbo.Get\u ADGroups\u
(
@用户名NVARCHAR(256)
)
作为
开始
声明@Query-NVARCHAR(1024),@Path-NVARCHAR(1024)
--查找完全合格的CN,例如:CN=Beau Holland,OU=Users,OU=Australia,OU=NSO,OU=Company,DC=Domain,DC=local
--将“LDAP://DC=Domain,DC=local”替换为您自己的域
SET@Query='1〕
选择@Path=DiscrimitedName
从OPENQUERY(ADSI),'
选择DifferentiedName
从“LDAP://DC=Domain,DC=local”
哪里
objectClass=''用户''和
sAMAccountName=''+@用户名+'''
'')
'
EXEC SP_EXECUTESQL@Query,N'@Path NVARCHAR(1024)OUTPUT',@Path=@Path OUTPUT
--获取用户的所有组
--将“LDAP://DC=Domain,DC=local”替换为您自己的域
SET@Query='1〕
选择cn、AdsPath
来自OPENQUERY(ADSI),;(&(objectClass=group)(成员:1.2.840.113556.1.4.1941:=“+@Path+”);cn,adspath;子树“”)
EXEC SP_EXECUTESQL@Query
结束
去

@Raj:谢谢你的链接。我已经阅读了许多脚本,我能够以编程的方式完成它,比如在C#或powershell中,但我没有将它们转换为TSQL中的
LDAP
查询。我决定了解这一点的原因是,我能够在给定组名的情况下执行完全相反的操作,检索属于该组的所有用户。(为了这个目的更新了问题)是的,因为这基本上是所有单值条目的列表。用户的“memberOf”是一个单属性,它是多值的,有多个条目(与关系设计中的1NF完全相反),通过查询,您可以返回AD中的用户对象列表,并且对于每个用户对象,您只能访问和使用单值属性(cn、sn、objectCategory等)看起来我必须通过创建一个say,CLR函数/sproc来改变策略。谢谢,marc_。这是一个很好的答案,值得更多的选票。理想情况下,您可以在子查询中获得路径,但不管怎样,这都很有效。@Elias-同意。那个子树后缀非常有用。对于其他感兴趣的人,您将在上找到有关设置此类内容的更多信息。