【问题标题】:SQL Server query to find all permissions/access for all users in a databaseSQL Server 查询以查找数据库中所有用户的所有权限/访问权限
【发布时间】:2011-10-26 07:18:07
【问题描述】:

我想在 sql 2008 上编写一个查询,该查询将报告所有有权访问特定数据库的用户,或数据库中的对象,例如表、视图和存储过程,直接或由于角色,等。此报告将用于安全审计目的。不确定是否有人有完全符合我需求的查询,但希望能给我一个好的开始。 sql 2008、2005 或 2000 都可以,我可以根据需要进行转换。

【问题讨论】:

  • 我希望我有这样的查询 - 我很想看到谁可以访问一个对象的列表,所以我希望你能得到答案!
  • 不确定 Jeremy 是否希望角色扩展,但我愿意。 :)

标签: sql-server sql-server-2005 sql-server-2008


【解决方案1】:

根据 Andomar 的建议,这是我对查询的第一次破解。此查询旨在提供用户直接应用到用户帐户或通过 用户拥有的角色。

/*
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 account.  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 
SELECT  
    [UserName] = CASE princ.[type] 
                    WHEN 'S' THEN princ.[name]
                    WHEN 'U' THEN ulogin.[name] COLLATE Latin1_General_CI_AI
                 END,
    [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,--perm.[class_desc],       
    [ObjectName] = OBJECT_NAME(perm.major_id),
    [ColumnName] = col.[name]
FROM    
    --database user
    sys.database_principals princ  
LEFT JOIN
    --Login accounts
    sys.login_token ulogin on princ.[sid] = ulogin.[sid]
LEFT JOIN        
    --Permissions
    sys.database_permissions perm ON perm.[grantee_principal_id] = princ.[principal_id]
LEFT JOIN
    --Table columns
    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
--List all access provisioned to a sql user or windows user/group through a database or application role
SELECT  
    [UserName] = CASE memberprinc.[type] 
                    WHEN 'S' THEN memberprinc.[name]
                    WHEN 'U' THEN ulogin.[name] COLLATE Latin1_General_CI_AI
                 END,
    [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,--perm.[class_desc],   
    [ObjectName] = OBJECT_NAME(perm.major_id),
    [ColumnName] = col.[name]
FROM    
    --Role/member associations
    sys.database_role_members members
JOIN
    --Roles
    sys.database_principals roleprinc ON roleprinc.[principal_id] = members.[role_principal_id]
JOIN
    --Role members (database users)
    sys.database_principals memberprinc ON memberprinc.[principal_id] = members.[member_principal_id]
LEFT JOIN
    --Login accounts
    sys.login_token ulogin on memberprinc.[sid] = ulogin.[sid]
LEFT JOIN        
    --Permissions
    sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id]
LEFT JOIN
    --Table columns
    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
--List all access provisioned to the public role, which everyone gets by default
SELECT  
    [UserName] = '{All Users}',
    [UserType] = '{All Users}', 
    [DatabaseUserName] = '{All Users}',       
    [Role] = roleprinc.[name],      
    [PermissionType] = perm.[permission_name],       
    [PermissionState] = perm.[state_desc],       
    [ObjectType] = obj.type_desc,--perm.[class_desc],  
    [ObjectName] = OBJECT_NAME(perm.major_id),
    [ColumnName] = col.[name]
FROM    
    --Roles
    sys.database_principals roleprinc
LEFT JOIN        
    --Role permissions
    sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id]
LEFT JOIN
    --Table columns
    sys.columns col on col.[object_id] = perm.major_id 
                    AND col.[column_id] = perm.[minor_id]                   
JOIN 
    --All objects   
    sys.objects obj ON obj.[object_id] = perm.[major_id]
WHERE
    --Only roles
    roleprinc.[type] = 'R' AND
    --Only public role
    roleprinc.[name] = 'public' AND
    --Only objects of ours, not the MS objects
    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] 

【讨论】:

  • 这正是我的业务用户想要看到的,因为它扩展了角色,因此您可以看到每个用户有权访问的所有单个对象。需要很长时间才能运行,但谁在乎呢。
  • 这是一个很棒的脚本,但我不得不对其进行一些调整以更好地考虑模式。当 perm.class_desc 设置为 SCHEMA 时,它错误地说它已授予架构对某些系统表的访问权限。我最终向 sys.schemas ON perm.major_id = schem.schema_id 添加了一个 LEFT JOIN 并更改了两个选择语句: [ObjectType] = CASE WHEN perm.class_desc 'SCHEMA' THEN obj.type_desc ELSE 'SCHEMA' END, [ ObjectName] = CASE WHEN perm.class_desc 'SCHEMA' THEN OBJECT_NAME(perm.major_id) ELSE schem.name END,可能不是最好的方法,但我找到的唯一快速方法。
  • 我想补充一下我的服务器处理这个问题的时间。我有一个非常不错的服务器,这个脚本需要 5:45 才能运行。大约 60 个数据库和大约 100 个用户帐户需要 5 小时 45 分钟。
  • 查看编辑历史记录,Sean Rose 的回答似乎是最全面的,包含了在此页面上提出的其他建议
  • 在 Azure SQL DB 中 login_token 更改为 user_token
【解决方案2】:

这是 Jeremy 2011 年 8 月查询的完整版本,其中包含 Brad(2011 年 10 月)和 iw.kuchin(2012 年 5 月)建议的更改:

  1. Brad: 更正 [ObjectType][ObjectName] 的架构。
  2. iw.kuchin: 对于[ObjectType],最好只对OBJECT_OR_COLUMN 权限类使用obj.type_desc。对于所有其他情况,请使用 perm.[class_desc]
  3. iw.kuchin: 处理IMPERSONATE 权限。
  4. iw.kuchin:sys.login_token 替换为sys.server_principals,因为它还会显示SQL 登录,而不仅仅是Windows 登录。
  5. iw.kuchin:包括 Windows 组。
  6. iw.kuchin: 排除用户 sys 和 INFORMATION_SCHEMA。

希望这可以挽救其他人一两个小时的生命。 :)

/*
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:
UserType        : Value will be either 'SQL User', 'Windows User', or 'Windows Group'.
                  This reflects the type of user/group defined for the SQL Server 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.
LoginName       : SQL or Windows/Active Directory user account.  This could also be an Active Directory group.
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.
Schema          : Name of the schema the object is in.
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.
*/

    --1) List all access provisioned to a SQL user or Windows user/group directly
    SELECT
        [UserType] = CASE princ.[type]
                         WHEN 'S' THEN 'SQL User'
                         WHEN 'U' THEN 'Windows User'
                         WHEN 'G' THEN 'Windows Group'
                     END,
        [DatabaseUserName] = princ.[name],
        [LoginName]        = ulogin.[name],
        [Role]             = NULL,
        [PermissionType]   = perm.[permission_name],
        [PermissionState]  = perm.[state_desc],
        [ObjectType] = CASE perm.[class]
                           WHEN 1 THEN obj.[type_desc]        -- Schema-contained objects
                           ELSE perm.[class_desc]             -- Higher-level objects
                       END,
        [Schema] = objschem.[name],
        [ObjectName] = CASE perm.[class]
                           WHEN 3 THEN permschem.[name]       -- Schemas
                           WHEN 4 THEN imp.[name]             -- Impersonations
                           ELSE OBJECT_NAME(perm.[major_id])  -- General objects
                       END,
        [ColumnName] = col.[name]
    FROM
        --Database user
        sys.database_principals            AS princ
        --Login accounts
        LEFT JOIN sys.server_principals    AS ulogin    ON ulogin.[sid] = princ.[sid]
        --Permissions
        LEFT JOIN sys.database_permissions AS perm      ON perm.[grantee_principal_id] = princ.[principal_id]
        LEFT JOIN sys.schemas              AS permschem ON permschem.[schema_id] = perm.[major_id]
        LEFT JOIN sys.objects              AS obj       ON obj.[object_id] = perm.[major_id]
        LEFT JOIN sys.schemas              AS objschem  ON objschem.[schema_id] = obj.[schema_id]
        --Table columns
        LEFT JOIN sys.columns              AS col       ON col.[object_id] = perm.[major_id]
                                                           AND col.[column_id] = perm.[minor_id]
        --Impersonations
        LEFT JOIN sys.database_principals  AS imp       ON imp.[principal_id] = perm.[major_id]
    WHERE
        princ.[type] IN ('S','U','G')
        -- No need for these system accounts
        AND princ.[name] NOT IN ('sys', 'INFORMATION_SCHEMA')

UNION

    --2) List all access provisioned to a SQL user or Windows user/group through a database or application role
    SELECT
        [UserType] = CASE membprinc.[type]
                         WHEN 'S' THEN 'SQL User'
                         WHEN 'U' THEN 'Windows User'
                         WHEN 'G' THEN 'Windows Group'
                     END,
        [DatabaseUserName] = membprinc.[name],
        [LoginName]        = ulogin.[name],
        [Role]             = roleprinc.[name],
        [PermissionType]   = perm.[permission_name],
        [PermissionState]  = perm.[state_desc],
        [ObjectType] = CASE perm.[class]
                           WHEN 1 THEN obj.[type_desc]        -- Schema-contained objects
                           ELSE perm.[class_desc]             -- Higher-level objects
                       END,
        [Schema] = objschem.[name],
        [ObjectName] = CASE perm.[class]
                           WHEN 3 THEN permschem.[name]       -- Schemas
                           WHEN 4 THEN imp.[name]             -- Impersonations
                           ELSE OBJECT_NAME(perm.[major_id])  -- General objects
                       END,
        [ColumnName] = col.[name]
    FROM
        --Role/member associations
        sys.database_role_members          AS members
        --Roles
        JOIN      sys.database_principals  AS roleprinc ON roleprinc.[principal_id] = members.[role_principal_id]
        --Role members (database users)
        JOIN      sys.database_principals  AS membprinc ON membprinc.[principal_id] = members.[member_principal_id]
        --Login accounts
        LEFT JOIN sys.server_principals    AS ulogin    ON ulogin.[sid] = membprinc.[sid]
        --Permissions
        LEFT JOIN sys.database_permissions AS perm      ON perm.[grantee_principal_id] = roleprinc.[principal_id]
        LEFT JOIN sys.schemas              AS permschem ON permschem.[schema_id] = perm.[major_id]
        LEFT JOIN sys.objects              AS obj       ON obj.[object_id] = perm.[major_id]
        LEFT JOIN sys.schemas              AS objschem  ON objschem.[schema_id] = obj.[schema_id]
        --Table columns
        LEFT JOIN sys.columns              AS col       ON col.[object_id] = perm.[major_id]
                                                           AND col.[column_id] = perm.[minor_id]
        --Impersonations
        LEFT JOIN sys.database_principals  AS imp       ON imp.[principal_id] = perm.[major_id]
    WHERE
        membprinc.[type] IN ('S','U','G')
        -- No need for these system accounts
        AND membprinc.[name] NOT IN ('sys', 'INFORMATION_SCHEMA')

UNION

    --3) List all access provisioned to the public role, which everyone gets by default
    SELECT
        [UserType]         = '{All Users}',
        [DatabaseUserName] = '{All Users}',
        [LoginName]        = '{All Users}',
        [Role]             = roleprinc.[name],
        [PermissionType]   = perm.[permission_name],
        [PermissionState]  = perm.[state_desc],
        [ObjectType] = CASE perm.[class]
                           WHEN 1 THEN obj.[type_desc]        -- Schema-contained objects
                           ELSE perm.[class_desc]             -- Higher-level objects
                       END,
        [Schema] = objschem.[name],
        [ObjectName] = CASE perm.[class]
                           WHEN 3 THEN permschem.[name]       -- Schemas
                           WHEN 4 THEN imp.[name]             -- Impersonations
                           ELSE OBJECT_NAME(perm.[major_id])  -- General objects
                       END,
        [ColumnName] = col.[name]
    FROM
        --Roles
        sys.database_principals            AS roleprinc
        --Role permissions
        LEFT JOIN sys.database_permissions AS perm      ON perm.[grantee_principal_id] = roleprinc.[principal_id]
        LEFT JOIN sys.schemas              AS permschem ON permschem.[schema_id] = perm.[major_id]
        --All objects
        JOIN      sys.objects              AS obj       ON obj.[object_id] = perm.[major_id]
        LEFT JOIN sys.schemas              AS objschem  ON objschem.[schema_id] = obj.[schema_id]
        --Table columns
        LEFT JOIN sys.columns              AS col       ON col.[object_id] = perm.[major_id]
                                                           AND col.[column_id] = perm.[minor_id]
        --Impersonations
        LEFT JOIN sys.database_principals  AS imp       ON imp.[principal_id] = perm.[major_id]
    WHERE
        roleprinc.[type] = 'R'
        AND roleprinc.[name] = 'public'
        AND obj.[is_ms_shipped] = 0

ORDER BY
    [UserType],
    [DatabaseUserName],
    [LoginName],
    [Role],
    [Schema],
    [ObjectName],
    [ColumnName],
    [PermissionType],
    [PermissionState],
    [ObjectType]

【讨论】:

  • 如果它可以为服务器上的所有数据库做到这一点会很好
  • 它似乎不包括其他未连接的用户以及系统管理员。
  • 正如@JakubP 上面评论的那样,如果您使用的是Azure SQL,则sys.login_tokensys.server_principals 都不支持,需要替换为sys.user_token
  • 谢谢。如果您使用 Azure SQL 和 Azure AD 安全组,则在查询 1 和 2 中,您可以将 WHERE membprinc/princ.[type] in ... 条件更改为 WHERE membprinc/princ.[type] IN ('S','U','G', 'E', 'X'),并将以下条件添加到顶部的 CASEWHEN 'E' THEN 'External user AAD'WHEN 'X' THEN 'External group AAD'。这样,Azure AD 用户和组也包括在内。来源:docs.microsoft.com/en-us/sql/relational-databases/…
【解决方案3】:

从 SQL Server 2005 开始,您可以为此使用系统视图。例如,此查询列出了数据库中的所有用户及其权限:

select  princ.name
,       princ.type_desc
,       perm.permission_name
,       perm.state_desc
,       perm.class_desc
,       object_name(perm.major_id)
from    sys.database_principals princ
left join
        sys.database_permissions perm
on      perm.grantee_principal_id = princ.principal_id

请注意,用户也可以通过角色拥有权限。例如,db_data_reader 角色授予大多数对象的select 权限。

【讨论】:

  • 这运行得更快,但您必须进行第二次查找(针对角色)以查看用户可以通过其角色看到哪些对象。
  • 对于 Azure SQL,我发现这个解决方案比公认的答案更可靠。重要的是,这会识别数据库 (select * from sys.database_principals where type_desc = 'EXTERNAL_GROUP') 中的外部(Azure Active Directory)主体,而接受的答案则不会,即使在修复 sys.user_token 之后也是如此。
  • 允许其他class_desc:SELECT PrincipalName = p.[name], p.[type_desc], dp.[permission_name], dp.[state_desc], CASE dp.class_desc WHEN 'DATABASE' THEN DB_NAME(dp.major_id) WHEN 'SCHEMA' THEN SCHEMA_NAME(dp.major_id) WHEN 'OBJECT_OR_COLUMN' THEN CONCAT_WS('.', OBJECT_SCHEMA_NAME(dp.major_id), OBJECT_NAME(dp.major_id), c.[name]) END FROM sys.database_principals AS p LEFT OUTER JOIN sys.database_permissions AS dp ON p.principal_id = dp.grantee_principal_id LEFT OUTER JOIN sys.columns AS c ON dp.major_id = c.[object_id] AND dp.minor_id = c.column_id
【解决方案4】:

无法对已接受的答案发表评论,因此我将在此处添加一些 cmets:

  • 我就架构问题向 Brad 求助。来自 MS 参考 sys.objects 表仅包含模式范围的对象。因此,要获取有关“更高级别”对象的信息(即我们案例中的模式),您需要使用 sys.schemas 表。
  • 对于[ObjectType],最好仅将obj.type_desc 用于OBJECT_OR_COLUMN 权限类。对于所有其他情况,请使用 perm.[class_desc]
  • 此查询处理得不好的另一种权限类型是IMPERSONATE。要获取有关模仿的信息,应在LEFT JOINsys.database_principalsperm.major_id = imp.principal_id
  • 根据我的经验,最好将 sys.login_token 替换为 sys.server_principals,因为它还会显示 SQL 登录,而不仅仅是 Windows
  • 应将 'G' 添加到允许的主体类型以允许 Windows 组
  • 此外,可以从结果表中排除用户sysINFORMATION_SCHEMA,因为这些用户仅用于服务

我将发布包含所有建议修复的第一段脚本,其他部分也应更改:

SELECT  
    [UserName] = ulogin.[name],
    [UserType] = CASE princ.[type]
                    WHEN 'S' THEN 'SQL User'
                    WHEN 'U' THEN 'Windows User'
                    WHEN 'G' THEN 'Windows Group'
                 END,  
    [DatabaseUserName] = princ.[name],       
    [Role] = null,      
    [PermissionType] = perm.[permission_name],       
    [PermissionState] = perm.[state_desc],       
    [ObjectType] = CASE perm.[class] 
                        WHEN 1 THEN obj.type_desc               -- Schema-contained objects
                        ELSE perm.[class_desc]                  -- Higher-level objects
                   END,       
    [ObjectName] = CASE perm.[class] 
                        WHEN 1 THEN OBJECT_NAME(perm.major_id)  -- General objects
                        WHEN 3 THEN schem.[name]                -- Schemas
                        WHEN 4 THEN imp.[name]                  -- Impersonations
                   END,
    [ColumnName] = col.[name]
FROM    
    --database user
    sys.database_principals princ  
LEFT JOIN
    --Login accounts
    sys.server_principals ulogin on princ.[sid] = ulogin.[sid]
LEFT JOIN        
    --Permissions
    sys.database_permissions perm ON perm.[grantee_principal_id] = princ.[principal_id]
LEFT JOIN
    --Table columns
    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]
LEFT JOIN
    sys.schemas schem ON schem.[schema_id] = perm.[major_id]
LEFT JOIN
    sys.database_principals imp ON imp.[principal_id] = perm.[major_id]
WHERE 
    princ.[type] IN ('S','U','G') AND
    -- No need for these system accounts
    princ.[name] NOT IN ('sys', 'INFORMATION_SCHEMA')

【讨论】:

  • 很好的反馈,我计划将所有反馈合并到原始答案中。
  • 实际上,还有更多建议 :) 除了对象名称之外,还应该是模式名称,以便轻松识别当前对象。还有更多的方法让某人通过服务器角色访问对象:即sysadmin + securityadmin 映射为dbo 用于服务器上的每个数据库 + 可以授予用户的服务器权限CONTROL SERVER。此权限提供与 sysadmin 几乎相同的权限。
  • 运行此查询后,我注意到它没有在其中一个 id 上找到 db_datareader。虽然速度很慢,但第一个答案似乎更完整。
  • @Tequila 这是对第一条原始查询的修改(直到第一个UNION);另外两个部分应相应更新以获得更完整的答案
【解决方案5】:

我看到的其他答案错过了数据库中可能存在的一些权限。下面代码中的第一个查询将获得非系统对象的everything 的数据库级权限。它还会生成适当的 GRANT 语句。第二个查询获取所有角色成员资格。

这必须为每个数据库运行,但时间太长而无法与 sp_MSforeachdb 一起使用。如果你想这样做,你必须将它作为系统存储过程添加到主数据库中。

要涵盖所有可能性,您还必须有一个检查服务器级别权限的脚本。

SELECT DB_NAME() AS database_name
    , class
    , class_desc
    , major_id
    , minor_id
    , grantee_principal_id
    , grantor_principal_id
    , databasepermissions.type
    , permission_name
    , STATE
    , state_desc
    , granteedatabaseprincipal.name AS grantee_name
    , granteedatabaseprincipal.type_desc AS grantee_type_desc
    , granteeserverprincipal.name AS grantee_principal_name
    , granteeserverprincipal.type_desc AS grantee_principal_type_desc
    , grantor.name AS grantor_name
    , granted_on_name
    , permissionstatement + N' TO ' + QUOTENAME(granteedatabaseprincipal.name) + CASE 
        WHEN STATE = N'W'
            THEN N' WITH GRANT OPTION'
        ELSE N''
        END AS permissionstatement
FROM (
    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(CONVERT(NVARCHAR(MAX), DB_NAME())) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS AS permissionstatement
    FROM sys.database_permissions
    WHERE (sys.database_permissions.class = 0)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.schemas.name) + N'.' + QUOTENAME(sys.objects.name) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON ' + QUOTENAME(sys.schemas.name) + N'.' + QUOTENAME(sys.objects.name) + COALESCE(N' (' + QUOTENAME(sys.columns.name) + N')', N'') AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.objects
        ON sys.objects.object_id = sys.database_permissions.major_id
    INNER JOIN sys.schemas
        ON sys.schemas.schema_id = sys.objects.schema_id
    LEFT OUTER JOIN sys.columns
        ON sys.columns.object_id = sys.database_permissions.major_id
            AND sys.columns.column_id = sys.database_permissions.minor_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 1)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.schemas.name) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON SCHEMA::' + QUOTENAME(sys.schemas.name) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.schemas
        ON sys.schemas.schema_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 3)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(targetPrincipal.name) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON ' + targetPrincipal.type_desc + N'::' + QUOTENAME(targetPrincipal.name) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.database_principals AS targetPrincipal
        ON targetPrincipal.principal_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 4)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.assemblies.name) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON ASSEMBLY::' + QUOTENAME(sys.assemblies.name) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.assemblies
        ON sys.assemblies.assembly_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 5)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.types.name) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON TYPE::' + QUOTENAME(sys.types.name) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.types
        ON sys.types.user_type_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 6)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.types.name) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON TYPE::' + QUOTENAME(sys.types.name) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.types
        ON sys.types.user_type_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 6)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.xml_schema_collections.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON XML SCHEMA COLLECTION::' + QUOTENAME(sys.xml_schema_collections.name) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.xml_schema_collections
        ON sys.xml_schema_collections.xml_collection_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 10)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.service_message_types.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON MESSAGE TYPE::' + QUOTENAME(sys.service_message_types.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.service_message_types
        ON sys.service_message_types.message_type_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 15)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.service_contracts.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON CONTRACT::' + QUOTENAME(sys.service_contracts.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.service_contracts
        ON sys.service_contracts.service_contract_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 16)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.services.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON SERVICE::' + QUOTENAME(sys.services.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.services
        ON sys.services.service_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 17)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.remote_service_bindings.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON REMOTE SERVICE BINDING::' + QUOTENAME(sys.remote_service_bindings.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.remote_service_bindings
        ON sys.remote_service_bindings.remote_service_binding_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 18)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.routes.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON ROUTE::' + QUOTENAME(sys.routes.name COLLATE SQL_Latin1_General_CP1_CI_AS) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.routes
        ON sys.routes.route_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 19)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.symmetric_keys.name) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON ASYMMETRIC KEY::' + QUOTENAME(sys.symmetric_keys.name) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.symmetric_keys
        ON sys.symmetric_keys.symmetric_key_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 24)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.certificates.name) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON CERTIFICATE::' + QUOTENAME(sys.certificates.name) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.certificates
        ON sys.certificates.certificate_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 25)

    UNION ALL

    SELECT sys.database_permissions.class
        , sys.database_permissions.class_desc
        , sys.database_permissions.major_id
        , sys.database_permissions.minor_id
        , sys.database_permissions.grantee_principal_id
        , sys.database_permissions.grantor_principal_id
        , sys.database_permissions.type
        , sys.database_permissions.permission_name
        , sys.database_permissions.state
        , sys.database_permissions.state_desc
        , QUOTENAME(sys.asymmetric_keys.name) AS granted_on_name
        , CASE 
            WHEN sys.database_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.database_permissions.state_desc
            END + N' ' + sys.database_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' ON ASYMMETRIC KEY::' + QUOTENAME(sys.asymmetric_keys.name) AS permissionstatement
    FROM sys.database_permissions
    INNER JOIN sys.asymmetric_keys
        ON sys.asymmetric_keys.asymmetric_key_id = sys.database_permissions.major_id
    WHERE (sys.database_permissions.major_id >= 0)
        AND (sys.database_permissions.class = 26)
    ) AS databasepermissions
INNER JOIN sys.database_principals AS granteedatabaseprincipal
    ON granteedatabaseprincipal.principal_id = grantee_principal_id
LEFT OUTER JOIN sys.server_principals AS granteeserverprincipal
    ON granteeserverprincipal.sid = granteedatabaseprincipal.sid
INNER JOIN sys.database_principals AS grantor
    ON grantor.principal_id = grantor_principal_id
ORDER BY grantee_name, granted_on_name

SELECT roles.name AS role_name
    , roles.principal_id
    , roles.type AS role_type
    , roles.type_desc AS role_type_desc
    , roles.is_fixed_role AS role_is_fixed_role
    , memberdatabaseprincipal.name AS member_name
    , memberdatabaseprincipal.principal_id AS member_principal_id
    , memberdatabaseprincipal.type AS member_type
    , memberdatabaseprincipal.type_desc AS member_type_desc
    , memberdatabaseprincipal.is_fixed_role AS member_is_fixed_role
    , memberserverprincipal.name AS member_principal_name
    , memberserverprincipal.type_desc member_principal_type_desc
    , N'ALTER ROLE ' + QUOTENAME(roles.name) + N' ADD MEMBER ' + QUOTENAME(memberdatabaseprincipal.name) AS AddRoleMembersStatement
FROM sys.database_principals AS roles
INNER JOIN sys.database_role_members
    ON sys.database_role_members.role_principal_id = roles.principal_id
INNER JOIN sys.database_principals AS memberdatabaseprincipal
    ON memberdatabaseprincipal.principal_id = sys.database_role_members.member_principal_id
LEFT OUTER JOIN sys.server_principals AS memberserverprincipal
    ON memberserverprincipal.sid = memberdatabaseprincipal.sid
ORDER BY role_name
    , member_name

更新:以下查询将检索服务器级别的权限和成员资格。

SELECT sys.server_permissions.class
        , sys.server_permissions.class_desc
        , sys.server_permissions.major_id
        , sys.server_permissions.minor_id
        , sys.server_permissions.grantee_principal_id
        , sys.server_permissions.grantor_principal_id
        , sys.server_permissions.type
        , sys.server_permissions.permission_name
        , sys.server_permissions.state
        , sys.server_permissions.state_desc
        , granteeserverprincipal.name AS grantee_principal_name
        , granteeserverprincipal.type_desc AS grantee_principal_type_desc
        , grantorserverprinicipal.name AS grantor_name
        , CASE 
            WHEN sys.server_permissions.state = N'W'
                THEN N'GRANT'
            ELSE sys.server_permissions.state_desc
            END + N' ' + sys.server_permissions.permission_name COLLATE SQL_Latin1_General_CP1_CI_AS + N' TO ' + QUOTENAME(granteeserverprincipal.name) AS permissionstatement
FROM sys.server_principals AS granteeserverprincipal
INNER JOIN sys.server_permissions
    ON sys.server_permissions.grantee_principal_id = granteeserverprincipal.principal_id
INNER JOIN sys.server_principals AS grantorserverprinicipal
    ON grantorserverprinicipal.principal_id = sys.server_permissions.grantor_principal_id
ORDER BY granteeserverprincipal.name
    , sys.server_permissions.permission_name

SELECT roles.name AS server_role_name
    , roles.principal_id
    , roles.type AS role_type
    , roles.type_desc AS role_type_desc
    , roles.is_fixed_role AS role_is_fixed_role
    , memberserverprincipal.name AS member_principal_name
    , memberserverprincipal.principal_id AS member_principal_id
    , memberserverprincipal.type AS member_principal_type
    , memberserverprincipal.type_desc AS member_principal_type_desc
    , memberserverprincipal.is_fixed_role AS member_is_fixed_role
    , N'ALTER SERVER ROLE ' + QUOTENAME(roles.name) + N' ADD MEMBER ' + QUOTENAME(memberserverprincipal.name) AS AddRoleMembersStatement
FROM sys.server_principals AS roles
INNER JOIN sys.server_role_members
    ON sys.server_role_members.role_principal_id = roles.principal_id
INNER JOIN sys.server_principals AS memberserverprincipal
    ON memberserverprincipal.principal_id = sys.server_role_members.member_principal_id
WHERE roles.type = N'R'
ORDER BY server_role_name
    , member_principal_name

【讨论】:

    【解决方案6】:

    很棒的脚本 Jeremy 和贡献者!谢谢!

    我有大量用户,所以为所有用户运行这个程序简直就是一场噩梦。我无法添加 cmets,因此我发布了包含更改的整个脚本。我添加了一个变量 + where 子句,这样我就可以搜索用户名中最多匹配 5 个字符的任何内容(或留空时的所有用户)。没什么特别的,但我认为它在某些用例中会有所帮助。

    DECLARE @p_userName NVARCHAR(5) = 'UName' -- Specify up to five characters here (or none for all users)
    
    /*
    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. 
    
    */
    
    DECLARE @userName NVARCHAR(4) = @p_UserName + '%'
    --List all access provisioned to a sql user or windows user/group directly 
    
    SELECT  
    [UserName] = CASE princ.[type] 
                    WHEN 'S' THEN princ.[name]
                    WHEN 'U' THEN ulogin.[name] COLLATE Latin1_General_CI_AI
                 END,
    [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,--perm.[class_desc],       
    [ObjectName] = OBJECT_NAME(perm.major_id),
    [ColumnName] = col.[name]
    FROM    
    --database user
    sys.database_principals princ  
    LEFT JOIN
    --Login accounts
    sys.login_token ulogin on princ.[sid] = ulogin.[sid]
    LEFT JOIN        
    --Permissions
    sys.database_permissions perm ON perm.[grantee_principal_id] = princ.[principal_id]
    LEFT JOIN
    --Table columns
    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')  
    AND princ.[name] LIKE @userName  -- Added this line --CSLAGLE
    UNION
    --List all access provisioned to a sql user or windows user/group through a database or application role
    SELECT  
    [UserName] = CASE memberprinc.[type] 
                    WHEN 'S' THEN memberprinc.[name]
                    WHEN 'U' THEN ulogin.[name] COLLATE Latin1_General_CI_AI
                 END,
    [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,--perm.[class_desc],   
    [ObjectName] = OBJECT_NAME(perm.major_id),
    [ColumnName] = col.[name]
    FROM    
    --Role/member associations
    sys.database_role_members members
    JOIN
    --Roles
    sys.database_principals roleprinc ON roleprinc.[principal_id] = members.[role_principal_id]
    JOIN
    --Role members (database users)
    sys.database_principals memberprinc ON memberprinc.[principal_id] = members.[member_principal_id]
    LEFT JOIN
    --Login accounts
    sys.login_token ulogin on memberprinc.[sid] = ulogin.[sid]
    LEFT JOIN        
    --Permissions
    sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id]
    LEFT JOIN
    --Table columns
    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 memberprinc.[name] LIKE @userName -- Added this line --CSLAGLE
    UNION
    --List all access provisioned to the public role, which everyone gets by default
    SELECT  
    [UserName] = '{All Users}', 
    [UserType] = '{All Users}', 
    [DatabaseUserName] = '{All Users}',       
    [Role] = roleprinc.[name],      
    [PermissionType] = perm.[permission_name],       
    [PermissionState] = perm.[state_desc],       
    [ObjectType] = obj.type_desc,--perm.[class_desc],  
    [ObjectName] = OBJECT_NAME(perm.major_id),
    [ColumnName] = col.[name]
    FROM    
    --Roles
    sys.database_principals roleprinc
    LEFT JOIN        
    --Role permissions
    sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id]
    LEFT JOIN
    --Table columns
    sys.columns col on col.[object_id] = perm.major_id 
                    AND col.[column_id] = perm.[minor_id]                   
    JOIN 
    --All objects   
    sys.objects obj ON obj.[object_id] = perm.[major_id]
    WHERE
    --Only roles
    roleprinc.[type] = 'R' AND
    --Only public role
    roleprinc.[name] = 'public' AND
    --Only objects of ours, not the MS objects
    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]  
    

    【讨论】:

    • 您的分配逻辑有错误。 DECLARE @ userName NVARCHAR(4) = @ p_UserName + '%' - 这是将 NVARCHAR(5) + VARCHAR(1) 分配给 NVARCHAR(4)。所以你应该 DECLARE @userName NVARCHAR(6)
    【解决方案7】:

    这是我的版本,改编自其他人。我刚才花了 30 分钟试图记住我是如何想到这个的,@Jeremy 的回答似乎是核心灵感。我不想更新 Jeremy 的答案,以防万一我引入错误,所以我在这里发布我的版本。

    我建议将完整的脚本与来自 Kenneth Fisher's T-SQL Tuesday: What Permissions Does a Specific User Have? 的一些灵感配对:这样您就可以自下而上地回答合规/审计问题,而不是自上而下。

    EXECUTE AS LOGIN = '<loginname>'
    
    SELECT token.name AS GroupNames
    FROM sys.login_token token
    JOIN sys.server_principals grp
        ON token.sid = grp.sid
    WHERE token.[type] = 'WINDOWS GROUP'
      AND grp.[type] = 'G'
    
    REVERT
    

    要了解其中的内容,请考虑 Contoso\DB_AdventureWorks_Accounting Windows AD 组和成员 Contoso\John.Doe。 John.Doe 通过 server_principal Contoso\DB_AdventureWorks_Logins Windows AD 组向 AdventureWorks 进行身份验证。如果有人问你,“John.Doe 有什么权限?”,你不能只用下面的脚本回答这个问题。然后,您需要遍历以下脚本返回的每一行并将其加入上述脚本。 (您可能还需要通过在 Active Directory 提供程序中查找 SID 来规范陈旧的 name 值。)

    这是脚本,没有包含这种反向查找逻辑。

    /*
    
    
    --Script source found at :  http://stackoverflow.com/a/7059579/1387418
    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 account.  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.
    PrinciaplUserName: if UserName is not blank, then UserName else DatabaseUserName
    PrincipalType    : Possible values are 'SQL User', 'Windows User', 'Database Role', 'Windows Group'
    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.                 
    */
    
    DECLARE @HideDatabaseDiagrams BIT = 1;
    
    --List all access provisioned to a sql user or windows user/group directly 
    SELECT  
        [UserName] = CASE dbprinc.[type] 
                        WHEN 'S' THEN dbprinc.[name] -- SQL User
                        WHEN 'U' THEN sprinc.[name] -- Windows User
                        WHEN 'R' THEN NULL -- Database Role
                        WHEN 'G' THEN NULL -- Windows Group
                        ELSE NULL
                     END,
        [UserType] = CASE dbprinc.[type]
                        WHEN 'S' THEN 'SQL User'
                        WHEN 'U' THEN 'Windows User'
                        WHEN 'R' THEN NULL -- Database Role
                        WHEN 'G' THEN NULL -- Windows Group
                        ELSE dbprinc.[type]
                     END,
        [PrincipalUserName] = COALESCE(
                        CASE dbprinc.[type]
                            WHEN 'S' THEN dbprinc.[name] -- SQL User
                            WHEN 'U' THEN sprinc.[name] -- Windows User
                            WHEN 'R' THEN NULL -- Database Role
                            WHEN 'G' THEN NULL -- Windows Group
                            ELSE NULL
                         END,
                         dbprinc.[name]
                     ),
        [PrincipalType] = CASE dbprinc.[type]
                        WHEN 'S' THEN 'SQL User'
                        WHEN 'U' THEN 'Windows User'
                        WHEN 'R' THEN 'Database Role'
                        WHEN 'G' THEN 'Windows Group'
                     END,
        [DatabaseUserName] = dbprinc.[name],
        [Role] = null,
        [PermissionType] = perm.[permission_name],
        [PermissionState] = perm.[state_desc],
        [ObjectType] = obj.[type_desc],--perm.[class_desc],
        [ObjectSchema] = OBJECT_SCHEMA_NAME(perm.major_id),
        [ObjectName] = OBJECT_NAME(perm.major_id),
        [ColumnName] = col.[name]
    FROM    
        --database user
        sys.database_principals dbprinc  
    LEFT JOIN
        --Login accounts
        sys.server_principals sprinc on dbprinc.[sid] = sprinc.[sid]
    LEFT JOIN        
        --Permissions
        sys.database_permissions perm ON perm.[grantee_principal_id] = dbprinc.[principal_id]
    LEFT JOIN
        --Table columns
        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 
        dbprinc.[type] in ('S','U')
        AND CASE
            WHEN @HideDatabaseDiagrams = 1 AND
            dbprinc.[name] = 'guest'
            AND (
                (
                    obj.type_desc = 'SQL_SCALAR_FUNCTION'
                    AND OBJECT_NAME(perm.major_id) = 'fn_diagramobjects'
                )
                OR (
                    obj.type_desc = 'SQL_STORED_PROCEDURE'
                    AND OBJECT_NAME(perm.major_id) IN
                    (
                        N'sp_alterdiagram',
                        N'sp_creatediagram',
                        N'sp_dropdiagram',
                        N'sp_helpdiagramdefinition',
                        N'sp_helpdiagrams',
                        N'sp_renamediagram'
                    )
                )
            )
            THEN 0
            ELSE 1
        END = 1
    UNION
    --List all access provisioned to a sql user or windows user/group through a database or application role
    SELECT  
        [UserName] = CASE memberprinc.[type]
                        WHEN 'S' THEN memberprinc.[name]
                        WHEN 'U' THEN sprinc.[name]
                        WHEN 'R' THEN NULL -- Database Role
                        WHEN 'G' THEN NULL -- Windows Group
                        ELSE NULL
                     END,
        [UserType] = CASE memberprinc.[type]
                        WHEN 'S' THEN 'SQL User'
                        WHEN 'U' THEN 'Windows User'
                        WHEN 'R' THEN NULL -- Database Role
                        WHEN 'G' THEN NULL -- Windows Group
                     END, 
        [PrincipalUserName] = COALESCE(
                        CASE memberprinc.[type]
                            WHEN 'S' THEN memberprinc.[name]
                            WHEN 'U' THEN sprinc.[name]
                            WHEN 'R' THEN NULL -- Database Role
                            WHEN 'G' THEN NULL -- Windows Group
                            ELSE NULL
                         END,
                         memberprinc.[name]
                     ),
        [PrincipalType] = CASE memberprinc.[type]
                        WHEN 'S' THEN 'SQL User'
                        WHEN 'U' THEN 'Windows User'
                        WHEN 'R' THEN 'Database Role'
                        WHEN 'G' THEN 'Windows Group'
                     END, 
        [DatabaseUserName] = memberprinc.[name],
        [Role] = roleprinc.[name],
        [PermissionType] = perm.[permission_name],
        [PermissionState] = perm.[state_desc],
        [ObjectType] = obj.type_desc,--perm.[class_desc],
        [ObjectSchema] = OBJECT_SCHEMA_NAME(perm.major_id),
        [ObjectName] = OBJECT_NAME(perm.major_id),
        [ColumnName] = col.[name]
    FROM    
        --Role/member associations
        sys.database_role_members members
    JOIN
        --Roles
        sys.database_principals roleprinc ON roleprinc.[principal_id] = members.[role_principal_id]
    JOIN
        --Role members (database users)
        sys.database_principals memberprinc ON memberprinc.[principal_id] = members.[member_principal_id]
    LEFT JOIN
        --Login accounts
        sys.server_principals sprinc on memberprinc.[sid] = sprinc.[sid]
    LEFT JOIN
        --Permissions
        sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id]
    LEFT JOIN
        --Table columns
        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    
        CASE
            WHEN @HideDatabaseDiagrams = 1 AND
            memberprinc.[name] = 'guest'
            AND (
                (
                    obj.type_desc = 'SQL_SCALAR_FUNCTION'
                    AND OBJECT_NAME(perm.major_id) = 'fn_diagramobjects'
                )
                OR (
                    obj.type_desc = 'SQL_STORED_PROCEDURE'
                    AND OBJECT_NAME(perm.major_id) IN
                    (
                        N'sp_alterdiagram',
                        N'sp_creatediagram',
                        N'sp_dropdiagram',
                        N'sp_helpdiagramdefinition',
                        N'sp_helpdiagrams',
                        N'sp_renamediagram'
                    )
                )
            )
            THEN 0
            ELSE 1
        END = 1
    UNION
    --List all access provisioned to the public role, which everyone gets by default
    SELECT  
        [UserName] = '{All Users}',
        [UserType] = '{All Users}',
        [PrincipalUserName] = '{All Users}',
        [PrincipalType] = '{All Users}',
        [DatabaseUserName] = '{All Users}',
        [Role] = roleprinc.[name],
        [PermissionType] = perm.[permission_name],
        [PermissionState] = perm.[state_desc],
        [ObjectType] = obj.type_desc,--perm.[class_desc],
        [ObjectSchema] = OBJECT_SCHEMA_NAME(perm.major_id),
        [ObjectName] = OBJECT_NAME(perm.major_id),
        [ColumnName] = col.[name]
    FROM    
        --Roles
        sys.database_principals roleprinc
    LEFT JOIN        
        --Role permissions
        sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id]
    LEFT JOIN
        --Table columns
        sys.columns col on col.[object_id] = perm.major_id
                        AND col.[column_id] = perm.[minor_id]
    JOIN 
        --All objects
        sys.objects obj ON obj.[object_id] = perm.[major_id]
    WHERE
        --Only roles
        roleprinc.[type] = 'R' AND
        --Only public role
        roleprinc.[name] = 'public' AND
        --Only objects of ours, not the MS objects
        obj.is_ms_shipped = 0
        AND CASE
            WHEN @HideDatabaseDiagrams = 1 AND
            roleprinc.[name] = 'public'
            AND (
                (
                    obj.type_desc = 'SQL_SCALAR_FUNCTION'
                    AND OBJECT_NAME(perm.major_id) = 'fn_diagramobjects'
                )
                OR (
                    obj.type_desc = 'SQL_STORED_PROCEDURE'
                    AND OBJECT_NAME(perm.major_id) IN
                    (
                        N'sp_alterdiagram',
                        N'sp_creatediagram',
                        N'sp_dropdiagram',
                        N'sp_helpdiagramdefinition',
                        N'sp_helpdiagrams',
                        N'sp_renamediagram'
                    )
                )
            )
            THEN 0
            ELSE 1
        END = 1
    ORDER BY
        dbprinc.[Name],
        OBJECT_NAME(perm.major_id),
        col.[name],
        perm.[permission_name],
        perm.[state_desc],
        obj.type_desc--perm.[class_desc]
    

    【讨论】:

      【解决方案8】:

      上面的 GetPermissions 存储过程很好,但是它使用 Sp_msforeachdb,这意味着如果您的 SQL 实例有任何数据库名称包含空格或破折号以及其他非最佳实践字符,它将中断。我创建了一个避免使用 Sp_msforeachdb 的版本,并且还包括两列,指示 1 - 如果登录是系统管理员登录 (IsSysAdminLogin) 和 2 - 如果登录是孤立用户 (IsEmptyRow)。

      USE [master] ;
      GO
      IF EXISTS
      (
          SELECT * FROM sys.objects
          WHERE object_id = OBJECT_ID(N'dbo.uspGetPermissionsOfAllLogins_DBsOnColumns')
          AND [type] in (N'P',N'PC')
      )
      BEGIN
          DROP PROCEDURE dbo.uspGetPermissionsOfAllLogins_DBsOnColumns ;
      END
      GO
      CREATE PROCEDURE dbo.uspGetPermissionsOfAllLogins_DBsOnColumns
      AS
      SET NOCOUNT ON
      ;
      BEGIN TRY
          IF EXISTS
          (
              SELECT * FROM tempdb.dbo.sysobjects
              WHERE id = object_id(N'[tempdb].dbo.[#permission]')
          )
          DROP TABLE #permission
          ;
          IF EXISTS
          (
              SELECT * FROM tempdb.dbo.sysobjects
              WHERE id = object_id(N'[tempdb].dbo.[#userroles_kk]')
          )
          DROP TABLE #userroles_kk
          ;
          IF EXISTS
          (
              SELECT * FROM tempdb.dbo.sysobjects
              WHERE id = object_id(N'[tempdb].dbo.[#rolemember_kk]')
          )
          DROP TABLE #rolemember_kk
          ;
          IF EXISTS
          (
              SELECT * FROM tempdb.dbo.sysobjects
              WHERE id = object_id(N'[tempdb].dbo.[##db_name]')
          )
          DROP TABLE ##db_name
          ;
          DECLARE
          @db_name VARCHAR(255)
          ,@sql_text VARCHAR(MAX) 
          ;
          SET @sql_text =
          'CREATE TABLE ##db_name
          (
              LoginUserName VARCHAR(MAX)
              ,' 
          ;
          DECLARE cursDBs CURSOR FOR 
              SELECT [name]
              FROM sys.databases
              ORDER BY [name]
          ;
          OPEN cursDBs 
          ;
          FETCH NEXT FROM cursDBs INTO @db_name 
          WHILE @@FETCH_STATUS = 0 
              BEGIN 
                      SET @sql_text =
              @sql_text + QUOTENAME(@db_name) + ' VARCHAR(MAX)
              ,' 
                      FETCH NEXT FROM cursDBs INTO @db_name 
              END 
          CLOSE cursDBs 
          ;
          SET @sql_text =
              @sql_text + 'IsSysAdminLogin CHAR(1)
              ,IsEmptyRow CHAR(1)
          )' 
      
          --PRINT @sql_text
          EXEC (@sql_text)
          ;
          DEALLOCATE cursDBs 
          ;
          DECLARE
          @RoleName VARCHAR(255) 
          ,@UserName VARCHAR(255) 
          ;
          CREATE TABLE #permission 
          (
           LoginUserName VARCHAR(255)
           ,databasename VARCHAR(255)
           ,[role] VARCHAR(255)
          ) 
          ;
          DECLARE cursSysSrvPrinName CURSOR FOR 
              SELECT [name]
              FROM sys.server_principals 
              WHERE
              [type] IN ( 'S', 'U', 'G' )
              AND principal_id > 4
              AND [name] NOT LIKE '##%'
              ORDER BY [name]
          ;
          OPEN cursSysSrvPrinName
          ;
          FETCH NEXT FROM cursSysSrvPrinName INTO @UserName 
          WHILE @@FETCH_STATUS = 0 
          BEGIN 
              CREATE TABLE #userroles_kk 
              ( 
                   databasename VARCHAR(255)
                   ,[role] VARCHAR(255)
              ) 
              ;
              CREATE TABLE #rolemember_kk 
              ( 
                   dbrole VARCHAR(255)
                   ,membername VARCHAR(255)
                   ,membersid VARBINARY(2048)
              ) 
              ;
              DECLARE cursDatabases CURSOR FAST_FORWARD LOCAL FOR
              SELECT [name]
              FROM sys.databases
              ORDER BY [name]
              ;
              OPEN cursDatabases
              ;
              DECLARE 
              @DBN VARCHAR(255)
              ,@sqlText NVARCHAR(4000)
              ;
              FETCH NEXT FROM cursDatabases INTO @DBN
              WHILE @@FETCH_STATUS = 0
              BEGIN
                  SET @sqlText =
          N'USE ' + QUOTENAME(@DBN) + ';
          TRUNCATE TABLE #RoleMember_kk 
          INSERT INTO #RoleMember_kk 
          EXEC sp_helprolemember 
          INSERT INTO #UserRoles_kk
          (DatabaseName,[Role])
          SELECT db_name(),dbRole
          FROM #RoleMember_kk
          WHERE MemberName = ''' + @UserName + '''
          '
      
                  --PRINT @sqlText ;
                  EXEC sp_executesql @sqlText ;
              FETCH NEXT FROM cursDatabases INTO @DBN
              END
              CLOSE cursDatabases
              ;
              DEALLOCATE cursDatabases
              ;
              INSERT INTO #permission 
              SELECT
              @UserName 'user'
              ,b.name
              ,u.[role]
              FROM
              sys.sysdatabases b
              LEFT JOIN
              #userroles_kk u 
                  ON QUOTENAME(u.databasename) = QUOTENAME(b.name)
              ORDER  BY 1 
              ;
              DROP TABLE #userroles_kk
              ; 
              DROP TABLE #rolemember_kk
              ;
              FETCH NEXT FROM cursSysSrvPrinName INTO @UserName 
          END 
          CLOSE cursSysSrvPrinName 
          ;
          DEALLOCATE cursSysSrvPrinName 
          ;
          TRUNCATE TABLE ##db_name 
          ;
          DECLARE
          @d1 VARCHAR(MAX)
          ,@d2 VARCHAR(MAX)
          ,@d3 VARCHAR(MAX)
          ,@ss VARCHAR(MAX)
          ;
          DECLARE cursPermisTable CURSOR FOR
              SELECT * FROM #permission 
              ORDER BY 2 DESC 
          ;
          OPEN cursPermisTable
          ;
          FETCH NEXT FROM cursPermisTable INTO @d1,@d2,@d3
          WHILE @@FETCH_STATUS = 0 
          BEGIN 
              IF NOT EXISTS
              (
                  SELECT 1 FROM ##db_name WHERE LoginUserName = @d1
              )
              BEGIN 
                  SET @ss =
                  'INSERT INTO ##db_name(LoginUserName) VALUES (''' + @d1 + ''')' 
                  EXEC (@ss) 
                  ;
                  SET @ss =
                  'UPDATE ##db_name SET ' + @d2 + ' = ''' + @d3 + ''' WHERE LoginUserName = ''' + @d1 + '''' 
                  EXEC (@ss)
                  ;
              END 
              ELSE 
              BEGIN 
                  DECLARE
                  @var NVARCHAR(MAX)
                  ,@ParmDefinition NVARCHAR(MAX)
                  ,@var1 NVARCHAR(MAX)
                  ;
                  SET @var =
                  N'SELECT @var1 = ' + QUOTENAME(@d2) + ' FROM ##db_name WHERE LoginUserName = ''' + @d1 + ''''
                  ; 
                  SET @ParmDefinition =
                  N'@var1 NVARCHAR(600) OUTPUT '
                  ; 
                  EXECUTE Sp_executesql @var,@ParmDefinition,@var1 = @var1 OUTPUT
                  ;
                  SET @var1 =
                  ISNULL(@var1, ' ')
                  ;
                  SET @var =
                  '  UPDATE ##db_name SET ' + @d2 + '=''' + @var1 + ' ' + @d3 + ''' WHERE LoginUserName = ''' + @d1 + '''  '
                  ;
                  EXEC (@var)
                  ;
              END
              FETCH NEXT FROM cursPermisTable INTO @d1,@d2,@d3
          END 
          CLOSE cursPermisTable
          ;
          DEALLOCATE cursPermisTable 
          ;
          UPDATE ##db_name SET
          IsSysAdminLogin = 'Y'
          FROM
          ##db_name TT
          INNER JOIN
          dbo.syslogins SL
              ON TT.LoginUserName = SL.[name]
          WHERE
          SL.sysadmin = 1
          ;
          DECLARE cursDNamesAsColumns CURSOR FAST_FORWARD LOCAL FOR
          SELECT [name]
          FROM tempdb.sys.columns
          WHERE
          OBJECT_ID = OBJECT_ID('tempdb..##db_name')
          AND [name] NOT IN ('LoginUserName','IsEmptyRow')
          ORDER BY [name]
          ;
          OPEN cursDNamesAsColumns
          ;
          DECLARE 
          @ColN VARCHAR(255)
          ,@tSQLText NVARCHAR(4000)
          ;
          FETCH NEXT FROM cursDNamesAsColumns INTO @ColN
          WHILE @@FETCH_STATUS = 0
          BEGIN
              SET @tSQLText =
      N'UPDATE ##db_name SET
      IsEmptyRow = ''N''
      WHERE IsEmptyRow IS NULL
      AND ' + QUOTENAME(@ColN) + ' IS NOT NULL
      ;
      '
      
              --PRINT @tSQLText ;
              EXEC sp_executesql @tSQLText ;
          FETCH NEXT FROM cursDNamesAsColumns INTO @ColN
          END
          CLOSE cursDNamesAsColumns
          ;
          DEALLOCATE cursDNamesAsColumns
          ;
          UPDATE ##db_name SET
          IsEmptyRow = 'Y'
          WHERE IsEmptyRow IS NULL
          ;
          UPDATE ##db_name SET
          IsSysAdminLogin = 'N'
          FROM
          ##db_name TT
          INNER JOIN
          dbo.syslogins SL
              ON TT.LoginUserName = SL.[name]
          WHERE
          SL.sysadmin = 0
          ;
          SELECT * FROM ##db_name
          ;
          DROP TABLE ##db_name
          ;
          DROP TABLE #permission
          ;
      END TRY
      BEGIN CATCH
          DECLARE
          @cursDBs_Status INT
          ,@cursSysSrvPrinName_Status INT
          ,@cursDatabases_Status INT
          ,@cursPermisTable_Status INT
          ,@cursDNamesAsColumns_Status INT
          ;
          SELECT
          @cursDBs_Status = CURSOR_STATUS('GLOBAL','cursDBs')
          ,@cursSysSrvPrinName_Status = CURSOR_STATUS('GLOBAL','cursSysSrvPrinName')
          ,@cursDatabases_Status = CURSOR_STATUS('GLOBAL','cursDatabases')
          ,@cursPermisTable_Status = CURSOR_STATUS('GLOBAL','cursPermisTable')
          ,@cursDNamesAsColumns_Status = CURSOR_STATUS('GLOBAL','cursPermisTable')
          ;
          IF @cursDBs_Status > -2
              BEGIN
                  CLOSE cursDBs ;
                  DEALLOCATE cursDBs ;
              END
          IF @cursSysSrvPrinName_Status > -2
              BEGIN
                  CLOSE cursSysSrvPrinName ;
                  DEALLOCATE cursSysSrvPrinName ;
              END
          IF @cursDatabases_Status > -2
              BEGIN
                  CLOSE cursDatabases ;
                  DEALLOCATE cursDatabases ;
              END
          IF @cursPermisTable_Status > -2
              BEGIN
                  CLOSE cursPermisTable ;
                  DEALLOCATE cursPermisTable ;
              END
          IF @cursDNamesAsColumns_Status > -2
              BEGIN
                  CLOSE cursDNamesAsColumns ;
                  DEALLOCATE cursDNamesAsColumns ;
              END
          SELECT ErrorNum = ERROR_NUMBER(),ErrorMsg = ERROR_MESSAGE() ;
      END CATCH
      GO
      /*
      EXEC [master].dbo.uspGetPermissionsOfAllLogins_DBsOnColumns ;
      */
      

      【讨论】:

      • 根据user himanshu you can use [] to resolve it. sp_msforeachdb ' use [?] select db_name()' 我认为他的回答是作为评论,但由于他的帐户没有满足最低声誉,所以他发布了一个答案。
      • 同意threeFourOneSixOneThree。当括号到位时,使用 sp_foreachdb 或 sp_foreachtable 可以正常工作。
      【解决方案9】:
      CREATE PROCEDURE Get_permission 
      AS 
          DECLARE @db_name  VARCHAR(200), 
                  @sql_text VARCHAR(max) 
      
          SET @sql_text='Create table ##db_name (user_name varchar(max),' 
      
          DECLARE db_cursor CURSOR FOR 
            SELECT name 
            FROM   sys.databases 
      
          OPEN db_cursor 
      
          FETCH next FROM db_cursor INTO @db_name 
      
          WHILE @@FETCH_STATUS = 0 
            BEGIN 
                SET @sql_text=@sql_text + @db_name + ' varchar(max),' 
      
                FETCH next FROM db_cursor INTO @db_name 
            END 
      
          CLOSE db_cursor 
      
          SET @sql_text=@sql_text + 'Server_perm varchar(max))' 
      
          EXEC (@sql_text) 
      
          DEALLOCATE db_cursor 
      
          DECLARE @RoleName VARCHAR(50) 
          DECLARE @UserName VARCHAR(50) 
          DECLARE @CMD VARCHAR(1000) 
      
          CREATE TABLE #permission 
            ( 
               user_name    VARCHAR(50), 
               databasename VARCHAR(50), 
               role         VARCHAR(50) 
            ) 
      
          DECLARE longspcur CURSOR FOR 
            SELECT name 
            FROM   sys.server_principals 
            WHERE  type IN ( 'S', 'U', 'G' ) 
                   AND principal_id > 4 
                   AND name NOT LIKE '##%' 
                   AND name <> 'NT AUTHORITY\SYSTEM' 
                   AND name <> 'ONDEMAND\Administrator' 
                   AND name NOT LIKE 'steel%' 
      
          OPEN longspcur 
      
          FETCH next FROM longspcur INTO @UserName 
      
          WHILE @@FETCH_STATUS = 0 
            BEGIN 
                CREATE TABLE #userroles_kk 
                  ( 
                     databasename VARCHAR(50), 
                     role         VARCHAR(50) 
                  ) 
      
                CREATE TABLE #rolemember_kk 
                  ( 
                     dbrole     VARCHAR(100), 
                     membername VARCHAR(100), 
                     membersid  VARBINARY(2048) 
                  ) 
      
                SET @CMD = 'use ? truncate table #RoleMember_kk insert into #RoleMember_kk exec sp_helprolemember  insert into #UserRoles_kk (DatabaseName, Role) select db_name(), dbRole from #RoleMember_kk where MemberName = ''' + @UserName + '''' 
      
                EXEC Sp_msforeachdb 
                  @CMD 
      
                INSERT INTO #permission 
                SELECT @UserName 'user', 
                       b.name, 
                       u.role 
                FROM   sys.sysdatabases b 
                       LEFT OUTER JOIN #userroles_kk u 
                                    ON u.databasename = b.name --and u.Role='db_owner' 
                ORDER  BY 1 
      
                DROP TABLE #userroles_kk; 
      
                DROP TABLE #rolemember_kk; 
      
                FETCH next FROM longspcur INTO @UserName 
            END 
      
          CLOSE longspcur 
      
          DEALLOCATE longspcur 
      
          TRUNCATE TABLE ##db_name 
      
          DECLARE @d1 VARCHAR(max), 
                  @d2 VARCHAR(max), 
                  @d3 VARCHAR(max), 
                  @ss VARCHAR(max) 
          DECLARE perm_cur CURSOR FOR 
            SELECT * 
            FROM   #permission 
            ORDER  BY 2 DESC 
      
          OPEN perm_cur 
      
          FETCH next FROM perm_cur INTO @d1, @d2, @d3 
      
          WHILE @@FETCH_STATUS = 0 
            BEGIN 
                IF NOT EXISTS(SELECT 1 
                              FROM   ##db_name 
                              WHERE  user_name = @d1) 
                  BEGIN 
                      SET @ss='insert into ##db_name(user_name) values (''' 
                              + @d1 + ''')' 
      
                      EXEC (@ss) 
      
                      SET @ss='update ##db_name set ' + @d2 + '=''' + @d3 
                              + ''' where user_name=''' + @d1 + '''' 
      
                      EXEC (@ss) 
                  END 
                ELSE 
                  BEGIN 
                      DECLARE @var            NVARCHAR(max), 
                              @ParmDefinition NVARCHAR(max), 
                              @var1           NVARCHAR(max) 
      
                      SET @var = N'select @var1=' + @d2 
                                 + ' from ##db_name where USER_NAME=''' + @d1 
                                 + ''''; 
                      SET @ParmDefinition = N'@var1 nvarchar(300) OUTPUT'; 
      
                      EXECUTE Sp_executesql 
                        @var, 
                        @ParmDefinition, 
                        @var1=@var1 output; 
      
                      SET @var1=Isnull(@var1, ' ') 
                      SET @var= '  update ##db_name set ' + @d2 + '=''' + @var1 + ' ' 
                                + @d3 + ''' where user_name=''' + @d1 + '''  ' 
      
                      EXEC (@var) 
                  END 
      
                FETCH next FROM perm_cur INTO @d1, @d2, @d3 
            END 
      
          CLOSE perm_cur 
      
          DEALLOCATE perm_cur 
      
          SELECT * 
          FROM   ##db_name 
      
          DROP TABLE ##db_name 
      
          DROP TABLE #permission 
      

      【讨论】:

      • 这个不错。谢谢!
      【解决方案10】:

      非常感谢出色的审计脚本。

      我强烈建议审计用户使用出色的 Kenneth Fisher (b | t) 存储过程:

      【讨论】:

      • 2019年死链
      • @gbeaven 链接已修复
      • 我结合使用 Kenneth Fisher 的脚本和我在下面发布的脚本。我在下面发布的脚本以易于在 Excel 中切片和切块的格式输出。我使用 Redgate SSMS 插件和在 Excel 中打开功能将我的结果导出到 Excel,然后应用快速过滤器。 Kenneth 的工具对于放大特定的负责人或角色更为有用。
      【解决方案11】:

      由于低代表无法回复要求在多个数据库/SQL Server 上运行它的人。

      创建一个已注册的服务器组并在它们之间进行查询,我们如下所示,只需在数据库中游标:

      --Make sure all ' are doubled within the SQL string.
      
      DECLARE @dbname VARCHAR(50)   
      DECLARE @statement NVARCHAR(max)
      
      DECLARE db_cursor CURSOR 
      LOCAL FAST_FORWARD
      FOR  
      SELECT name
      FROM MASTER.dbo.sysdatabases
      where name like '%DBName%'
      
      OPEN db_cursor  
      FETCH NEXT FROM db_cursor INTO @dbname  
      WHILE @@FETCH_STATUS = 0  
      BEGIN  
      
      SELECT @statement = 'use '+@dbname +';'+ '
      /*
      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:
      UserType        : Value will be either ''SQL User'', ''Windows User'', or ''Windows Group''.
                        This reflects the type of user/group defined for the SQL Server 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.
      LoginName       : SQL or Windows/Active Directory user account.  This could also be an Active Directory group.
      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.
      Schema          : Name of the schema the object is in.
      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.
      */
      
          --1) List all access provisioned to a SQL user or Windows user/group directly
          SELECT
              [UserType] = CASE princ.[type]
                               WHEN ''S'' THEN ''SQL User''
                               WHEN ''U'' THEN ''Windows User''
                               WHEN ''G'' THEN ''Windows Group''
                           END,
              [DatabaseUserName] = princ.[name],
              [LoginName]        = ulogin.[name],
              [Role]             = NULL,
              [PermissionType]   = perm.[permission_name],
              [PermissionState]  = perm.[state_desc],
              [ObjectType] = CASE perm.[class]
                                 WHEN 1 THEN obj.[type_desc]        -- Schema-contained objects
                                 ELSE perm.[class_desc]             -- Higher-level objects
                             END,
              [Schema] = objschem.[name],
              [ObjectName] = CASE perm.[class]
                                 WHEN 3 THEN permschem.[name]       -- Schemas
                                 WHEN 4 THEN imp.[name]             -- Impersonations
                                 ELSE OBJECT_NAME(perm.[major_id])  -- General objects
                             END,
              [ColumnName] = col.[name]
          FROM
              --Database user
              sys.database_principals            AS princ
              --Login accounts
              LEFT JOIN sys.server_principals    AS ulogin    ON ulogin.[sid] = princ.[sid]
              --Permissions
              LEFT JOIN sys.database_permissions AS perm      ON perm.[grantee_principal_id] = princ.[principal_id]
              LEFT JOIN sys.schemas              AS permschem ON permschem.[schema_id] = perm.[major_id]
              LEFT JOIN sys.objects              AS obj       ON obj.[object_id] = perm.[major_id]
              LEFT JOIN sys.schemas              AS objschem  ON objschem.[schema_id] = obj.[schema_id]
              --Table columns
              LEFT JOIN sys.columns              AS col       ON col.[object_id] = perm.[major_id]
                                                                 AND col.[column_id] = perm.[minor_id]
              --Impersonations
              LEFT JOIN sys.database_principals  AS imp       ON imp.[principal_id] = perm.[major_id]
          WHERE
              princ.[type] IN (''S'',''U'',''G'')
              -- No need for these system accounts
              AND princ.[name] NOT IN (''sys'', ''INFORMATION_SCHEMA'')
      
      UNION
      
          --2) List all access provisioned to a SQL user or Windows user/group through a database or application role
          SELECT
              [UserType] = CASE membprinc.[type]
                               WHEN ''S'' THEN ''SQL User''
                               WHEN ''U'' THEN ''Windows User''
                               WHEN ''G'' THEN ''Windows Group''
                           END,
              [DatabaseUserName] = membprinc.[name],
              [LoginName]        = ulogin.[name],
              [Role]             = roleprinc.[name],
              [PermissionType]   = perm.[permission_name],
              [PermissionState]  = perm.[state_desc],
              [ObjectType] = CASE perm.[class]
                                 WHEN 1 THEN obj.[type_desc]        -- Schema-contained objects
                                 ELSE perm.[class_desc]             -- Higher-level objects
                             END,
              [Schema] = objschem.[name],
              [ObjectName] = CASE perm.[class]
                                 WHEN 3 THEN permschem.[name]       -- Schemas
                                 WHEN 4 THEN imp.[name]             -- Impersonations
                                 ELSE OBJECT_NAME(perm.[major_id])  -- General objects
                             END,
              [ColumnName] = col.[name]
          FROM
              --Role/member associations
              sys.database_role_members          AS members
              --Roles
              JOIN      sys.database_principals  AS roleprinc ON roleprinc.[principal_id] = members.[role_principal_id]
              --Role members (database users)
              JOIN      sys.database_principals  AS membprinc ON membprinc.[principal_id] = members.[member_principal_id]
              --Login accounts
              LEFT JOIN sys.server_principals    AS ulogin    ON ulogin.[sid] = membprinc.[sid]
              --Permissions
              LEFT JOIN sys.database_permissions AS perm      ON perm.[grantee_principal_id] = roleprinc.[principal_id]
              LEFT JOIN sys.schemas              AS permschem ON permschem.[schema_id] = perm.[major_id]
              LEFT JOIN sys.objects              AS obj       ON obj.[object_id] = perm.[major_id]
              LEFT JOIN sys.schemas              AS objschem  ON objschem.[schema_id] = obj.[schema_id]
              --Table columns
              LEFT JOIN sys.columns              AS col       ON col.[object_id] = perm.[major_id]
                                                                 AND col.[column_id] = perm.[minor_id]
              --Impersonations
              LEFT JOIN sys.database_principals  AS imp       ON imp.[principal_id] = perm.[major_id]
          WHERE
              membprinc.[type] IN (''S'',''U'',''G'')
              -- No need for these system accounts
              AND membprinc.[name] NOT IN (''sys'', ''INFORMATION_SCHEMA'')
      
      UNION
      
          --3) List all access provisioned to the public role, which everyone gets by default
          SELECT
              [UserType]         = ''{All Users}'',
              [DatabaseUserName] = ''{All Users}'',
              [LoginName]        = ''{All Users}'',
              [Role]             = roleprinc.[name],
              [PermissionType]   = perm.[permission_name],
              [PermissionState]  = perm.[state_desc],
              [ObjectType] = CASE perm.[class]
                                 WHEN 1 THEN obj.[type_desc]        -- Schema-contained objects
                                 ELSE perm.[class_desc]             -- Higher-level objects
                             END,
              [Schema] = objschem.[name],
              [ObjectName] = CASE perm.[class]
                                 WHEN 3 THEN permschem.[name]       -- Schemas
                                 WHEN 4 THEN imp.[name]             -- Impersonations
                                 ELSE OBJECT_NAME(perm.[major_id])  -- General objects
                             END,
              [ColumnName] = col.[name]
          FROM
              --Roles
              sys.database_principals            AS roleprinc
              --Role permissions
              LEFT JOIN sys.database_permissions AS perm      ON perm.[grantee_principal_id] = roleprinc.[principal_id]
              LEFT JOIN sys.schemas              AS permschem ON permschem.[schema_id] = perm.[major_id]
              --All objects
              JOIN      sys.objects              AS obj       ON obj.[object_id] = perm.[major_id]
              LEFT JOIN sys.schemas              AS objschem  ON objschem.[schema_id] = obj.[schema_id]
              --Table columns
              LEFT JOIN sys.columns              AS col       ON col.[object_id] = perm.[major_id]
                                                                 AND col.[column_id] = perm.[minor_id]
              --Impersonations
              LEFT JOIN sys.database_principals  AS imp       ON imp.[principal_id] = perm.[major_id]
          WHERE
              roleprinc.[type] = ''R''
              AND roleprinc.[name] = ''public''
              AND obj.[is_ms_shipped] = 0
      
      ORDER BY
          [UserType],
          [DatabaseUserName],
          [LoginName],
          [Role],
          [Schema],
          [ObjectName],
          [ColumnName],
          [PermissionType],
          [PermissionState],
          [ObjectType]
      '
      exec sp_executesql @statement
      
      FETCH NEXT FROM db_cursor INTO @dbname  
      END  
      CLOSE db_cursor  
      DEALLOCATE db_cursor 
      

      这个帖子对我帮助很大,谢谢大家!

      【讨论】:

      • 今天这对我帮助很大。我唯一更改的是输出数据库名称(当我运行多个数据库的查询时),使用DB_NAME() 并将输出存储在临时表中以避免最终得到多个结果集。谢谢!
      【解决方案12】:

      我几乎尝试了所有这些,但我很快注意到有些缺失,尤其是系统管理员用户。在我们即将进行的审计中出现这样的漏洞看起来不太好,所以这就是我想出的

      USE master
      GO
      
      SELECT DISTINCT 
              p.name AS [loginname] ,
              --p.type,
              p.type_desc ,
              p.is_disabled,
              s.sysadmin,
              sp.permission_name
      FROM sys.server_principals p
      INNER JOIN sys.syslogins s ON p.sid = s.sid
      INNER JOIN sys.server_permissions sp ON p.principal_id = sp.grantee_principal_id
      WHERE p.type_desc IN ('SQL_LOGIN', 'WINDOWS_LOGIN', 'WINDOWS_GROUP')
          -- Logins that are not process logins
          AND p.name NOT LIKE '##%'
      ORDER BY p.name
      GO
      

      【讨论】:

        【解决方案13】:

        我刚刚在 Jeremy 的回答中添加了以下内容,因为我有一个分配给数据库 db_datareader 的角色,该角色没有显示该角色拥有的权限。我尝试浏览每个人帖子中的所有答案,但找不到任何可以做到这一点的东西,所以我添加了自己的查询。

            SELECT 
            UserType='Role', 
            DatabaseUserName = '{Role Members}',
            LoginName = DP2.name,
            Role = DP1.name,
            'SELECT' AS [PermissionType] ,
            [PermissionState]  = 'GRANT',
            [ObjectType] = 'Table',
            [Schema] = 'dbo',
            [ObjectName] = 'All Tables',
            [ColumnName] = NULL
        FROM sys.database_role_members AS DRM  
        RIGHT OUTER JOIN sys.database_principals AS DP1  
            ON DRM.role_principal_id = DP1.principal_id  
        LEFT OUTER JOIN sys.database_principals AS DP2  
            ON DRM.member_principal_id = DP2.principal_id  
        WHERE DP1.type = 'R'
        AND DP2.name IS NOT NULL
        

        【讨论】:

          【解决方案14】:

          一个仅显示您是否是系统管理员的简单查询:

          IF IS_SRVROLEMEMBER ('sysadmin') = 1  
             print 'Current user''s login is a member of the sysadmin role'  
          ELSE IF IS_SRVROLEMEMBER ('sysadmin') = 0  
             print 'Current user''s login is NOT a member of the sysadmin role'  
          ELSE IF IS_SRVROLEMEMBER ('sysadmin') IS NULL  
             print 'ERROR: The server role specified is not valid.';
          

          【讨论】:

            【解决方案15】:

            这是 Jeremy 提交的最受欢迎的答案,但经过修改以包含 Greg Sipes 提到的 sysadmin 和 disabled 标志以及 log_date_time 列。

            两全其美?

            /*
            Source: 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 account.  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 
            SELECT  
                [UserName] = CASE princ.[type] 
                                WHEN 'S' THEN princ.[name]
                                WHEN 'U' THEN ulogin.[name] COLLATE Latin1_General_CI_AI
                             END,
                [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,--perm.[class_desc],       
                [ObjectName] = OBJECT_NAME(perm.major_id),
                [ColumnName] = col.[name],
                sp.is_disabled,
                s.sysadmin,
                GETDATE() AS [log_date_time]
            FROM    
                --database user
                sys.database_principals princ  
            LEFT JOIN
                --Login accounts
                sys.login_token ulogin on princ.[sid] = ulogin.[sid]
            LEFT JOIN        
                --Permissions
                sys.database_permissions perm ON perm.[grantee_principal_id] = princ.[principal_id]
            LEFT JOIN
                --Table columns
                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]
            LEFT JOIN sys.syslogins s ON princ.sid = s.sid
            LEFT JOIN sys.server_principals sp ON princ.name = sp.name
            WHERE 
                princ.[type] in ('S','U')
            UNION
            --List all access provisioned to a sql user or windows user/group through a database or application role
            SELECT  
                [UserName] = CASE memberprinc.[type] 
                                WHEN 'S' THEN memberprinc.[name]
                                WHEN 'U' THEN ulogin.[name] COLLATE Latin1_General_CI_AI
                             END,
                [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,--perm.[class_desc],   
                [ObjectName] = OBJECT_NAME(perm.major_id),
                [ColumnName] = col.[name],
                sp.is_disabled,
                s.sysadmin,
                GETDATE() AS [log_date_time]
            FROM    
                --Role/member associations
                sys.database_role_members members
            JOIN
                --Roles
                sys.database_principals roleprinc ON roleprinc.[principal_id] = members.[role_principal_id]
            JOIN
                --Role members (database users)
                sys.database_principals memberprinc ON memberprinc.[principal_id] = members.[member_principal_id]
            LEFT JOIN
                --Login accounts
                sys.login_token ulogin on memberprinc.[sid] = ulogin.[sid]
            LEFT JOIN        
                --Permissions
                sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id]
            LEFT JOIN
                --Table columns
                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]
            LEFT JOIN sys.syslogins s ON memberprinc.[sid] = s.sid
            LEFT JOIN sys.server_principals sp ON memberprinc.[name] = sp.name
            UNION
            --List all access provisioned to the public role, which everyone gets by default
            SELECT  
                [UserName] = '{All Users}',
                [UserType] = '{All Users}', 
                [DatabaseUserName] = '{All Users}',       
                [Role] = roleprinc.[name],      
                [PermissionType] = perm.[permission_name],       
                [PermissionState] = perm.[state_desc],       
                [ObjectType] = obj.type_desc,--perm.[class_desc],  
                [ObjectName] = OBJECT_NAME(perm.major_id),
                [ColumnName] = col.[name],
                sp.is_disabled,
                s.sysadmin,
                GETDATE() AS [log_date_time]
            FROM    
                --Roles
                sys.database_principals roleprinc
            LEFT JOIN        
                --Role permissions
                sys.database_permissions perm ON perm.[grantee_principal_id] = roleprinc.[principal_id]
            LEFT JOIN
                --Table columns
                sys.columns col on col.[object_id] = perm.major_id 
                                AND col.[column_id] = perm.[minor_id]     
            LEFT JOIN sys.syslogins s ON roleprinc.sid = s.sid
            LEFT JOIN sys.server_principals sp ON roleprinc.name = sp.name
            JOIN 
                --All objects   
                sys.objects obj ON obj.[object_id] = perm.[major_id]
            WHERE
                --Only roles
                roleprinc.[type] = 'R' AND
                --Only public role
                roleprinc.[name] = 'public' AND
                --Only objects of ours, not the MS objects
                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] 
            

            【讨论】:

              【解决方案16】:

              很遗憾,由于声誉不足,我无法对 Sean Rose 的帖子发表评论,但是我不得不修改脚本的“公共”角色部分,因为由于 (INNER) JOIN,它没有显示 SCHEMA 范围的权限针对 sys.objects。在更改为 LEFT JOIN 之后,我还必须修改 WHERE 子句逻辑以省略系统对象。我对公共权限的修改查询如下。

              --3) List all access provisioned to the public role, which everyone gets by default
                  SELECT
                      @@servername ServerName
                      , db_name() DatabaseName
                      , [UserType]         = '{All Users}',
                      [DatabaseUserName] = '{All Users}',
                      [LoginName]        = '{All Users}',
                      [Role]             = roleprinc.[name],
                      [PermissionType]   = perm.[permission_name],
                      [PermissionState]  = perm.[state_desc],
                      [ObjectType] = CASE perm.[class]
                                         WHEN 1 THEN obj.[type_desc]        -- Schema-contained objects
                                         ELSE perm.[class_desc]             -- Higher-level objects
                                     END,
                      [Schema] = objschem.[name],
                      [ObjectName] = CASE perm.[class]
                                         WHEN 3 THEN permschem.[name]       -- Schemas
                                         WHEN 4 THEN imp.[name]             -- Impersonations
                                         ELSE OBJECT_NAME(perm.[major_id])  -- General objects
                                     END,
                      [ColumnName] = col.[name]
                  FROM
                      --Roles
                      sys.database_principals            AS roleprinc
                      --Role permissions
                      LEFT JOIN sys.database_permissions AS perm      ON perm.[grantee_principal_id] = roleprinc.[principal_id]
                      LEFT JOIN sys.schemas              AS permschem ON permschem.[schema_id] = perm.[major_id]
                      --All objects
                      LEFT JOIN sys.objects              AS obj       ON obj.[object_id] = perm.[major_id]
                      LEFT JOIN sys.schemas              AS objschem  ON objschem.[schema_id] = obj.[schema_id]
                      --Table columns
                      LEFT JOIN sys.columns              AS col       ON col.[object_id] = perm.[major_id]
                                                                         AND col.[column_id] = perm.[minor_id]
                      --Impersonations
                      LEFT JOIN sys.database_principals  AS imp       ON imp.[principal_id] = perm.[major_id]
                  WHERE
                      roleprinc.[type] = 'R'
                      AND roleprinc.[name] = 'public'
                      AND isnull(obj.[is_ms_shipped], 0) = 0
                      AND isnull(object_schema_name(perm.[major_id]), '') <> 'sys'
              
              ORDER BY
                  [UserType],
                  [DatabaseUserName],
                  [LoginName],
                  [Role],
                  [Schema],
                  [ObjectName],
                  [ColumnName],
                  [PermissionType],
                  [PermissionState],
                  [ObjectType]
              

              【讨论】:

                【解决方案17】:

                如果您想检查特定登录名对数据库的访问权限,请使用以下简单脚本:

                sys.sp_helplogins @LoginNamePattern = 'Domain\login' -- 系统名

                【讨论】:

                  【解决方案18】:

                  --好吧,轮到我回馈了,享受吧

                  此报告标题动态获取报告运行的 SQL 实例名称、日期\时间和帐户名称,所有这些都是优秀的审计员想知道的。 :)

                  注意 - 如果您在主数据库上有一个名为“环境”的扩展属性,则该值(无论您使用什么:PreProd、Development、Production、DR 等)都将包含在报告标题中。

                  BEGIN
                  
                  BEGIN TRY
                      SET NOCOUNT ON
                      SELECT 'See Messages Tab..... use  Ctrl+SHIFT+F and re-run to ''send to file'''
                      DECLARE @DBName nvarchar(2000) = DB_NAME()
                      DECLARE @User_Name nvarchar(200) = suser_sname()
                      DECLARE @Account_Name nvarchar(200)
                      DECLARE @Granted_permissions nvarchar(2000)
                      DECLARE @Permission_State nvarchar(200)
                      DECLARE @ParentObject nvarchar(200)
                      DECLARE @env2 varchar(50) = Convert(varchar(50),(Select ServerProperty('Servername')));
                      DECLARE @day varchar(50) = FORMAT (getdate(), 'dddd, MM, yyyy');
                      DECLARE @clk varchar(50) = FORMAT (getdate(), 'hh:mm:ss tt') ;
                      DECLARE @env1 VARCHAR(25) = (SELECT CAST(value AS varchar(25)) 
                      FROM [master].[sys].fn_listextendedproperty('environment', default, default, default, default, default, default));
                  
                      PRINT '*** ' + @DBName + ' Security Audit Report ***';
                      PRINT '      in the ' + @env1 + ' environment'; 
                      PRINT '      on SQL Instance: ' + @env2;  
                      PRINT '      '+ @day + ' at ' + @clk;
                      PRINT '      run under account ' + @User_Name;
                      PRINT ' '
                  
                      CREATE TABLE #GP(
                          DBName NVARCHAR(200),
                          Account_Name NVARCHAR(200),
                          Granted_Permissions NVARCHAR(max),
                          Permission_State NVARCHAR(200),
                          ParentObject NVARCHAR(200)
                          )
                      ;WITH SampleDataR AS
                          (SELECT
                              DB_NAME() AS 'DBName'
                              ,dp.name AS 'Account_Name'
                              ,dpm.permission_name AS 'Granted_Permissions'
                              ,dpm.state_desc AS 'Permission_State'
                              ,dpm.class_desc AS 'ParentObject'
                              , ROW_NUMBER() OVER (PARTITION BY DB_NAME(), dp.[name] ,dpm.state_desc, dpm.class_desc ORDER BY permission_name) rownum
                          FROM sys.database_principals dp
                              LEFT OUTER JOIN [sys].[database_permissions] dpm
                              ON dp.principal_id = dpm.grantee_principal_id
                          WHERE dp.type ='R'
                          AND dp.sid IS NOT NULL
                          AND dp.name <> 'public' 
                          AND dp.name NOT LIKE 'db_a%'
                          AND dp.name NOT LIKE 'db_b%'
                          AND dp.name NOT LIKE 'db_d%'
                          AND dp.name NOT LIKE 'db_o%'
                          AND dp.name NOT LIKE 'db_s%'
                          --AND dpm.class_desc = 'DATABASE'  -- remove to see schema based permissions
                          ) 
                  
                          --Select * from SampleDataR
                  
                      INSERT INTO #GP
                      SELECT DISTINCT 
                          DBName
                          ,Account_Name
                          ,(SELECT Granted_Permissions + 
                              CASE 
                                  WHEN s1.rownum = (select MAX(rownum) 
                                  FROM SampleDataR 
                                  WHERE DBName = s1.DBName AND 
                                  Account_Name = s1.Account_Name AND
                                  ParentObject = s1.ParentObject)
                                  THEN ' (' + Permission_State + '), '
                                  ELSE ' (' + Permission_State + '),  '
                              END 
                      FROM SampleDataR s1
                      WHERE s1.DBName = s2.DBName AND 
                            s1.Account_Name = s2.Account_Name AND
                            s1.ParentObject = s2.ParentObject
                          FOR xml path(''),type).value('(.)[1]','varchar(max)'
                          ) Granted_Permissions
                          ,Permission_State
                          ,ParentObject
                          FROM SampleDataR s2
                  
                          --Select * from #GP
                  
                      PRINT  'Assigned Role Permissions'
                      PRINT ' '
                      SET NOCOUNT ON
                      DECLARE cur CURSOR FOR
                          SELECT DISTINCT DBName, Account_Name, ParentObject, Granted_permissions 
                          FROM #GP
                  
                      OPEN cur
                          SET NOCOUNT ON
                          FETCH NEXT FROM cur INTO @DBname, @Account_Name, @ParentObject, @Granted_permissions;
                          WHILE @@FETCH_STATUS = 0
                          BEGIN   
                              PRINT @DBName + ', ' + @Account_Name +  ', ' + '[' + @ParentObject + '], ' + @Granted_permissions
                              FETCH NEXT FROM cur INTO @DBname, @Account_Name,  @ParentObject , @Granted_permissions;
                          END
                      CLOSE cur;
                      DEALLOCATE cur;
                      SET NOCOUNT ON
                      DROP Table #GP
                  
                      SET NOCOUNT ON
                      DECLARE @DBName2 nvarchar(200)
                      DECLARE @Account_Name2 nvarchar(200)
                      DECLARE @Granted_permissions2 nvarchar(200)
                  
                      CREATE TABLE #GP2(
                          DBName NVARCHAR(200),
                          Account_Name NVARCHAR(200) ,
                          Granted_Permissions NVARCHAR(200)
                          )
                      ;WITH SampleDataR AS
                          (SELECT
                              DB_NAME() AS 'DBName'
                              ,dp.name AS 'Account_Name'
                              --,dp.type
                              ,dpm.permission_name
                              ,ROW_NUMBER() OVER (PARTITION BY DB_NAME(), dp.[name] ORDER BY permission_name) rownum
                          FROM sys.database_principals dp
                              LEFT OUTER JOIN [sys].[database_permissions] dpm
                              ON dp.principal_id = dpm.grantee_principal_id
                                  --order by dp.type
                          WHERE dp.type not in ('A', 'R', 'X') --removed  'G',
                          AND dp.sid is not null
                          AND dp.name not in ('guest','dbo')
                          ) 
                      INSERT INTO #GP2 
                      SELECT DISTINCT 
                          DBName
                          ,Account_Name
                          ,(SELECT permission_name + 
                              CASE 
                                  WHEN s1.rownum = (select MAX(rownum) 
                                  FROM SampleDataR 
                                  WHERE DBName = s1.DBName and Account_Name = s1.Account_Name
                              )
                              THEN '' 
                              ELSE ',' 
                              END 
                      FROM SampleDataR s1
                      WHERE s1.DBName = s2.DBName AND s1.Account_Name = s2.Account_Name
                          FOR xml path(''),type).value('(.)[1]','varchar(max)') Granted_Permissions
                          FROM SampleDataR s2;
                  
                      PRINT ' '
                      PRINT ' '
                      PRINT  'Assigned User Permissions'
                      PRINT ' '
                      DECLARE cur CURSOR FOR
                          SELECT DBName, Account_Name, Granted_permissions 
                          FROM #GP2
                      OPEN cur
                          SET NOCOUNT ON
                          FETCH NEXT FROM cur INTO @DBname2, @Account_Name2, @Granted_permissions2;
                          WHILE @@FETCH_STATUS = 0
                          BEGIN   
                              PRINT @DBName2 + ', ' + @Account_Name2 + ', ' + @Granted_permissions2
                              FETCH NEXT FROM cur INTO @DBname2, @Account_Name2, @Granted_permissions2;
                          END
                      CLOSE cur;
                      DEALLOCATE cur;
                      DROP TABLE #GP2
                  
                      SET NOCOUNT ON
                      DECLARE @DBName3 nvarchar(200)
                      DECLARE @Role_Name3 nvarchar(max)
                      DECLARE @Members3 nvarchar(max)
                  
                      CREATE TABLE #GP3(
                          DBName NVARCHAR(200),
                          Role_Name NVARCHAR(max),
                          members NVARCHAR(max)
                          )
                      ;WITH SampleDataR AS
                          (SELECT
                              DB_NAME() AS 'DBName'
                              ,r.name AS 'role_name'
                              ,m.name AS 'members'
                              ,ROW_NUMBER() OVER (PARTITION BY DB_NAME(), r.[name] ORDER BY m.[name]) rownum
                          FROM sys.database_role_members rm 
                              INNER JOIN sys.database_principals r on rm.role_principal_id = r.principal_id
                              INNER JOIN sys.database_principals m on rm.member_principal_id = m.principal_id
                          ) 
                  
                      INSERT INTO #GP3
                      SELECT DISTINCT 
                          DBName
                          ,Role_Name
                          ,(SELECT Members + 
                              CASE 
                                  WHEN s3.rownum = (select MAX(rownum) 
                                  FROM SampleDataR 
                                  WHERE DBName = s3.DBName and Role_Name = s3.Role_Name
                                  )
                              THEN ',' 
                              ELSE ',' 
                              END 
                      FROM SampleDataR s1
                      WHERE s1.DBName = s3.DBName and s1.Role_Name = s3.Role_Name
                          FOR xml path(''),type).value('(.)[1]','varchar(max)') Members
                          FROM SampleDataR s3
                  
                      PRINT ' '
                      PRINT ' '
                      PRINT  'Assigned Role Membership'
                      PRINT ' '
                      DECLARE cur CURSOR FOR
                          SELECT DBName, Role_Name, Members 
                          FROM #GP3
                      OPEN cur
                          SET NOCOUNT ON
                          FETCH NEXT FROM cur INTO @DBname3, @Role_Name3, @Members3;
                          WHILE @@FETCH_STATUS = 0
                          BEGIN   
                              PRINT @DBName3 + ', ' + @Role_Name3 + ', ' + @Members3
                              FETCH NEXT FROM cur INTO @DBname3, @Role_Name3, @Members3;
                          END
                      CLOSE cur;
                      DEALLOCATE cur;
                      DROP Table #GP3;
                  END TRY
                  
                  BEGIN CATCH  
                     SELECT 'Real ERROR at Line #' + CAST(ERROR_LINE() AS VARCHAR(20));
                     -- Throw/raise and error caught from the Try section. 
                     THROW; 
                  END CATCH;
                  

                  结束

                  --非常适合保存为存储过程

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-03-02
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-05-05
                    • 2011-04-02
                    相关资源
                    最近更新 更多