SQL Server如何正確的刪除Windows認證用戶

 

SQL Server數據庫中,有時候會創建一些Windows認證的帳號(域帳號),例如,咱們公司習慣給開發人員和Support同事開通NT帳號權限,若是有離職或負責事宜變動的話,那麼要如何正確的刪除這些Windows認證帳號呢?這篇文章就是來探討一下如何正確的刪除Windows認證帳號。以下所示:sql

 

下面這種方式,僅僅是刪除登陸名(login),然而並無刪除用戶(User)數據庫

 

USE [master]
GO
 
DROP LOGIN [xxx\xxxx]
GO

 

你刪除登陸名的時候,就會遇到相似下面的告警信息:架構

 

Deleting server logins does not delete the database users associated with the logins. To complete the process, delete the users in each database. It may be necessary to first transfer the ownership of schemas to new users.app

 

 

也就是說,雖然你刪除了登陸名,可是對應用戶數據庫或系統數據庫相關的User權限並無清理,在SQL Server中登陸名(Server Login)跟數據庫的用戶(database User)是分離開來,可是又有關聯的。因此正確的姿式: 在刪除登陸名(login)後,還必須去每一個數據庫,刪除對應的用戶(user). 在刪除登陸名前必須檢查,有那些做業的OWNER或數據庫的OWNER的爲該Windows認證帳號(NT帳號),不然後面就會遇到一些問題:spa

 

1:若是刪除Windows認證用戶前,沒有修改做業的OWNER(若是此做業的OWNER爲此Windows用戶的話,那麼刪除Windows認證用戶後,做業就會報相似下面這種錯誤。code

 

The job failed.  The owner (xx\xxx) of job syspolicy_purge_history does not have server access.orm

 

    因此在刪除Windows認證用戶前,必須檢查並修改做業的Owner,避免這種狀況出現。server

 

2:刪除Windows認證用戶前,確認是否有數據庫的OWNER爲此Windows認證用戶。不然刪除登陸名時會報錯blog

 

Msg 15174, Level 16, State 1, Line 4ip

Login 'xxx\xxxx' owns one or more database(s). Change the owner of the database(s) before dropping the login.

 

Msg 15174, Level 16, State 1, Line 4

登陸名 'xxx\xxx' 擁有一個或多個數據庫。在刪除該登陸名以前,請更改相應數據庫的全部者。

 

必須修改數據庫的Owner後(通常將數據庫的owner改成sa),才能刪除登陸名

 

sp_changedbowner 'sa'

 

 

3:有時候刪除用戶時,報下面錯誤,必須修改後,才能刪除對應的用戶。

 

 

 

遇到下面錯誤:

 

Msg 15138, Level 16, State 1, Line 3

數據庫主體在該數據庫中擁有 架構,沒法刪除。

 

Msg 15138, Level 16, State 1, Line 3

The database principal owns a schema in the database, and cannot be dropped.

 

clip_image001

 

 

USE YourSQLDba;

GO

ALTER AUTHORIZATION ON SCHEMA::[db_owner]  TO [dbo];

 

 

USE [YourSQLDba]

GO

DROP USER [xxx\konglb];

GO

 

   固然要根據實際狀況來處理

 

 

USE [UserDatabase];

GO

ALTER AUTHORIZATION ON SCHEMA::[xxx]  TO [dbo];

 

另一種是用戶建立的Schema,這個根上面狀況沒有差異。

 

 

因此正確的刪除登陸名,能夠用腳本生成對應的SQL(固然也能夠執行對應的SQL,可是這種高位操做,建議生成腳本,人工判斷後,手工執行)

 

 

 
DECLARE @login_name  sysname;
SET @login_name='GFG1\getsqldbo'
 
SELECT  d.name        AS database_name,
        owner_sid    AS owner_sid ,
        l.name        AS database_owner
FROM    sys.databases d
        LEFT JOIN sys.syslogins l ON l.sid = d.owner_sid
WHERE l.name=@login_name;
 
 
 
SELECT  'USE ' + d.name + CHAR(10) 
        + 'GO' + CHAR(10)
        + 'EXEC dbo.sp_changedbowner @loginame =N''sa'', @map = false' AS change_db_owner_cmd
FROM    sys.databases d
        LEFT JOIN sys.syslogins l ON l.sid = d.owner_sid
WHERE   l.name = @login_name;
 
 
SELECT j.job_id                                       AS JOB_ID            
      ,j.name                                         AS JOB_NAME          
      ,CASE WHEN [enabled] =1 THEN 'Enabled'
                              ELSE 'Disabled'  END    AS JOB_ENABLED    
      ,l.name                                         AS JOB_OWNER   
      ,j.category_id                                  AS JOB_CATEGORY_ID
      ,c.name                                         AS JOB_CATEGORY_NAME
      ,[description]                                  AS JOB_DESCRIPTION   
      ,date_created                                   AS DATE_CREATED      
      ,date_modified                                  AS DATE_MODIFIED
FROM msdb.dbo.sysjobs j
INNER JOIN msdb.dbo.syscategories c ON j.category_id = c.category_id
INNER JOIN sys.syslogins l ON l.sid = j.owner_sid
WHERE l.name= @login_name
ORDER BY j.name
 
 
 
DECLARE  @job_owner   NVARCHAR(32);
 
SET @job_owner='sa';
 
SELECT  'EXEC msdb.dbo.sp_update_job @job_name=N''' +j.name + ''', @owner_login_name=N''' + RTRIM(LTRIM(@job_owner)) + ''';' AS change_job_owner_cmd
FROM msdb.dbo.sysjobs j
INNER JOIN msdb.dbo.syscategories c ON j.category_id = c.category_id
INNER JOIN sys.syslogins l ON l.sid = j.owner_sid
WHERE l.name = @login_name
ORDER BY j.name
 
 
SELECT  '
USE [master]
GO
DROP LOGIN  ' + QUOTENAME(@login_name) +  
'
GO
AS  drop_login_user;

 

而後刪除用戶(User),此腳本也能夠清理那些登陸名已經刪除,可是對應的USER沒有清理的Windows 認證用戶。此腳本可能有一些邏輯上的Bug,我的也是fix掉了一些Bug後,才發佈這篇博客。若是遇到什麼Bug,能夠留言反饋。

 

DECLARE @database_id    INT;
DECLARE @database_name  sysname;
DECLARE @cmdText        NVARCHAR(MAX);
DECLARE @prc_text       NVARCHAR(MAX);
DECLARE @RowIndex       INT;
DECLARE @user_name      NVARCHAR(128);
 
 
IF OBJECT_ID('TempDB.dbo.#databases') IS NOT NULL
    DROP TABLE dbo.#databases;
 
CREATE TABLE #databases
(
    database_id        INT,
    database_name   sysname
)
 
 
INSERT  INTO #databases
SELECT  database_id ,
        name
FROM    sys.databases
WHERE   name NOT IN ( 'master', 'tempdb', 'model', 'msdb',
                        'distribution', 'ReportServer',
                        'ReportServerTempDB', 'YourSQLDba' )
        AND state = 0; --state_desc=ONLINE 
 
 
CREATE TABLE #removed_user
(
    username sysname
)
 
--開始循環每個用戶數據庫(排除了上面相關數據庫)
WHILE 1= 1
BEGIN
 
 
    SELECT TOP 1 @database_name= database_name   
    FROM #databases
    ORDER BY database_id;
 
    IF @@ROWCOUNT =0 
        BREAK;
 
 
    SET @cmdText =  'USE ' + @database_name + ';' +CHAR(10)
 
    SELECT @cmdText += 'INSERT INTO #removed_user
                        SELECT  name FROM sys.sysusers
                        WHERE sid NOT IN (SELECT sid FROM sys.syslogins WHERE isntname=1 AND name LIKE ''GFG1%'')
                          AND isntname=1 AND name NOT IN (''NT AUTHORITY\SYSTEM'')' + CHAR(10);
    
    EXEC SP_EXECUTESQL @cmdText
 
    SELECT @database_name AS database_name;
 
    SELECT j.job_id                                         AS JOB_ID            
          ,j.name                                           AS JOB_NAME          
          ,CASE WHEN [enabled] =1 THEN 'Enabled'
                                  ELSE 'Disabled'  END      AS JOB_ENABLED    
          ,l.name                                           AS JOB_OWNER   
          ,j.category_id                                    AS JOB_CATEGORY_ID
          ,c.name                                           AS JOB_CATEGORY_NAME
          ,[description]                                    AS JOB_DESCRIPTION   
          ,date_created                                     AS DATE_CREATED      
          ,date_modified                                    AS DATE_MODIFIED
    FROM msdb.dbo.sysjobs j
    INNER JOIN msdb.dbo.syscategories c ON j.category_id = c.category_id
    INNER JOIN sys.syslogins l ON l.sid = j.owner_sid
    INNER JOIN #removed_user r ON l.name = r.username
    ORDER BY j.name;
 
 
    SELECT  d.name                AS database_name ,
            l.name                AS database_owner ,
            d.create_date         AS create_date ,
            d.collation_name      AS collcation_name ,
            d.state_desc          AS state_desc
    FROM    sys.databases d
            INNER JOIN sys.syslogins l ON d.owner_sid = l.sid
            INNER JOIN #removed_user r ON r.username = l.name
 
    
    SET @cmdText =  'USE ' + @database_name + ';' +CHAR(10)
 
    SET @cmdText += 'SELECT * FROM sys.schemas  s
                        INNER JOIN  #removed_user r ON s.name =r.username Collate Database_Default' + CHAR(10);
     
    EXEC SP_EXECUTESQL @cmdText;
 
 
    SET @cmdText =  'USE ' + @database_name + ';' +CHAR(10)
 
    SET @cmdText += 'SELECT * FROM sys.objects WHERE schema_id IN (SELECT s.schema_id FROM sys.schemas s INNER JOIN  #removed_user r ON s.name =r.username Collate Database_Default);'
 
    EXEC SP_EXECUTESQL @cmdText;
 
    SET @cmdText =  'USE ' + @database_name + ';' +CHAR(10)
    SET @cmdText += 'SELECT ''USE ' + @database_name + ';'' + CHAR(10) +''GO'' + CHAR(10) +''ALTER AUTHORIZATION ON SCHEMA::'' +QUOTENAME(s.name) +''  TO [dbo];'' AS change_schema_cmd FROM sys.schemas  s
                        INNER JOIN  #removed_user r ON s.name =r.username Collate Database_Default '  + CHAR(10);
 
    EXEC SP_EXECUTESQL @cmdText, N'@database_name sysname',@database_name ;
    
    SET @cmdText =  'USE ' + @database_name + ';' +CHAR(10)
    SET @cmdText += 'SELECT  ''USE ' + @database_name + ';'' + CHAR(10) +''GO'' + CHAR(10) +''ALTER AUTHORIZATION ON SCHEMA::'' +QUOTENAME(s.SCHEMA_NAME) +''  TO [dbo];'' AS change_schema_cmd
                     FROM    INFORMATION_SCHEMA.SCHEMATA s
                     INNER JOIN  #removed_user r ON s.SCHEMA_OWNER =r.username Collate Database_Default'  + CHAR(10);
 
    EXEC SP_EXECUTESQL @cmdText, N'@database_name sysname',@database_name ;
 
    SELECT  'USE ' + QUOTENAME(@database_name) + CHAR(10)
          + 'GO '  + CHAR(10)
          + 'DROP USER ' + QUOTENAME(username) +';' + CHAR(10)
          + 'GO'  AS drop_user_cmd
    FROM #removed_user;
 
 
    TRUNCATE TABLE #removed_user;
 
 
    DELETE FROM #databases WHERE database_name=@database_name;
 
END
 
DROP TABLE  #databases;
DROP TABLE #removed_user;
相關文章
相關標籤/搜索