T-SQL: Retrieve all users and associated roles for ALL databases

Jan 24, 2012 / By Mohammed Mawla

Tags: , ,

A frequent inquiry concerning databases’ security is to retrieve the database role(s) associated with each user for auditing or troubleshooting purposes.

Each database user (principal) can be retrieved from sys.database_principals and the associated database roles can be retrieved from sys.database_role_members

The following code runs against ALL the databases using SP_MSForeachdb and all roles for one principal is concatenated in one row


DECLARE @DB_USers TABLE
(DBName sysname, UserName sysname, LoginType sysname, AssociatedRole varchar(max),create_date datetime,modify_date datetime)

INSERT @DB_USers
EXEC sp_MSforeachdb

'
use [?]
SELECT ''?'' AS DB_Name,
case prin.name when ''dbo'' then prin.name + '' (''+ (select SUSER_SNAME(owner_sid) from master.sys.databases where name =''?'') + '')'' else prin.name end AS UserName,
prin.type_desc AS LoginType,
isnull(USER_NAME(mem.role_principal_id),'''') AS AssociatedRole ,create_date,modify_date
FROM sys.database_principals prin
LEFT OUTER JOIN sys.database_role_members mem ON prin.principal_id=mem.member_principal_id
WHERE prin.sid IS NOT NULL and prin.sid NOT IN (0x00) and
prin.is_fixed_role <> 1 AND prin.name NOT LIKE ''##%'''

SELECT

dbname,username ,logintype ,create_date ,modify_date ,

STUFF(

(

SELECT ',' + CONVERT(VARCHAR(500),associatedrole)

FROM @DB_USers user2

WHERE

user1.DBName=user2.DBName AND user1.UserName=user2.UserName

FOR XML PATH('')

)

,1,1,'') AS Permissions_user

FROM @DB_USers user1

GROUP BY

dbname,username ,logintype ,create_date ,modify_date

ORDER BY DBName,username

The code applies few filters:

- No Guest user account; you should NOT enable a guest account for a production database.

- Skip fixed database roles such as DB_OWNER , db_datawriter,db_datareader,….etc

- Principals with NULL SID ; those are internal to the DB such as INFORMATION_SCHEMA & sys

Remarks

- SYSADMINS don’t need to be part of explicit database’s users list to gain access as they have access to everything on server. You can get list of SYSADMIN users by running following code

SELECT
p.name AS [Name] ,r.type_desc,r.is_disabled,r.create_date , r.modify_date,r.default_database_name
FROM
sys.server_principals r
INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id
INNER JOIN sys.server_principals p ON
p.principal_id = m.member_principal_id
WHERE r.type = 'R' and r.name = N'sysadmin'

- If a windows login is part of a windows group then you may need to look at the members of this Windows group to identify who can access this database.

- A user may still be revoked access to database indvidual objects even the role allows access normally.

Following blog has a query to list permissions on indvidual objects

http://consultingblogs.emc.com/jamiethomson/archive/2007/02/09/SQL-Server-2005_3A00_-View-all-permissions–_2800_2_2900_.aspx

HTH
M

11 Responses to “T-SQL: Retrieve all users and associated roles for ALL databases”

  • vicky says:

    totally beautiful script. well written. thanks for this.

    cheers

    • patrick says:

      I keep receiving this msg when I execute the script.
      Msg 515, Level 16, State 2, Line 4
      Cannot insert the value NULL into column ‘UserName’, table ‘@DB_USers’; column does not allow nulls. INSERT fails.
      The statement has been terminated.

      (0 row(s) affected)

      • rajesh says:

        declare username sysname is null like below

        DECLARE @DB_USers TABLE(DBName sysname, UserName sysname null,

  • ms engineer says:

    Great script you are the best

  • Christophe says:

    A real time saver thanks !!

  • blogongal says:

    Fantastic script. Saved me hours of work.

  • Jamie says:

    Hi – The last SQL block may not be quite right. The version of server_principals shown in the SELECT block should be the one aliased “p”, not “r”. This version may produce better results;

    SELECT p.name AS [Name] ,
    p.type_desc,
    p.is_disabled ,
    p.create_date ,
    p.modify_date ,
    p.default_database_name
    FROM sys.server_principals r
    INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id
    INNER JOIN sys.server_principals p ON p.principal_id = m.member_principal_id
    AND p.is_disabled = 0
    WHERE r.type = ‘R’
    AND r.name = N’sysadmin’

  • Laura says:

    Maybe this code would help someone:

    BEGIN

    DECLARE @Date SMALLDATETIME

    SET @Date = CAST(CAST(GETDATE() AS DATE) AS SMALLDATETIME)

    SELECT CONVERT(VARCHAR(250), SERVERPROPERTY(‘ServerName’)) AS ServerName, SP1.[name] AS [Login], SP2.[name] AS ServerRole, SP1.is_disabled AS IsDisabled, @Date AS ExtractDate
    FROM sys.server_principals SP1
    INNER JOIN sys.server_role_members SRM ON SP1.principal_id = SRM.member_principal_id
    INNER JOIN sys.server_principals SP2 ON SRM.role_principal_id = SP2.principal_id
    WHERE SP1.[name] NOT IN (‘NT Service\MSSQLSERVER’,'NT SERVICE\SQLSERVERAGENT’,'NT SERVICE\SQLWriter’,'NT SERVICE\Winmgmt’,
    ‘NT AUTHORITY\SYSTEM’,'NT AUTHORITY\NETWORK SERVICE’)
    ;

    END

  • Sriharsha Gurram says:

    Nice Script, it would be better if it has the ability to generate user creation and role allocation commands which can be used during database migrations.

  • Brooks says:

    Great script, thanks M! What would I need to change to have it include User Groups? (or run separately for User Groups)

Leave a Reply

  • (will not be published)

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>