Dans SQL Server 2005, existe-t-il un moyen de rechercher des utilisateurs qui n'existent pas au niveau du serveur (un compte qui a été supprimé au niveau du serveur mais qui n'a pas été dissocié des bases de données avant sa suppression) ou des comptes qui ne sont pas liés (un compte peut avoir été supprimé au niveau du serveur mais pas au niveau db, puis réajouté mais le niveau db n'a jamais été nettoyé).
J'ai un serveur très en désordre et ce serait génial s'il y avait une requête à exécuter pour les trouver.
Le script suivant du site Brent Ozar Unlimited parcourt toutes les bases de données et répertorie les utilisateurs orphelins par base de données, ainsi que la commande drop pour les supprimer. Il peut y avoir une façon plus soignée/plus récente de gérer cela, mais cela semble fonctionner correctement sur 2005-2012.
DECLARE @SQL nvarchar(2000)
DECLARE @name nvarchar(128)
DECLARE @database_id int
SET NOCOUNT ON;
IF NOT EXISTS
(SELECT name FROM tempdb.sys.tables WHERE name like '%#Orphan_users%')
BEGIN
CREATE TABLE #Orphan_users
(
database_name nvarchar(128) NOT NULL,
[user_name] nvarchar(128) NOT NULL,
drop_command_text nvarchar(200) NOT NULL
)
END
CREATE TABLE #databases
(
database_id int NOT NULL
, database_name nvarchar(128) NOT NULL
, processed bit NOT NULL
)
INSERT
#databases
( database_id
, database_name
, processed )
SELECT
database_id
, name
, 0
FROM
master.sys.databases
WHERE
name NOT IN
('master'
, 'tempdb'
, 'msdb'
, 'distribution'
, 'model')
WHILE (SELECT COUNT(processed) FROM #databases WHERE processed = 0) > 0
BEGIN
SELECT TOP 1
@name = database_name,
@database_id = database_id
FROM #databases
WHERE processed = 0
ORDER BY database_id
SELECT @SQL =
'USE [' + @name + '];
INSERT INTO #Orphan_users (database_name, user_name, drop_command_text)
SELECT
DB_NAME()
, u.name
, ' + ''''
+ 'USE [' + @name + ']; '
+ 'DROP USER ['
+ '''' + ' + u.name
+ ' + '''' + '] '
+ '''' + '
FROM
master..syslogins l
RIGHT JOIN
sysusers u
ON l.sid = u.sid
WHERE
l.sid IS NULL
AND issqlrole <> 1
AND isapprole <> 1
AND ( u.name <> ' + '''' + 'INFORMATION_SCHEMA' + ''''
+ ' AND u.name <> ' + '''' + 'guest' + ''''
+ ' AND u.name <> ' + '''' + 'dbo' + ''''
+ ' AND u.name <> ' + '''' + 'sys' + ''''
+ ' AND u.name <> ' + '''' + 'system_function_schema' + '''' + ')'
PRINT @SQL;
EXEC sys.sp_executesql @SQL
UPDATE
#databases
SET
processed = 1
WHERE
database_id = @database_id;
END
SELECT
database_name
, [user_name]
, drop_command_text
FROM
#Orphan_users
ORDER BY
[database_name]
, [user_name];
DROP TABLE #databases;
DROP TABLE #Orphan_users;
SET NOCOUNT OFF;
Je voulais d'abord REMERCIER Mark pour avoir posté le script. Cela m'a fait gagner beaucoup de temps à l'écrire à partir de zéro. Je l'ai modifié un peu depuis que j'ai rencontré le problème où j'ai reçu une erreur indiquant que le "principal de la base de données possède un schéma dans la base de données et ne peut pas être supprimé". J'ai modifié le script pour générer les commandes pour l'erreur SCHEMA et également pour l'erreur de rôle si vous devez également obtenir celle-ci.
J'espère que cela aide quelqu'un là-bas ..
DECLARE @SQL nvarchar(2000)
DECLARE @name nvarchar(128)
DECLARE @database_id int
SET NOCOUNT ON;
IF NOT EXISTS
(SELECT name FROM tempdb.sys.tables WHERE name like '%#Orphan_users%')
BEGIN
CREATE TABLE #Orphan_users
(
database_name nvarchar(128) NOT NULL,
[user_name] nvarchar(128) NOT NULL,
drop_command_text nvarchar(200) NOT NULL,
drop_schema_text nvarchar(200) not null,
drop_role_text nvarchar(200) not null
)
END
CREATE TABLE #databases
(
database_id int NOT NULL
, database_name nvarchar(128) NOT NULL
, processed bit NOT NULL
)
INSERT
#databases
( database_id
, database_name
, processed )
SELECT
database_id
, name
, 0
FROM
master.sys.databases
WHERE
name NOT IN
('master'
, 'tempdb'
, 'msdb'
, 'distribution'
, 'model')
WHILE (SELECT COUNT(processed) FROM #databases WHERE processed = 0) > 0
BEGIN
SELECT TOP 1
@name = database_name,
@database_id = database_id
FROM #databases
WHERE processed = 0
ORDER BY database_id
SELECT @SQL =
'USE [' + @name + '];
INSERT INTO #Orphan_users (database_name, user_name, drop_command_text, Drop_schema_text, drop_role_text)
SELECT
DB_NAME()
, u.name
,
' + ''''
+ 'USE [' + @name + ']; '
+ 'DROP USER ['
+ '''' + ' + u.name
+ ' + '''' + '] '
+ '''' + '
,
' + '''' + 'USE [' + @name + ']; ' +
'ALTER AUTHORIZATION ON SCHEMA::['
+ '''' + ' + u.name
+ ' + '''' + '] TO [dbo]' + '''' + '
,
' + '''' + 'USE [' + @name + ']; ' +
'ALTER AUTHORIZATION ON Role::['
+ '''' + ' + u.name
+ ' + '''' + '] TO [dbo]' + '''' + '
FROM
master..syslogins l
RIGHT JOIN
sysusers u
ON l.sid = u.sid
WHERE
l.sid IS NULL
AND issqlrole <> 1
AND isapprole <> 1
AND ( u.name <> ' + '''' + 'INFORMATION_SCHEMA' + ''''
+ ' AND u.name <> ' + '''' + 'guest' + ''''
+ ' AND u.name <> ' + '''' + 'dbo' + ''''
+ ' AND u.name <> ' + '''' + 'sys' + ''''
+ ' AND u.name <> ' + '''' + 'system_function_schema' + '''' + ')'
PRINT @SQL;
EXEC sys.sp_executesql @SQL
UPDATE
#databases
SET
processed = 1
WHERE
database_id = @database_id;
END
SELECT
database_name
, [user_name]
, drop_command_text
, Drop_schema_text
, drop_role_text
FROM
#Orphan_users
ORDER BY
[database_name]
, [user_name];
DROP TABLE #databases;
DROP TABLE #Orphan_users;
SET NOCOUNT OFF;
Ce sp_change_users_login est amorti à partir de SQL 2008 mais fonctionne toujours bien. Si vous passez l'option "rapport", elle répertoriera tous les utilisateurs qui n'ont pas de connexion associée.
EXEC sp_change_users_login 'report'
Si vous souhaitez l'exécuter pour toutes vos bases de données, vous pouvez le faire comme ceci.
EXEC sp_msforeachdb 'use [?]; PRINT ''?''; EXEC sp_change_users_login ''report'';'
Si vous le recherchez dans BOL, vous trouverez également des options pour réparer les utilisateurs "orphelins".