Lorsque vous regardez les propriétés d'une connexion particulière, il est possible de voir une liste d'utilisateurs mappés à cette connexion:
J'ai profilé SQL Server Management Studio (SSMS) et je vois que SSMS se connecte à chaque base de données une par une et récupère les informations de sys.database_permissions
Est-il possible d'écrire une seule requête qui récupère les informations de mappage utilisateur indiquées ci-dessus ou suis-je obligé d'utiliser un curseur ou sp_MSforeachdb ou quelque chose comme ça?
Voici une façon d'utiliser le SQL dynamique. Il n'y a pas vraiment de moyen de le faire sans itérer mais cette approche est beaucoup plus sûre que options non documentées, non prises en charge et boguées comme sp_MSforeachdb
.
Cela obtiendra une liste de toutes les bases de données en ligne, l'utilisateur mappé (s'il existe) avec le nom de schéma par défaut et une liste séparée par des virgules des rôles auxquels ils appartiennent.
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;
Ce script est légèrement modifié à partir d'un script mentionné à fera ce que vous cherchez. Remplacez "ThursdayClass" par la connexion dont vous avez besoin d'informations. 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'
Essayez sp_dbpermissions . Il vous donnera probablement plus d'informations que nécessaire, mais il fera ce que vous voulez.
Une fois installé, exécutez ceci.
sp_dbpermissions @dbname = 'All', @LoginName = 'LoginName'
Juste avertissement pour le moment, il fait une correspondance "J'aime", donc si d'autres connexions sont similaires et correspondent, vous les verrez également. Par exemple, MyLogin
et MyLoginForThis
correspondront tous les deux à MyLogin
. Si c'est un problème, j'ai une version que je n'ai pas encore publiée où vous pouvez la désactiver. Faites-le moi savoir et je pourrai vous l'envoyer par email.
Malheureusement, vous allez devoir parcourir toutes les bases de données pour obtenir les informations. Vous voudrez rejoindre sys.database_principals
à sys.server_principals
pour chaque base de données correspondant au SID.
N'utilisez pas sp_msforeachdb
car on sait qu'il manque parfois des bases de données.
Voici une solution 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
}
}
}
}
Je cherchais une réponse similaire et j'ai trouvé ceci: https://www.pythian.com/blog/httpconsultingblogs-emc-comjamiethomsonarchive20070209sql-server-2005_3a00_-view-all-permissions-_2800_2_2900_-aspx/ . Et oui, il utilise le redouté sp_MSforeachDB, mais je pense que ce gars obtient parfois un mauvais rap ... ;-)
Je publierai le SQL ici pour des pâtes de copie faciles (je suis [~ # ~] pas [~ # ~] en prenant le crédit pour cela, juste le rendant facilement accessible!):
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