List of Database Users with Database Roles

  • Comments posted to this topic are about the content posted at http://www.sqlservercentral.com/columni


    1234

  • Elegant and simple in design, nice in execution.  While the scripts themselves are useful, the written example of how to use a cursor was even more useful.

    Now I can start re-writing that awful procedure I inherited from a now defunct developer to make it work like it should have done all along!

    Thanks!

    Ant Butler.

  • Thank you for this as I am working on the same issue right now.

  • Suggest adding:

    SET @mSQL1 = 'TRUNCATE TABLE dbo.DBRoles'

    EXECUTE (@mSql1)

    After the initial DECLARE's to clear out the table if you run the Proc more than once.  (Assumes you created the table under dbo). (Chose dynamic SQL in keeping with the style of the proc.)

    Alternativey, you may want to include some "NOT EXISTS" logic to prevent adding duplicate role information, assuming the cur_date field enables you to track changes over time.

  • Here's a version that doesn't require the DBRoles table and executes the final SELECT with parameters so you can just execute List_DBRoles and specify things like "@dbo='Y' " or "@user='RS02130' " and get the results back immediately. It's pretty flexible.

    CREATE procedure dbo.List_DBRoles

    (

    @database nvarchar(128)=null,

    @user varchar(20)=null,

    @dbo char(1)=null,

    @access char(1)=null,

    @security char(1)=null,

    @ddl char(1)=null,

    @datareader char(1)=null,

    @datawriter char(1)=null,

    @denyread char(1)=null,

    @denywrite char(1)=null

    )

    as

    declare @dbname varchar(200)

    declare @mSql1 varchar(8000)

    CREATE TABLE #DBROLES

    ( DBName sysname not null,

      UserName sysname not null,

      db_owner varchar(3) not null,

      db_accessadmin varchar(3) not null,

      db_securityadmin varchar(3) not null,

      db_ddladmin varchar(3) not null,

      db_datareader varchar(3) not null,

      db_datawriter varchar(3) not null,

      db_denydatareader varchar(3) not null,

      db_denydatawriter varchar(3) not null,

      Cur_Date datetime not null default getdate()

    )

    DECLARE DBName_Cursor CURSOR FOR

     select name

     from master.dbo.sysdatabases

     where name not in ('mssecurity','tempdb')

     Order by name

    OPEN DBName_Cursor

    FETCH NEXT FROM DBName_Cursor INTO @dbname

    WHILE @@FETCH_STATUS = 0

     BEGIN

      Set @mSQL1 = ' Insert into #DBROLES ( DBName, UserName, db_owner, db_accessadmin,

                      db_securityadmin, db_ddladmin, db_datareader, db_datawriter,

                    db_denydatareader, db_denydatawriter )

     SELECT '+''''+@dbName +''''+ ' as DBName ,UserName, '+char(13)+ ' 

        Max(CASE RoleName WHEN ''db_owner''    THEN ''Yes'' ELSE ''No'' END) AS db_owner,

      Max(CASE RoleName WHEN ''db_accessadmin ''   THEN ''Yes'' ELSE ''No'' END) AS db_accessadmin ,

      Max(CASE RoleName WHEN ''db_securityadmin''  THEN ''Yes'' ELSE ''No'' END) AS db_securityadmin,

      Max(CASE RoleName WHEN ''db_ddladmin''    THEN ''Yes'' ELSE ''No'' END) AS db_ddladmin,

      Max(CASE RoleName WHEN ''db_datareader''    THEN ''Yes'' ELSE ''No'' END) AS db_datareader,

      Max(CASE RoleName WHEN ''db_datawriter''    THEN ''Yes'' ELSE ''No'' END) AS db_datawriter,

        Max(CASE RoleName WHEN ''db_denydatareader'' THEN ''Yes'' ELSE ''No'' END) AS db_denydatareader,

      Max(CASE RoleName WHEN ''db_denydatawriter'' THEN ''Yes'' ELSE ''No'' END) AS db_denydatawriter

     from (

           select b.name as USERName, c.name as RoleName

           from ' + @dbName+'.dbo.sysmembers a '+char(13)+

       ' join '+ @dbName+'.dbo.sysusers  b '+char(13)+

            ' on a.memberuid = b.uid  join '+@dbName +'.dbo.sysusers c

              on a.groupuid = c.uid )s  

         Group by USERName

             order by UserName'

      --Print @mSql1

      Execute (@mSql1)

      FETCH NEXT FROM DBName_Cursor INTO @dbname

     END

    CLOSE DBName_Cursor

    DEALLOCATE DBName_Cursor

    Select * from #DBRoles

    where ((@database is null) OR (DBName LIKE '%'+@database+'%')) AND

     ((@user is null) OR (UserName LIKE '%'+@user+'%')) AND

     ((@dbo is null) OR  (db_owner = 'Yes')) AND

     ((@access is null) OR  (db_accessadmin = 'Yes')) AND

     ((@security is null) OR  (db_securityadmin = 'Yes')) AND

     ((@ddl is null) OR  (db_ddladmin = 'Yes')) AND

     ((@datareader is null) OR (db_datareader = 'Yes')) AND

     ((@datawriter is null) OR  (db_datawriter = 'Yes')) AND

     ((@denyread is null) OR  (db_denydatareader = 'Yes')) AND

     ((@denywrite is null) OR (db_denydatawriter = 'Yes'))

    GO

     

  • ...MS Supplies the following:

    Exec sp_HelpLogins

    Exec sp_HelpUser

    Exec sp_HelProtect

    Exec sp_HelpSrvRoleMember

    Exec sp_HelpRoleMember

  • Based on some quick empirical testing the above SP's only apply to the current database. The new SP posted above lists all relevant data (OK, we could add SID if you really want it) for all databases on the server assuming you have appropriate access to dbo.sysmembers and dbo.sysusers. I believe in a standard SQL Server setup everyone has READ access to these tables so the SP consolidates a lot of information in one place. The MS SP's (it seems) have to be run in each DB separately and the information correlated.

     

  • > The MS SP's (it seems) have to be run in each DB separately and the information correlated.

    Use Master

    Go

    Exec master..sp_HelpUser

    Exec pubs..sp_HelpUser

    Exec northwind..sp_HelpUser

  • Still, you have to run it against each DB as opposed to the posted SP which gets all the DB names from master.dbo.sysdatabases and recurses the list. OK, it uses a cursor. When I have some time maybe I'll see if I can convert it to set-based processing.

     

  • Great piece of work, I have meant to do this for quite awhile...

    Two minor suggestions:

    One, may want to use consistent casing in case you run this procedure in a "case sensitive" environment.

    Secondly, may want to add a check to bypass any database that is temporarily offline:

    and databaseproperty(name, 'IsOffline') = 0

    Cheers!

     

     

     

  • Interesting, though a bit long winded way to do it. Lots of good tips in this thread though.

    John Scarborough
    MCDBA, MCSA

  • Superb!

    Joining sysmembers and sysusers is a superb idea.

    Just used it in a recovery from crash.

    Thank you

  • Great stuff. This has been here a while bit if anyone is interested. Similiar code.

    Slightly modified to work with SQLOverview. With it I can hit several servers. Now I get the data I am looking for a way to determine any changes. I have some ideas to determine changes or additions to any database/user/roles. Anyone done anything like this with out a trigger?

    IF EXISTS

    (SELECT *

    FROM tempdb.dbo.sysobjects

    WHERE id = OBJECT_ID(N'[tempdb].[dbo].[DBROLES]')

    )

    DROP TABLE [tempdb].[dbo].[DBROLES]

    GO

    SET ANSI_NULLS ON

    GO

    SET QUOTED_IDENTIFIER ON

    GO

    SET ANSI_PADDING ON

    GO

    CREATE TABLE [tempdb].[dbo].[DBROLES](

    [ServerName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL CONSTRAINT [DF_DBROLES_ServerName] DEFAULT (N'.'),

    [DBName] [sysname] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

    [UserName] [sysname] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

    [db_owner] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

    [db_accessadmin] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

    [db_securityadmin] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

    [db_ddladmin] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

    [db_datareader] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

    [db_datawriter] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

    [db_denydatareader] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

    [db_denydatawriter] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

    [createdate] [datetime] NOT NULL,

    [updatedate] [datetime] NOT NULL,

    [Cur_Date] [datetime] NOT NULL CONSTRAINT [DF__DBROLES__Cur_Dat__3A179ED3] DEFAULT (getdate())

    ) ON [PRIMARY]

    GO

    INSERT INTO [tempdb].[dbo].[DBROLES]

    EXEC sp_MSForEachDB

    'SELECT CONVERT(nvarchar(128), SERVERPROPERTY(''Servername'')) AS ServerName,

    ''?'' as DBName,

    UserName,

    Max(CASE RoleName WHEN ''db_owner'' THEN ''Yes'' ELSE ''No'' END) AS db_owner,

    Max(CASE RoleName WHEN ''db_accessadmin '' THEN ''Yes'' ELSE ''No'' END) AS db_accessadmin ,

    Max(CASE RoleName WHEN ''db_securityadmin'' THEN ''Yes'' ELSE ''No'' END) AS db_securityadmin,

    Max(CASE RoleName WHEN ''db_ddladmin'' THEN ''Yes'' ELSE ''No'' END) AS db_ddladmin,

    Max(CASE RoleName WHEN ''db_datareader'' THEN ''Yes'' ELSE ''No'' END) AS db_datareader,

    Max(CASE RoleName WHEN ''db_datawriter'' THEN ''Yes'' ELSE ''No'' END) AS db_datawriter,

    Max(CASE RoleName WHEN ''db_denydatareader'' THEN ''Yes'' ELSE ''No'' END) AS db_denydatareader,

    Max(CASE RoleName WHEN ''db_denydatawriter'' THEN ''Yes'' ELSE ''No'' END) AS db_denydatawriter,

    createdate,

    updatedate,

    GETDATE()

    from (

    select b.name as USERName, c.name as RoleName, b.createdate, b.updatedate

    from [?].dbo.sysmembers a

    join [?].dbo.sysusers b on a.memberuid = b.uid

    join [?].dbo.sysusers c

    on a.groupuid = c.uid )s

    Group by USERName, createdate, updatedate

    order by UserName'

    SET ANSI_PADDING OFF

  • After executing this I got a list of all users and their database access and roles. Then I realized something was missing. I used to login to sql server 2000 and execute sql statements. I am local system admin. I can see a login named Builtin\Administrator under security and this has access to all database as db_public and db_owner.

    Here i have 2 questions

    1. Why is Builtin\administrators not listed ? doest that mean that the procedure and query given in the link is wrong.

    2. I can see certain users who has access to few of the databases. But these users are not in the login section under security. How can a user have access to database without a login ?

    I would be extremely thankful to you could clarify my queries.

    Thanks

  • hi how would you run this for one login?

Viewing 15 posts - 1 through 15 (of 19 total)

You must be logged in to reply to this topic. Login to reply