Tsql 通过SQL递归查询AD组成员
背景 我正在创建一些SQL来帮助进行安全审计;这将从各种系统数据库和Active Directory中获取安全信息,并生成所有异常情况的列表(即,在一个系统中关闭帐户但在其他系统中未关闭帐户的情况) 当前代码 要获取作为安全组成员的用户列表,我运行以下SQL:Tsql 通过SQL递归查询AD组成员,tsql,active-directory,sql-server-2008-r2,adsi,ldap-query,Tsql,Active Directory,Sql Server 2008 R2,Adsi,Ldap Query,背景 我正在创建一些SQL来帮助进行安全审计;这将从各种系统数据库和Active Directory中获取安全信息,并生成所有异常情况的列表(即,在一个系统中关闭帐户但在其他系统中未关闭帐户的情况) 当前代码 要获取作为安全组成员的用户列表,我运行以下SQL: if not exists(select 1 from sys.servers where name = 'ADSI') EXEC sp_addlinkedserver 'ADSI', 'Active Directory Ser
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的上下文中,生成的字符串看起来是静态的
--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;
——获取组的所有成员
选择cn、AdsPath
来自OPENQUERY(ADSI,;(&(objectCategory=person)(memberOf:1.2.840.113556.1.4.1941:=CN=Administrators,CN=Builtin,DC=corp,DC=mycorp,DC=com));CN,adspath;子树')
cn发出的命令;
--获取用户所属的所有组
选择cn、AdsPath
来自OPENQUERY(ADSI,;(&(objectClass=group)(成员:1.2.840.113556.1.4.1941:=CN=johndoe,OU=Developers,OU=Staff,DC=corp,DC=mycorp,DC=com));CN,adspath;子树')
cn发出的命令;
查看递归搜索条件。虽然这是一篇老文章,但谷歌仍然喜欢将其放在搜索结果的顶部,因此,当我为同样的问题苦苦挣扎时,我想发布我的发现/解决方案,这要归功于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
然后,我使用哈希表将AD组与SQL数据以及最终用户应该看到的内容正确匹配
DECLARE @RptPermissions table (ldapGroup nvarchar(max),scholarshipCode nvarchar(50),gender nvarchar(2))
INSERT INTO @RptPermissions VALUES('EMP_Enrollment_Admissions','ALL','MF')
在我的例子中,我使用它来提取SSRS用户变量,并将其传递到查询中,以便根据广告组成员资格选择记录
;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'
希望这能有所帮助。ps.我还有一些关于这方面的子问题-我还没有在这里发布,因为我还在谷歌工作,但我想我会在评论中提到,以防有人能提供帮助。有人知道如何获取
lastLogon
值吗?有人知道如何使SQL动态化吗(也就是说,我可以为安全组使用一个变量,而不是在查询中对其进行硬编码)?提前感谢大家。lastLogon
问题在于DB(服务器;而不是客户端)是x86。该功能仅在x64上起作用。解决了一些小问题-有关新代码,请参阅上面的更新。尽管如此,上述问题仍然存在。
;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'