Una query che elenca tutti gli utenti mappati per un determinato accesso


19

Quando si esaminano le proprietà di un determinato accesso, è possibile visualizzare un elenco di utenti associati a tale accesso: inserisci qui la descrizione dell'immagine

Ho profilato SQL Server Management Studio (SSMS) e vedo che SSMS si collega a ogni database uno alla volta e recupera le informazioni da sys.database_permissions

È possibile scrivere una singola query che recupera le informazioni di mappatura dell'utente mostrate sopra o sono costretto a usare un cursore o sp_MSforeachdb o qualcosa del genere?


Risposte:


15

Ecco un modo per utilizzare SQL dinamico. Non c'è davvero modo di farlo senza iterare ma questo approccio è molto più sicuro di opzioni non documentate, non supportate e buggy comesp_MSforeachdb .

Verrà visualizzato un elenco di tutti i database online, l'utente mappato (se esiste) insieme al nome dello schema predefinito e un elenco separato da virgole dei ruoli a cui appartengono.

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 interessante, ho dovuto aggiungere regole di confronto esplicite alle colonne p.name e p.default_schema_name affinché l'unione funzionasse correttamente
Michael J Swart,

@MichaelJSwart Ah sì, l'ho già visto prima quando i database hanno regole di confronto diverse (alcune colonne di metadati usano le regole di confronto del server ma altre ereditano le regole di confronto del database). Spero che le uniche persone che brucino davvero siano quelle che insistono nell'usare personaggi stravaganti nei nomi di entità che sono supportati solo in alcune oscure regole di confronto ...
Aaron Bertrand

7

Questo script è leggermente modificato da uno script menzionato in farà ciò che stai cercando. Sostituisci "ThursdayClass" con il login per il quale hai bisogno di informazioni. 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' 

Grazie Taiob, questo funziona bene, (racchiuderei la colonna database_name tra parentesi ('[' and ']')
Michael J Swart

5

Prova sp_dbpermissions . Probabilmente ti darà più informazioni di quelle di cui hai bisogno ma farà quello che vuoi.

Una volta installato esegui questo.

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

Un avvertimento corretto al momento fa una corrispondenza "mi piace", quindi se altri accessi sono simili e corrispondono, li vedrai anche. Ad esempio MyLogined MyLoginForThisentrambi corrisponderanno MyLogin. Se questo è un problema, ho una versione che non ho ancora rilasciato in cui è possibile disattivarlo. Fammi sapere e posso inviarti un'e-mail.


4

Ecco una soluzione 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

Sfortunatamente dovrai scorrere tutti i database per ottenere le informazioni. Ti consigliamo di unirtisys.database_principals a sys.server_principalsper ogni abbinamento database sul SID.

Non utilizzare sp_msforeachdbcome è noto a volte perdere database.


1

Stavo cercando una risposta simile e ho trovato questo: https://www.pythian.com/blog/httpconsultingblogs-emc-comjamiethomsonarchive20070209sql-server-2005_3a00_-view-all-permissions-_2800_2_2900_-aspx/ . E sì, usa il temuto sp_MSforeachDB, ma penso che quel ragazzo a volte faccia un brutto rap ... ;-)

Pubblicherò qui l'SQL per un facile copia-pasta ( NON me ne sto prendendo il merito, rendendolo facilmente accessibile!):

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

Query di seguito restituirà i mapping per il DbName richiesto

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'

Query migliorata è di seguito

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

Grazie, l'obiettivo di questo script era trovare una mappatura per tutti i database. Lo script fornisce informazioni per un solo database specifico, non tutti.
Michael J Swart,

Grazie per il feedback, ho pensato che potesse essere ripetuto. Ora aggiornato con query migliorata
dilipkumar katre

Vedi la risposta di @ Aaron-Bertrand e commenta i suoi pensieri su sp_MSforeachdb.
Michael J Swart,

-3

Che dire EXEC master..sp_msloginmappings?


Hai verificato che sp_msloginmappingsnon sia documentato e non supportato prima di pubblicare?
Kin Shah,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.