Kueri yang mencantumkan semua pengguna yang dipetakan untuk login yang diberikan

19

Ketika melihat properti dari login tertentu, dimungkinkan untuk melihat daftar pengguna yang dipetakan ke login itu: masukkan deskripsi gambar di sini

Saya membuat profil SQL Server Management Studio (SSMS) dan saya melihat SSMS terhubung ke setiap database satu per satu dan mengambil informasi dari sys.database_permissions

Apakah mungkin untuk menulis satu permintaan yang mengambil informasi pemetaan pengguna yang ditunjukkan di atas atau apakah saya dipaksa untuk menggunakan kursor atau sp_MSforeachdb atau sesuatu seperti itu?

Michael J Swart
sumber
5
Tolong jangan gunakan sp_MSforeachdb .
Aaron Bertrand

Jawaban:

15

Inilah salah satu cara menggunakan SQL dinamis. Tidak ada cara apa pun untuk melakukan ini tanpa iterasi tetapi pendekatan ini jauh lebih aman daripada opsi yang tidak terdokumentasi, tidak didukung dan seperti keretasp_MSforeachdb .

Ini akan mendapatkan daftar semua database online, pengguna yang dipetakan (jika ada) bersama dengan nama skema default dan daftar peran yang dipisahkan oleh koma dari siapa mereka berada.

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
sumber
1
catatan menarik, saya harus menambahkan collations eksplisit ke kolom p.name dan p.default_schema_name agar semua dapat berfungsi dengan baik
Michael J Swart
@MichaelJSwart Ah ya, saya pernah menemukan ini sebelumnya ketika basis data memiliki susunan yang berbeda (beberapa kolom metadata menggunakan susunan server tetapi yang lain mewarisi susunan basis data). Saya berharap satu-satunya orang yang benar-benar terbakar adalah mereka yang bersikeras menggunakan karakter aneh dalam nama entitas yang hanya didukung dalam beberapa pemeriksaan yang tidak jelas ...
Aaron Bertrand
7

Script ini sedikit dimodifikasi dari script yang disebutkan di akan melakukan apa yang Anda cari. Ganti 'ThursdayClass' dengan info masuk yang Anda perlukan. 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
sumber
Terima kasih Taiob, ini bekerja dengan baik, (saya akan melampirkan kolom database_name dalam tanda kurung ('[' dan ']')
Michael J Swart
5

Coba sp_dbpermissions . Ini mungkin akan memberi Anda lebih banyak informasi daripada yang Anda butuhkan tetapi itu akan melakukan apa yang Anda inginkan.

Setelah terinstal, jalankan ini.

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

Peringatan yang adil pada saat itu cocok "seperti" jadi jika login lain mirip dan cocok maka Anda akan melihatnya juga. Misalnya MyLogindan MyLoginForThiskeduanya akan cocok MyLogin. Jika itu masalah, saya memiliki versi yang belum saya rilis di mana Anda dapat mematikannya. Beri tahu saya dan saya dapat mengirimkan email kepada Anda.

Kenneth Fisher
sumber
4

Inilah solusi 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
           }
       }
   }
}
Ben Thul
sumber
4

Sayangnya Anda harus beralih melalui semua database untuk mendapatkan informasi. Anda ingin bergabung sys.database_principalske sys.server_principalsuntuk setiap basis data yang cocok dengan SID.

Jangan gunakan sp_msforeachdbkarena diketahui sering melewatkan database.

Nic
sumber
1

Saya sedang mencari jawaban yang sama dan menemukan ini: https://www.pythian.com/blog/httpconsultingblogs-emc-comjamiethomsonarchive20070209sql-server-2005_3a00_-view-all-allmisi-_2800_2_2900_-aspx/ . Dan ya, itu menggunakan sp_MSforeachDB yang ditakuti, tapi saya pikir orang itu kadang-kadang mendapat rap yang buruk ... ;-)

Saya akan memposting SQL di sini untuk copy-paste mudah (Saya TIDAK mengambil kredit untuk ini, hanya membuatnya mudah diakses!):

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
sumber
-1

Kueri di bawah ini akan mengembalikan pemetaan untuk DbName yang diminta

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'

Kueri yang Ditingkatkan ada di bawah

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
sumber
Terima kasih, tujuan skrip ini adalah menemukan pemetaan untuk semua basis data. Skrip Anda memberikan informasi hanya untuk satu basis data tertentu, tidak semuanya.
Michael J Swart
Terima kasih atas umpan baliknya, saya pikir itu bisa diulang. Sekarang Diperbarui dengan kueri yang ditingkatkan
dilipkumar katre
Lihat jawaban dan komentar @ Aaron-Bertrand tentang pemikirannya tentang sp_MSforeachdb.
Michael J Swart
-3

Bagaimana dengan EXEC master..sp_msloginmappings?

Nacho
sumber
Apakah Anda memeriksa sp_msloginmappingstidak berdokumen dan tidak didukung sebelum memposting?
Kin Shah