【问题标题】:Query AD Group Membership Recursively Through SQL通过SQL递归查询AD组成员
【发布时间】:2012-12-17 13:01:13
【问题描述】:

背景

我正在创建一些 SQL 来协助进行安全审计;这将从各种系统数据库和 Active Directory 获取安全信息,并生成所有异常的列表(即帐户在一个系统中关闭但其他系统未关闭的情况。

当前代码

要获取属于安全组成员的用户列表,我运行以下 SQL:

if not exists(select 1 from sys.servers where name = 'ADSI') 
    EXEC sp_addlinkedserver 'ADSI', 'Active Directory Services 2.5', 'ADSDSOObject', 'adsdatasource'

SELECT sAMAccountName, displayName, givenName, sn, isDeleted --, lastLogonTimestamp --, lastLogon (Could not convert the data value due to reasons other than sign mismatch or overflow.)
FROM OPENQUERY(ADSI
, 'SELECT sAMAccountName, displayName, givenName, sn, isDeleted
FROM ''LDAP://DC=myDomain,DC=myCompany,DC=com''
WHERE objectCategory = ''Person''
AND objectClass = ''user'' 
AND memberOf = ''CN=mySecurityGroup,OU=Security Groups,OU=UK,DC=myDomain,DC=myCompany,DC=com''
')
order by sAMAccountName

问题/疑问

我希望这段代码能够递归工作;即,如果用户是指定组成员的组的成员,则它们也应该被包括在内(对于完整的层次结构)。有谁知道如何通过 SQL 做到这一点?

更新

我现在已经解决了一些问题(与引用的问题无关,但我遇到的其他一些问题)。

  • lastLogon 引发错误。这是因为服务器版本是 x86。使用 x64 数据库解决了这个问题。
  • lastLogon 作为数字返回。添加了一些代码以将其转换为 DateTime2。
  • 通过使 OpenQuery 本身动态化,我能够将组名从硬编码字符串中移出,因此在 OpenQuery 的上下文中生成的字符串看起来是静态的。

..

--create linked server
if not exists(select 1 from sys.servers where name = 'ADSI')
begin
    --EXEC sp_addlinkedserver 'ADSI', 'Active Directory Services 2.5', 'ADSDSOObject', 'adsdatasource'
    EXEC master.dbo.sp_addlinkedserver 'ADSI', 'Active Directory Service Interfaces', 'ADSDSOObject', 'adsdatasource'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'collation compatible',  @optvalue=N'false'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'data access', @optvalue=N'true'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'dist', @optvalue=N'false'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'pub', @optvalue=N'false'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'rpc', @optvalue=N'false'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'rpc out', @optvalue=N'false'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'sub', @optvalue=N'false'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'connect timeout', @optvalue=N'0'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'collation name', @optvalue=null
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'lazy schema validation',  @optvalue=N'false'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'query timeout', @optvalue=N'0'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'use remote collation',  @optvalue=N'true'
    EXEC master.dbo.sp_serveroption @server=N'ADSI', @optname=N'remote proc transaction promotion', @optvalue=N'true'
end


declare @path nvarchar(1024) = 'DC=myDomain,DC=myCompany,DC=com'
declare @groupCN nvarchar(1024) = 'CN=My Security Group,OU=Security Groups,OU=UK,' + @path
, @sql nvarchar(max)

--construct the query we send to AD
set @sql = '
SELECT sAMAccountName, displayName, givenName, sn, isDeleted, lastLogon
FROM ''LDAP://' + replace(@path,'''','''''') + '''
WHERE objectCategory = ''Person''
AND objectClass = ''user'' 
AND memberOf = ''' + replace(@groupCN,'''','''''') + '''
'

--now wrap that query in the outer query
set @sql = 'SELECT sAMAccountName, displayName, givenName, sn, isDeleted
, case     
    when cast([lastLogon] as bigint) = 0 then null
    else dateadd(mi,(cast([lastlogon] as bigint) / 600000000), cast(''1601-01-01'' as datetime2)) 
  end LastLogon
FROM OPENQUERY(ADSI, ''' + replace(@sql,'''','''''') + ''')
order by sAMAccountName'

--now run it
exec(@sql)

【问题讨论】:

  • ps。我对此也有一些子问题-尚未在此处发布,因为我仍在通过 Google 工作,但我想我会在 cmets 中提及,以防有人可以提供帮助。有谁知道如何获得lastLogon 值?有谁知道如何使 SQL 动态化(即,我可以为安全组使用一个变量,而不是在查询中对其进行硬编码)?在此先感谢大家。
  • lastLogon 问题归结为数据库(服务器;不是客户端)是 x86。该功能仅适用于 x64。
  • 小问题已解决 - 请参阅上面的更新以获取新代码。不过,上述问题仍然悬而未决。

标签: tsql active-directory sql-server-2008-r2 adsi ldap-query


【解决方案1】:

虽然这是一篇旧帖子,但 Google 仍然喜欢将其放在结果的顶部,所以当我在同样的问题上苦苦挣扎时,我想发布我的发现/解决方案,感谢 Riverway 获得我在正确的轨道上。

创建存储过程:

CREATE PROCEDURE [dbo].[GetLdapUserGroups]
    (
    @LdapUsername NVARCHAR(max)
    )
AS
BEGIN
DECLARE @Query NVARCHAR(max), @Path NVARCHAR(max)

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(max) OUTPUT', @Path = @Path OUTPUT 

  SET @Query = '
    SELECT cn AS [LdapGroup]
    FROM OPENQUERY (ADSI, ''<LDAP://DOMAIN.COM>;
    (&(objectClass=group)(member:1.2.840.113556.1.4.1941:= ' + @Path + '));
    cn, adspath;subtree'')
    ORDER BY cn;
'

EXEC SP_EXECUTESQL @Query
END

然后,只需传递用户名即可调用您的 SP:

DECLARE @UserGroup table (LdapGroup nvarchar(max))
INSERT INTO @UserGroup exec Datamart.dbo.GetLdapUserGroups @LdapUser

然后,我使用哈希表将 AD 组与 SQL 数据以及最终用户应该看到的内容正确匹配。

DECLARE @RptPermissions table (ldapGroup nvarchar(max),scholarshipCode nvarchar(50),gender nvarchar(2))
INSERT INTO @RptPermissions VALUES('EMP_Enrollment_Admissions','ALL','MF')

在我的例子中,我使用它来提取 SSRS 用户变量并将其传递到查询中,以根据 AD 组成员身份选择记录。

;WITH CTE_Permissions AS
(
    SELECT
        p.scholarshipCode
        ,p.gender
    FROM @UserGroup AS g
    JOIN @RptPermissions AS p ON
        g.ldapGroup = p.ldapGroup
)

...稍后在查询中

JOIN CTE_Permissions AS p ON
         s.SCHOLARSHIP_ID = p.scholarshipCode
         OR p.scholarshipCode = 'ALL'

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    像这样?

    --Get all members of a group
    SELECT cn,AdsPath 
    FROM OPENQUERY (ADSI, '<LDAP: dc="corp,dc=mycorp,dc=com">;(&(objectCategory=person)(memberOf:1.2.840.113556.1.4.1941:=CN=Administrators,CN=Builtin,DC=corp,DC=mycorp,DC=com));cn, adspath;subtree')
    ORDER BY cn; 
    
    --get all groups a user is a member of
    SELECT cn,AdsPath
    FROM OPENQUERY (ADSI, '<LDAP: dc="corp,dc=mycorp,dc=com">;(&(objectClass=group)(member:1.2.840.113556.1.4.1941:=CN=John Doe,OU=Developers,OU=Staff,DC=corp,DC=mycorp,DC=com));cn, adspath;subtree')
    ORDER BY cn;
    

    有关递归搜索条件,请参阅 http://msdn.microsoft.com/en-us/library/aa746475(VS.85).aspx

    【讨论】:

      猜你喜欢
      • 2014-08-16
      • 1970-01-01
      • 2019-11-02
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2020-06-11
      • 1970-01-01
      相关资源
      最近更新 更多