Active Directory Query

Find out to which AD group a login belongs or find out who the members of a group are.

use master
go
EXEC xp_logininfo N'<your AD login>','ALL';
GO

use master
go
EXEC xp_logininfo N'<your AD Group>','MEMBERS';
GO

So what can we make with these functions?
Well I was for example intrested in who are in the active directory groups and so who in that group have what kind of permissions on the databases.

This is what I made

use master
GO

DECLARE @LoginName nvarchar(256)

SET NOCOUNT ON; 

-- Create a temp table to store exceptions
drop table if exists #Exceptions;
create table #Exceptions
(
   Id int identity(1,1)
  ,ErrorNumber int
  ,ErrorSeverity int
  ,ErrorState int
  ,ErrorMessage nvarchar(1024)
)

-- Create a temp table to store all AD groups that are mapped in SQL server
drop table if exists #WindowsGroups;
create table #WindowsGroups
(
   GroupName nvarchar(256)
  ,CheckedForMembers bit default 0
)
insert into #WindowsGroups (GroupName)
select name as 'GroupName' FROM sys.server_principals where type_desc = 'WINDOWS_GROUP'

-- create a temp stage table
DROP TABLE IF EXISTS #GroupMembers;
CREATE TABLE #GroupMembers
(
   Id int identity(1,1)
  ,AccountName nvarchar(256)
  ,AccountType nvarchar(128)
  ,Privilege nvarchar(256)
  ,MappedLoginName nvarchar(256)
  ,PermissionsPath nvarchar(512)
)
-- create a temp stage table
DECLARE @GroupMembers TABLE 
(
   AccountName nvarchar(256)
  ,AccountType nvarchar(128)
  ,Privilege nvarchar(256)
  ,MappedLoginName nvarchar(256)
  ,PermissionsPath nvarchar(512)
)

DECLARE GroupCursor CURSOR FOR
SELECT 
 GroupName
,SqlCommand = 
  case 
    when type_desc = 'WINDOWS_GROUP' 
    then concat('EXEC xp_logininfo N''',name, ''', ''members''',';') 
  end
FROM sys.server_principals as s
join #WindowsGroups as g on s.name = g.GroupName and CheckedForMembers = 0
where type_desc = 'WINDOWS_GROUP'

DECLARE @GroupName nvarchar(256), @xp_logininfo nvarchar(max)
OPEN GroupCursor  
FETCH NEXT FROM GroupCursor INTO @GroupName, @xp_logininfo
WHILE (select top 1 1 FROM sys.server_principals as s join #WindowsGroups as g on s.name = g.GroupName and CheckedForMembers = 0) = 1
BEGIN  
  begin try
    print @GroupName
    update #WindowsGroups 
    set CheckedForMembers = 1 
    where GroupName = @GroupName

    insert into @GroupMembers (AccountName, AccountType, Privilege, MappedLoginName, PermissionsPath)
    exec sp_executesql @xp_logininfo

    -- insert all users into temp #GroupMembers table
    insert into #GroupMembers (AccountName, AccountType, Privilege, MappedLoginName, PermissionsPath)
    select AccountName, AccountType, Privilege, MappedLoginName, PermissionsPath
    from @GroupMembers
    where AccountType = 'user'

    -- add newly found groups into the #Windows templ table so that it too will loop by this cursor
    insert into #WindowsGroups (GroupName)
    select AccountName from @GroupMembers where AccountType = 'group' and AccountName not in (select GroupName from #WindowsGroups)

  end try
  begin catch
    -- collect exceptions into temp #exception table
    insert into #Exceptions (ErrorNumber, ErrorSeverity, ErrorState, ErrorMessage)
    SELECT  
       ERROR_NUMBER() AS ErrorNumber  
      ,ERROR_SEVERITY() AS ErrorSeverity  
      ,ERROR_STATE() AS ErrorState  
      ,ERROR_MESSAGE() AS ErrorMessage;  
  end catch	
  FETCH NEXT FROM GroupCursor INTO @GroupName, @xp_logininfo
END 
CLOSE GroupCursor  
DEALLOCATE GroupCursor 

-- Find the AD groups to whitch a AD Login belongs
DROP TABLE IF EXISTS #AllSqlLoginsExtraced;
CREATE TABLE #AllSqlLoginsExtraced
(
   Id int identity(1,1)
  ,AccountName nvarchar(256)
  ,AccountType nvarchar(128)
  ,Privilege nvarchar(256)
  ,MappedLoginName nvarchar(256)
  ,MemberOfAdGroupInSql nvarchar(512)
);

DECLARE @xp_logininfo2 nvarchar(256), @AccountName nvarchar(256)
DECLARE LoginCursor CURSOR FOR
with CteLogin
as
(
  select distinct AccountName from #GroupMembers
  union
  select Name FROM sys.server_principals where type_desc = 'WINDOWS_LOGIN'
) 
select concat('exec xp_logininfo ''', AccountName ,''', ''all'''), AccountName
from CteLogin

OPEN LoginCursor  
FETCH NEXT FROM LoginCursor INTO @xp_logininfo2, @AccountName
WHILE @@FETCH_STATUS = 0
BEGIN  
  begin try
    insert into #AllSqlLoginsExtraced (AccountName, AccountType, Privilege, MappedLoginName, MemberOfAdGroupInSql)
    exec sp_executesql @xp_logininfo2

    if @@ROWCOUNT = 0
    begin 
      insert into #AllSqlLoginsExtraced (AccountName, MemberOfAdGroupInSql) values (@AccountName, '{NON}')
    end
  end try
  begin catch
    insert into #Exceptions (ErrorNumber, ErrorSeverity, ErrorState, ErrorMessage)
    SELECT  
       ERROR_NUMBER() AS ErrorNumber  
      ,ERROR_SEVERITY() AS ErrorSeverity  
      ,ERROR_STATE() AS ErrorState  
      ,ERROR_MESSAGE() AS ErrorMessage;  
  end catch	
  FETCH NEXT FROM LoginCursor INTO @xp_logininfo2, @AccountName
END 
CLOSE LoginCursor  
DEALLOCATE LoginCursor 

/*
url: https://stackoverflow.com/questions/7048839/sql-server-query-to-find-all-permissions-access-for-all-users-in-a-database

Security Audit Report
1) List all access provisioned to a sql user or windows user/group directly 
2) List all access provisioned to a sql user or windows user/group through a database or application role
3) List all access provisioned to the public role

Columns Returned:
UserName        : SQL or Windows/Active Directory user cccount.  This could also be an Active Directory group.
UserType        : Value will be either 'SQL User' or 'Windows User'.  This reflects the type of user defined for the 
                  SQL Server user account.
DatabaseUserName: Name of the associated user as defined in the database user account.  The database user may not be the
                  same as the server user.
Role            : The role name.  This will be null if the associated permissions to the object are defined at directly
                  on the user account, otherwise this will be the name of the role that the user is a member of.
PermissionType  : Type of permissions the user/role has on an object. Examples could include CONNECT, EXECUTE, SELECT
                  DELETE, INSERT, ALTER, CONTROL, TAKE OWNERSHIP, VIEW DEFINITION, etc.
                  This value may not be populated for all roles.  Some built in roles have implicit permission
                  definitions.
PermissionState : Reflects the state of the permission type, examples could include GRANT, DENY, etc.
                  This value may not be populated for all roles.  Some built in roles have implicit permission
                  definitions.
ObjectType      : Type of object the user/role is assigned permissions on.  Examples could include USER_TABLE, 
                  SQL_SCALAR_FUNCTION, SQL_INLINE_TABLE_VALUED_FUNCTION, SQL_STORED_PROCEDURE, VIEW, etc.   
                  This value may not be populated for all roles.  Some built in roles have implicit permission
                  definitions.          
ObjectName      : Name of the object that the user/role is assigned permissions on.  
                  This value may not be populated for all roles.  Some built in roles have implicit permission
                  definitions.
ColumnName      : Name of the column of the object that the user/role is assigned permissions on. This value
                  is only populated if the object is a table, view or a table value function.                 
*/

--List all access provisioned to a sql user or windows user/group directly 
SET NOCOUNT ON;

declare @SqlCommand nvarchar(max)
set @SqlCommand = '
--List all access provisioned to a sql user or windows user/group directly
SELECT 
 DB_NAME(DB_ID()) AS DatabaseName
,[UserName] = CASE princ.[type]
WHEN ''S''
THEN princ.[name]
WHEN ''U''
THEN ulogin.[name] COLLATE Latin1_General_CI_AI
END
,UserType = princ.[type_desc]
--,[UserType] = CASE princ.[type]
--WHEN ''S''
--THEN ''SQL User''
--WHEN ''U''
--THEN ''Windows User''
--END
,[DatabaseUserName] = princ.[name]
,[Role] = NULL
,[PermissionType] = PERM.[permission_name]
,[PermissionState] = PERM.[state_desc]
,[ObjectType] = obj.type_desc
,[ObjectName] = OBJECT_NAME(PERM.major_id)
,[ColumnName] = col.[name]
FROM sys.database_principals princ
LEFT JOIN sys.login_token ulogin ON princ.[sid] = ulogin.[sid]
LEFT JOIN sys.database_permissions PERM ON PERM.[grantee_principal_id] = princ.[principal_id]
LEFT JOIN sys.columns col ON col.[object_id] = PERM.major_id
AND col.[column_id] = PERM.[minor_id]
LEFT JOIN sys.objects obj ON PERM.[major_id] = obj.[object_id]
WHERE princ.[type] IN (''S'',''U'')
UNION
SELECT 
 DB_NAME(DB_ID()) AS DatabaseName
,[UserName] = CASE memberprinc.[type]
WHEN ''S''
THEN memberprinc.[name]
WHEN ''U''
THEN ulogin.[name] COLLATE Latin1_General_CI_AI
END
,UserType = memberprinc.[type_desc]
--,[UserType] = CASE memberprinc.[type]
--WHEN ''S''
--THEN ''SQL User''
--WHEN ''U''
--THEN ''Windows User''
--END
,[DatabaseUserName] = memberprinc.[name]
,[Role] = roleprinc.[name]
,[PermissionType] = PERM.[permission_name]
,[PermissionState] = PERM.[state_desc]
,[ObjectType] = obj.type_desc
,[ObjectName] = OBJECT_NAME(PERM.major_id)
,[ColumnName] = col.[name]
FROM sys.database_role_members members
INNER JOIN sys.database_principals roleprinc ON roleprinc.[principal_id] = members.[role_principal_id]
INNER JOIN sys.database_principals memberprinc ON memberprinc.[principal_id] = members.[member_principal_id]
LEFT JOIN sys.login_token ulogin ON memberprinc.[sid] = ulogin.[sid]
LEFT JOIN sys.database_permissions PERM ON PERM.[grantee_principal_id] = roleprinc.[principal_id]
LEFT JOIN sys.columns col ON col.[object_id] = PERM.major_id
AND col.[column_id] = PERM.[minor_id]
LEFT JOIN sys.objects obj ON PERM.[major_id] = obj.[object_id]
UNION
SELECT 
 DB_NAME(DB_ID()) AS DatabaseName
,[UserName] = ''{All Users}''
,[UserType] = ''{All Users}''
,[DatabaseUserName] = ''{All Users}''
,[Role] = roleprinc.[name]
,[PermissionType] = PERM.[permission_name]
,[PermissionState] = PERM.[state_desc]
,[ObjectType] = obj.type_desc
,[ObjectName] = OBJECT_NAME(PERM.major_id)
,[ColumnName] = col.[name]
FROM sys.database_principals roleprinc
LEFT JOIN sys.database_permissions PERM ON PERM.[grantee_principal_id] = roleprinc.[principal_id]
LEFT JOIN sys.columns col ON col.[object_id] = PERM.major_id
AND col.[column_id] = PERM.[minor_id]
INNER JOIN --All objects
sys.objects obj ON obj.[object_id] = PERM.[major_id]
WHERE
roleprinc.[type] = ''R'' AND
roleprinc.[name] = ''public'' AND
obj.is_ms_shipped = 0
ORDER BY princ.[Name]
,OBJECT_NAME(PERM.major_id)
,col.[name]
,PERM.[permission_name]
,PERM.[state_desc]
,obj.type_desc --perm.[class_desc]'

drop table if exists #SqlSecurity
create table #SqlSecurity
(
   DatabaseName nvarchar(512)
  ,UserName nvarchar(256)
  ,UserType nvarchar(256)
  ,DatabaseUserName nvarchar(512)
  ,RoleName nvarchar(256)
  ,PermissionType nvarchar(256)
  ,PermissionsState nvarchar(256)
  ,ObjectType nvarchar(256)
  ,ObjectName nvarchar(256)
  ,ColumName nvarchar(256)
)

DECLARE @DbName VARCHAR(256) -- database name 
DEclare @SqlCommand2 nvarchar(max)

DECLARE db_cursor CURSOR FOR 
SELECT name 
FROM MASTER.dbo.sysdatabases 

OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @DbName  

WHILE @@FETCH_STATUS = 0  
BEGIN  
  DECLARE @ExecuteSql nvarchar(max) = 'use ['+@DbName+']; ' + @SqlCommand
  INSERT INTO #SqlSecurity 
  EXEC sp_executesql @ExecuteSql
  FETCH NEXT FROM db_cursor INTO @DbName 
END 

CLOSE db_cursor  
DEALLOCATE db_cursor 

-- create indexes
create nonclustered index ix_#AllSqlLoginsExtraced_AccountName on #AllSqlLoginsExtraced(AccountName) with (fillfactor = 100)
create nonclustered index ix_#AllSqlLoginsExtraced_MemberOfAdGroupInSql on #AllSqlLoginsExtraced(MemberOfAdGroupInSql) with (fillfactor = 100)
create nonclustered index ix_#SqlSecurity_DatabaseUserName on #SqlSecurity(DatabaseUserName) with (fillfactor = 100)

-- drop temp tables we no longer need
drop table #WindowsGroups
drop table #GroupMembers


-- To return the members of the server roles ( SQL Server only), execute the following statement.
SELECT DISTINCT
 sRole.name AS [ServerRoleName] 
,sPrinc.name AS [LoginOrGroup]
,a.AccountName as MembersOfGroup

FROM sys.server_role_members AS sRo  
JOIN sys.server_principals AS sPrinc  
    ON sRo.member_principal_id = sPrinc.principal_id  
JOIN sys.server_principals AS sRole  
    ON sRo.role_principal_id = sRole.principal_id
LEFT JOIN #AllSqlLoginsExtraced as a on sPrinc.name = a.MemberOfAdGroupInSql
where sPrinc.name = @LoginName or @LoginName is null;

select 
 AccountName
,Privilege
,MemberOfAdGroupInSql
,s.*
from #AllSqlLoginsExtraced as a
left join #SqlSecurity as s on a.AccountName = s.DatabaseUserName or a.MemberOfAdGroupInSql = s.DatabaseUserName
where @LoginName is null or @LoginName = AccountName or @LoginName = s.DatabaseUserName
order by MemberOfAdGroupInSql asc


-- show exceptions
select * from #Exceptions
GO