Una consulta que enumera todos los usuarios asignados para un inicio de sesión determinado


19

Al mirar las propiedades de un inicio de sesión particular, es posible ver una lista de usuarios asignados a ese inicio de sesión: ingrese la descripción de la imagen aquí

Perfilé SQL Server Management Studio (SSMS) y veo que SSMS se conecta a cada base de datos de una en una y recupera información de sys.database_permissions

¿Es posible escribir una sola consulta que recupere la información de mapeo del usuario que se muestra arriba o me veo obligado a usar un cursor o sp_MSforeachdb o algo así?


Respuestas:


15

Aquí hay una forma de usar SQL dinámico. Realmente no hay ninguna forma de hacer esto sin iterar, pero este enfoque es mucho más seguro que las opciones no documentadas, no compatibles y con erroressp_MSforeachdb .

Esto obtendrá una lista de todas las bases de datos en línea, el usuario asignado (si existe) junto con el nombre de esquema predeterminado y una lista separada por comas de los roles a los que pertenecen.

DECLARE @name SYSNAME = N'your login name'; -- input param, presumably

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'UNION ALL SELECT N''' + REPLACE(name,'''','''''') + ''',
  p.name, p.default_schema_name, STUFF((SELECT N'','' + r.name 
  FROM ' + QUOTENAME(name) + N'.sys.database_principals AS r
  INNER JOIN ' + QUOTENAME(name) + N'.sys.database_role_members AS rm
   ON r.principal_id = rm.role_principal_id
  WHERE rm.member_principal_id = p.principal_id
  FOR XML PATH, TYPE).value(N''.[1]'',''nvarchar(max)''),1,1,N'''')
 FROM sys.server_principals AS sp
 LEFT OUTER JOIN ' + QUOTENAME(name) + '.sys.database_principals AS p
 ON sp.sid = p.sid
 WHERE sp.name = @name '
FROM sys.databases WHERE [state] = 0;

SET @sql = STUFF(@sql, 1, 9, N'');

PRINT @sql;
EXEC master.sys.sp_executesql @sql, N'@name SYSNAME', @name;

1
Nota interesante, tuve que agregar intercalaciones explícitas a las columnas p.name y p.default_schema_name para que la unión funcione correctamente
Michael J Swart

@MichaelJSwart Ah sí, me he encontrado con esto antes cuando las bases de datos tienen diferentes clasificaciones (algunas columnas de metadatos usan la clasificación del servidor pero otras heredan la clasificación de la base de datos). Espero que las únicas personas que realmente se queman sean aquellas que insisten en usar caracteres extravagantes en los nombres de entidades que solo se admiten en una recopilación oscura ...
Aaron Bertrand

7

Esta secuencia de comandos se modifica ligeramente de una secuencia de comandos mencionada que hará lo que está buscando. Reemplace 'ThursdayClass' con el inicio de sesión para el que necesita información. https://www.simple-talk.com/sql/sql-tools/the-sqlcmd-workbench/

    SET NOCOUNT ON
    CREATE TABLE #temp
        (
          SERVER_name SYSNAME NULL ,
          Database_name SYSNAME NULL ,
          UserName SYSNAME ,
          GroupName SYSNAME ,
          LoginName SYSNAME NULL ,
          DefDBName SYSNAME NULL ,
          DefSchemaName SYSNAME NULL ,
          UserID INT ,
          [SID] VARBINARY(85)
        )

    DECLARE @command VARCHAR(MAX)
    --this will contain all the databases (and their sizes!)
    --on a server
    DECLARE @databases TABLE
        (
          Database_name VARCHAR(128) ,
          Database_size INT ,
          remarks VARCHAR(255)
        )
    INSERT  INTO @databases--stock the table with the list of databases
            EXEC sp_databases

    SELECT  @command = COALESCE(@command, '') + '
    USE ' + database_name + '
    insert into #temp (UserName,GroupName, LoginName,
                        DefDBName, DefSchemaName,UserID,[SID])
         Execute sp_helpuser
    UPDATE #TEMP SET database_name=DB_NAME(),
                     server_name=@@ServerName
    where database_name is null
    '
    FROM    @databases
    EXECUTE ( @command )

    SELECT  loginname ,
            UserName ,
            Database_name
    FROM    #temp
    WHERE   LoginName = 'ThursdayClass' 

Gracias Taiob, esto funciona bien, (encerraría la columna nombre_basedatos entre paréntesis ('[' y ']')
Michael J Swart

5

Prueba sp_dbpermissions . Probablemente te dará más información de la que necesitas, pero hará lo que quieras.

Una vez que esté instalado, ejecute esto.

sp_dbpermissions @dbname = 'All', @LoginName = 'LoginName'

Advertencia justa en el momento en que coincide "me gusta", por lo que si otros inicios de sesión son similares y coinciden, también los verá. Por ejemplo, MyLoginy MyLoginForThisambos coincidirán MyLogin. Si eso es un problema, tengo una versión que aún no he lanzado, donde puedes desactivarla. Avísame y te lo puedo enviar por correo electrónico.


4

Aquí hay una solución de PowerShell:

import-module sqlps;

$s = new-object microsoft.sqlserver.management.smo.server '.'
foreach ($db in $s.Databases | where {$_.IsAccessible -eq $true}) {
   $u = $db.users | where {$_.Login -eq 'foobar'}
   if ($u -ne $null) { #login is mapped to a user in the db
       foreach ($role in $db.Roles) {
           if ($role.EnumMembers() -contains $u.Name) {
               $u | select parent, @{name="role";expression={$role.name}}, name
           }
       }
   }
}

4

Lamentablemente, tendrá que recorrer todas las bases de datos para obtener la información. Querrá unirse sys.database_principalsa sys.server_principalscada base de datos que coincida en el SID.

No lo use sp_msforeachdbya que se sabe que a veces pierde bases de datos.


1

Estaba buscando una respuesta similar y encontré esto: https://www.pythian.com/blog/httpconsultingblogs-emc-comjamiethomsonarchive20070209sql-server-2005_3a00_-view-all-permissions-_2800_2_2900_-aspx/ . Y sí, usa el temido sp_MSforeachDB, pero creo que ese tipo tiene una mala reputación a veces ... ;-)

Publicaré el SQL aquí para copiar y pegar fácilmente (¡ NO me estoy dando crédito por esto, solo lo hago fácilmente accesible!):

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

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

SELECT dbname, username, logintype, create_date, modify_date,
    STUFF((SELECT ',' + CONVERT(VARCHAR(500), associatedrole)
        FROM @DB_Users user2
        WHERE user1.DBName=user2.DBName AND user1.UserName=user2.UserName
        FOR XML PATH('')
    ),1,1,'') AS Permissions_user
FROM @DB_Users user1
WHERE user1.UserName = N'<put your login-name here!>'
GROUP BY dbname, username, logintype, create_date, modify_date
ORDER BY DBName, username

-1

Debajo de Consulta devolverá las asignaciones para el DbName solicitado

SELECT 'DbName', dbPri.name, dbPri1.name
FROM [DbName].sys.database_principals dbPri 
JOIN [DbName].sys.database_role_members dbRoleMem ON dbRoleMem.member_principal_id = 
dbPri.principal_id
JOIN [DbName].sys.database_principals dbPri1  ON dbPri1.principal_id = 
dbRoleMem.role_principal_id
WHERE dbPri.name != 'dbo'

La consulta mejorada está debajo

declare @sql varchar(Max)

 set @sql = 'use ? SELECT ''?'', dbPri.name, dbPri1.name
 FROM sys.database_principals dbPri 
 JOIN sys.database_role_members dbRoleMem ON 
 dbRoleMem.member_principal_id = 
 dbPri.principal_id
 JOIN sys.database_principals dbPri1  ON dbPri1.principal_id = 
 dbRoleMem.role_principal_id
 WHERE dbPri.name != ''dbo'''

 EXEC sp_MSforeachdb @sql

Gracias, el objetivo de este script fue encontrar un mapeo para todas las bases de datos. Su script proporciona información para una sola base de datos específica, no para todas.
Michael J Swart

Gracias por los comentarios, pensé que se puede repetir. Ahora actualizado con consulta mejorada
dilipkumar katre

Vea la respuesta de @ Aaron-Bertrand y comente sus pensamientos sobre sp_MSforeachdb.
Michael J Swart

-3

¿Qué hay de EXEC master..sp_msloginmappings?


¿Ha verificado sp_msloginmappingsque no está documentado y no es compatible antes de publicar?
Kin Shah
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.