แบบสอบถามที่แสดงผู้ใช้ที่แมปทั้งหมดสำหรับการเข้าสู่ระบบที่กำหนด


19

เมื่อดูคุณสมบัติของการเข้าสู่ระบบโดยเฉพาะเป็นไปได้ที่จะเห็นรายการผู้ใช้ที่แมปเข้าสู่การเข้าสู่ระบบนั้น: ป้อนคำอธิบายรูปภาพที่นี่

ฉันทำโปรไฟล์ SQL Server Management Studio (SSMS) และฉันเห็นว่า SSMS เชื่อมต่อกับฐานข้อมูลทุกรายการทีละรายการและดึงข้อมูลจาก sys.database_permissions

เป็นไปได้ไหมที่จะเขียนเคียวรีเดี่ยวที่ดึงข้อมูลการแม็พผู้ใช้ที่แสดงด้านบนหรือฉันถูกบังคับให้ใช้เคอร์เซอร์หรือ sp_MSforeachdb หรืออะไรทำนองนั้น


5
กรุณาอย่าใช้ sp_MSforeachdb
Aaron Bertrand

คำตอบ:


15

นี่เป็นวิธีหนึ่งในการใช้ SQL แบบไดนามิก ไม่มีวิธีใดที่จะทำได้โดยไม่ต้องทำซ้ำ แต่วิธีนี้ปลอดภัยกว่าตัวเลือกที่ไม่ได้รับการสนับสนุนและบั๊กกี้อย่างsp_MSforeachdbปลอดภัย

สิ่งนี้จะได้รับรายชื่อของฐานข้อมูลออนไลน์ทั้งหมดผู้ใช้ที่ถูกแมป (ถ้ามี) พร้อมกับชื่อสคีมาเริ่มต้นและรายการที่คั่นด้วยเครื่องหมายจุลภาคของบทบาทที่เป็นของพวกเขา

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
บันทึกที่น่าสนใจฉันต้องเพิ่มการเรียงที่ชัดเจนไปยังคอลัมน์ p.name และ p.default_schema_name เพื่อให้ทุกสหภาพทำงานได้อย่างถูกต้อง
Michael J Swart

@MichaelJS ออกอาใช่ฉันเคยเจอเรื่องนี้มาก่อนเมื่อฐานข้อมูลมีการเปรียบเทียบที่แตกต่างกัน (คอลัมน์เมทาดาทาบางคอลัมน์ใช้การเปรียบเทียบเซิร์ฟเวอร์ แต่คนอื่นสืบทอดการเปรียบเทียบฐานข้อมูล) ฉันหวังว่าคนเดียวที่เคยถูกเผาไหม้จริงๆคือคนที่ยืนกรานที่จะใช้ตัวละครที่แปลกประหลาดในชื่อเอนทิตีที่ได้รับการสนับสนุนในการเปรียบเทียบที่คลุมเครือบางอย่างเท่านั้น ...
Aaron Bertrand

7

สคริปต์นี้ได้รับการแก้ไขเล็กน้อยจากสคริปต์ที่กล่าวถึงจะทำสิ่งที่คุณกำลังมองหา แทนที่ 'ThursdayClass' ด้วยชื่อเข้าสู่ระบบที่คุณต้องการข้อมูล 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' 

ขอบคุณ Taiob สิ่งนี้ใช้ได้ดี (ฉันจะใส่คอลัมน์ database_name ไว้ในวงเล็บ ('[' และ ']'))
Michael J Swart

5

ลองsp_dbpermissions มันอาจจะให้ข้อมูลมากกว่าที่คุณต้องการ แต่มันจะทำสิ่งที่คุณต้องการ

เมื่อติดตั้งแล้วให้รันสิ่งนี้

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

คำเตือนที่เป็นธรรมในขณะนี้มันจับคู่ "ชอบ" ดังนั้นหากการเข้าสู่ระบบอื่น ๆ ที่คล้ายกันและตรงกับแล้วคุณจะเห็นพวกเขายัง ตัวอย่างMyLoginและทั้งสองจะตรงกับในMyLoginForThis MyLoginหากเป็นปัญหาฉันมีรุ่นที่ฉันยังไม่ได้วางจำหน่ายซึ่งคุณสามารถปิดได้ แจ้งให้เราทราบและฉันสามารถส่งอีเมลถึงคุณ


4

นี่คือโซลูชั่นของ 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

น่าเศร้าที่คุณจะต้องวนซ้ำฐานข้อมูลทั้งหมดเพื่อรับข้อมูล คุณจะต้องการที่จะเข้าร่วมsys.database_principalsการsys.server_principalsสำหรับแต่ละตรงกับฐานข้อมูลที่ SID

อย่าใช้sp_msforeachdbเนื่องจากเป็นที่ทราบกันดีว่าพลาดฐานข้อมูลตลอดเวลา


1

ฉันกำลังมองหาคำตอบที่คล้ายกันและพบนี้: https://www.pythian.com/blog/httpconsultingblogs-emc-comjamiethomsonarchive20070209sql-server-2005_3a00_-view-all-permissions-_2800_2_2900_-aspx/ และใช่มันใช้ sp_MSforeachDB ที่หวั่น แต่ฉันคิดว่าผู้ชายคนนั้นแร็พไม่ดีในบางครั้ง ... ;-)

ฉันจะโพสต์ SQL ที่นี่เพื่อให้ง่ายต่อการคัดลอกพาสต้า (ฉันไม่ได้รับเครดิตสำหรับสิ่งนี้เพียงทำให้เข้าถึงได้ง่าย!):

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

ด้านล่างแบบสอบถามจะส่งคืนการแมปสำหรับ DbName ที่ร้องขอ

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'

ข้อความค้นหาที่ปรับปรุงแล้วอยู่ด้านล่าง

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

ขอบคุณเป้าหมายของสคริปต์นี้คือการค้นหาแผนที่สำหรับฐานข้อมูลทั้งหมด สคริปต์ของคุณให้ข้อมูลสำหรับฐานข้อมูลเฉพาะเพียงแห่งเดียวไม่ใช่ทั้งหมด
Michael J Swart

ขอบคุณสำหรับข้อเสนอแนะฉันคิดว่ามันสามารถทำซ้ำได้ อัปเดตตอนนี้ด้วยข้อความค้นหาที่ปรับปรุงแล้ว
dilipkumar katre

ดูคำตอบและความคิดเห็นของ @ Aaron-Bertrand เกี่ยวกับความคิดของเขาเกี่ยวกับ sp_MSforeachdb
Michael J Swart

-3

เกี่ยวกับEXEC master..sp_msloginmappingsอะไร


คุณตรวจสอบsp_msloginmappingsว่าไม่มีเอกสารและไม่สนับสนุนก่อนโพสต์หรือไม่
Kin Shah
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.