Eine Abfrage, die alle zugeordneten Benutzer für eine bestimmte Anmeldung auflistet

19

Wenn Sie sich die Eigenschaften eines bestimmten Logins ansehen, können Sie eine Liste der Benutzer sehen, die diesem Login zugeordnet sind: Bildbeschreibung hier eingeben

Ich habe ein Profil für SQL Server Management Studio (SSMS) erstellt und festgestellt, dass SSMS nacheinander eine Verbindung zu jeder Datenbank herstellt und Informationen aus sys.database_permissions abruft

Ist es möglich, eine einzelne Abfrage zu schreiben, die die oben gezeigten Benutzerzuordnungsinformationen abruft, oder bin ich gezwungen, einen Cursor oder sp_MSforeachdb oder ähnliches zu verwenden?

Michael J Swart
quelle
5
Bitte verwenden Sie nicht sp_MSforeachdb .
Aaron Bertrand

Antworten:

15

Hier ist eine Möglichkeit, dynamisches SQL zu verwenden. Es gibt eigentlich keine Möglichkeit, dies ohne Iteration zu tun, aber dieser Ansatz ist viel sicherer als undokumentierte, nicht unterstützte und fehlerhafte Optionen wiesp_MSforeachdb .

Daraufhin wird eine Liste aller Onlinedatenbanken, des zugeordneten Benutzers (sofern vorhanden) zusammen mit dem Standardschemanamen und einer durch Kommas getrennten Liste der Rollen, zu denen sie gehören, angezeigt.

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;
Aaron Bertrand
quelle
1
Interessanterweise musste ich den Spalten p.name und p.default_schema_name explizite Kollatierungen hinzufügen, damit die Vereinigung ordnungsgemäß funktioniert
Michael J Swart
@MichaelJSwart Ah ja, ich habe dies schon einmal erlebt, wenn Datenbanken unterschiedliche Kollatierungen aufweisen (einige Metadatenspalten verwenden die Server-Kollatierung, andere erben die Datenbank-Kollatierung). Ich hoffe, die einzigen Menschen, die jemals wirklich brennen, sind diejenigen, die darauf bestehen, verrückte Zeichen in Entitätsnamen zu verwenden, die nur in einer obskuren Zusammenstellung unterstützt werden ...
Aaron Bertrand
7

Dieses Skript wurde geringfügig von einem Skript geändert, das nach Belieben verwendet wird, um das zu tun, was Sie suchen. Ersetzen Sie 'ThursdayClass' durch das Login, für das Sie Informationen benötigen. 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' 
SqlWorldWide
quelle
Danke Taiob, das funktioniert gut (ich würde die database_name-Spalte in Klammern ('[' und ']') einschließen)
Michael J Swart
5

Versuchen Sie es mit sp_dbpermissions . Es wird Ihnen wahrscheinlich mehr Informationen geben, als Sie benötigen, aber es wird tun, was Sie wollen.

Sobald es installiert ist, führe dies aus.

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

Faire Warnung: Im Moment wird eine "Gefällt mir" -Anpassung durchgeführt. Wenn andere Anmeldungen ähnlich sind und übereinstimmen, werden sie auch angezeigt. Zum Beispiel MyLoginund MyLoginForThisbeide stimmen überein MyLogin. Wenn das ein Problem ist, habe ich eine Version, die ich noch nicht veröffentlicht habe, wo Sie das ausschalten können. Lassen Sie es mich wissen und ich kann es Ihnen per E-Mail senden.

Kenneth Fisher
quelle
4

Hier ist eine PowerShell-Lösung:

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
           }
       }
   }
}
Ben Thul
quelle
4

Leider müssen Sie alle Datenbanken durchlaufen, um die Informationen zu erhalten. Sie werden beitreten möchten , sys.database_principalsum sys.server_principalsauf der SID für jede Datenbank - Matching.

Nicht verwenden, sp_msforeachdbda es bekannt ist, dass Datenbanken manchmal fehlen.

Nic
quelle
1

Ich suchte nach einer ähnlichen Antwort und fand diese: https://www.pythian.com/blog/httpconsultingblogs-emc-comjamiethomsonarchive20070209sql-server-2005_3a00_-view-all-permissions-_2800_2_2900_-aspx/ . Und ja, es benutzt die gefürchtete sp_MSforeachDB, aber ich denke, dieser Typ bekommt manchmal einen schlechten Ruf ... ;-)

Ich werde den SQL-Code hier veröffentlichen, um einfache Copy-Pasta zu erhalten (ich nehme das NICHT an, mache es nur einfach zugänglich!):

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
NateJ
quelle
-1

Die folgende Abfrage gibt die Zuordnungen für den angeforderten Datenbanknamen zurück

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'

Eine verbesserte Abfrage finden Sie weiter unten

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
dilipkumar katre
quelle
Vielen Dank, das Ziel dieses Skripts war es, eine Zuordnung für alle Datenbanken zu finden. Ihr Skript enthält Informationen nur für eine bestimmte Datenbank, nicht für alle.
Michael J Swart
Vielen Dank für die Rückmeldung, ich dachte, es kann wiederholt werden. Jetzt mit verbesserter Abfrage aktualisiert
dilipkumar katre
Siehe @ Aaron-Bertrands Antwort und Kommentar zu seinen Gedanken zu sp_MSforeachdb.
Michael J Swart
-3

Was ist EXEC master..sp_msloginmappings?

Nacho
quelle
Haben Sie sp_msloginmappingsvor dem Posten überprüft, ob die Dokumente undokumentiert sind und nicht unterstützt werden?
Kin Shah