在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.
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;