Encuentra usuarios huérfanos

12

En SQL Server 2005, ¿hay alguna manera de encontrar usuarios que no existan a nivel de servidor (una cuenta que se eliminó a nivel de servidor pero que no se desasoció de las bases de datos antes de eliminarse) o cuentas que no están vinculadas (es posible que se haya eliminado una cuenta en el nivel del servidor pero no en el nivel de base de datos, luego se haya vuelto a leer, pero el nivel de base de datos nunca se limpió).

Tengo un servidor muy desordenado y sería increíble si hubiera una consulta para encontrarlos.

DForck42
fuente

Respuestas:

15

El siguiente script del sitio Brent Ozar Unlimited recorre en iteración todas las bases de datos y enumera a los usuarios huérfanos por base de datos, junto con el comando soltar para eliminarlos. Puede haber una forma más ordenada / nueva de manejar esto, pero parece funcionar correctamente en 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;
Mark Storey-Smith
fuente
4

Primero quería agradecer a Mark por publicar el guión. Me ahorró un montón de tiempo escribirlo desde cero. Lo modifiqué un poco ya que me encontré con el problema en el que recibí un error que indica que el "principal de la base de datos posee un esquema en la base de datos y no se puede descartar". Modifiqué el script para generar los comandos para el error SCHEMA y también para el error Role si usted también debe obtener ese.

Espero que esto ayude a alguien por ahí ...

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;
dbafollower
fuente
3

Este sp_change_users_login se deprecia a partir de SQL 2008, pero aún funciona bien. Si pasa la opción 'informe', se enumerará a todos los usuarios que no tienen un inicio de sesión asociado.

EXEC sp_change_users_login 'report'

Si desea ejecutarlo para todas sus bases de datos, puede hacerlo así.

EXEC sp_msforeachdb 'use [?]; PRINT ''?''; EXEC sp_change_users_login ''report'';'

Si lo busca en BOL, también encontrará opciones para reparar usuarios "huérfanos".

Kenneth Fisher
fuente