SQL Server 登陸賬戶權限克隆 ——sp_DBA_LoginClone 升級版

《克隆 SQL Server 登陸名及權限》一文中對登陸名的克隆相對適用範圍較窄,爲更好的應用,對腳本進行了擴充和完善,具體如sp_DBA_LoginPermissionsClone。

sp_DBA_LoginPermissionsClone有兩個用途,區別主要在於第二、三個參數。@newLoginName和@loginName相同或者爲NULL時,進行的是登陸賬戶權限克隆(生成的腳本賬戶名、權限和密碼與原先登陸賬戶相同);@newLoginName非NULL且不等於@loginName時,@pwd 非NULL,則生成將原賬戶權限(@loginNam)克隆給新賬戶(@newLoginName)的腳本(賬戶名、密碼爲新的,權限和原賬戶相同)。

如下爲sp_DBA_LoginPermissionsClone具體腳本:

USE [master]
GO
/*
      功能:生成克隆帳戶權限的腳本或者將一個登陸帳戶的權限賦予另外一個登陸帳戶的腳本
      適用於SQL SERVER 2008/SQL SERVER 2008 R2/SQL SERVER 2012/SQL SERVER 2014/SQL SERVER 2016
      ***其他版本暫未測試
      注意:   1.適用於將一個登陸名的權限賦予另外一個登陸名
              2.不能克隆憑據、非對稱密鑰和證書
              3.如果一個登陸名有管理另外登陸名的權限,且所管理的登陸名也是新的,需要手動調整對應的腳本
      實例:
      1. 生成克隆帳戶權限的腳本
      DECLARE @sql VARCHAR(max)
      EXEC sp_DBA_LoginPermissionsClone [Jack],NULL,NULL,@sql OUTPUT
      SELECT @sql FOR XML PATH('')
      2. 將一個帳戶的權限賦予一個新的帳戶
      DECLARE @sql VARCHAR(max)
      EXEC sp_DBA_LoginPermissionsClone [Jack],[Jack_new],'password',@sql OUTPUT
      SELECT @sql FOR XML PATH('')
*/
CREATE PROC [dbo].[sp_DBA_LoginPermissionsClone]
    @loginName sysname
    ,@newLoginName sysname
    ,@pwd VARCHAR(25)=NULL
    ,@loginCloneSQL VARCHAR(max) OUTPUT
AS
BEGIN
      DECLARE @password_hash VARchar(256)
      DECLARE @sid VARchar(85)
      DECLARE @hasaccess int
      DECLARE @denylogin int
    DECLARE @is_disabled INT
    DECLARE @is_policy_checked VARCHAR(3)
    DECLARE @is_expiration_checked VARCHAR(3)
    DECLARE @defaultdb sysname
    DECLARE @type varchar (1)
 
      --判斷登陸名是否存在
    IF NOT EXISTS (
         SELECT 1 FROM sys.syslogins WHERE name= @loginName
       ) OR @loginName IS NULL
        BEGIN
            PRINT @loginName + ' 不存在'
            RETURN
        END
      
    IF  EXISTS (
         SELECT 1 FROM sys.syslogins WHERE name= @newLoginName
       )  AND @newLoginName<>@loginName
        BEGIN
            PRINT @newLoginName + ' 已存在'
            RETURN
        END
    IF  @newLoginName<>@loginName AND @pwd IS NULL AND @newLoginName IS NOT NULL
        BEGIN
            PRINT '請輸入密碼'
            RETURN
        END
    IF @newLoginName IS NULL
            SET @newLoginName=@loginName
      SELECT  @type = type
      FROM    sys.server_principals
      WHERE name=@loginName
      SELECT @hasaccess=hasaccess, @denylogin=denylogin
      FROM sys.syslogins
      WHERE name=@loginName
 
      SET @loginCloneSQL = 'USE master ' + CHAR(10) + 'GO ' + CHAR(10)
      --如果新帳戶和原帳戶不同,使用給定的密碼創建新帳戶
      IF @newLoginName<>@loginName
    BEGIN
            IF (@type IN ( 'G', 'U'))
            BEGIN --NT authenticated account/group
                  SELECT @defaultdb=default_database_name
                  from sys.server_principals
                  WHERE name=@loginName
              SET @loginCloneSQL =@loginCloneSQL+ 'Create LOGIN '
                  + QUOTENAME( @newLoginName,']' )
                  + ' FROM WINDOWS WITH DEFAULT_DATABASE = '
                  + QUOTENAME(@defaultdb , ']')+CHAR(10)
            END
            ELSE
            BEGIN
                  SELECT  @sid=CONVERT(VARCHAR(85),p.sid,1), @is_disabled= p.is_disabled
                        , @defaultdb=p.default_database_name
                        ,@is_policy_checked= CASE is_policy_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' end
                        ,@is_expiration_checked= CASE is_expiration_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' END
                        ,@password_hash=CONVERT(VARCHAR(256),password_hash , 1)
                  FROM    sys.sql_logins p
                  WHERE name=@loginName
                  SET @loginCloneSQL=@loginCloneSQL+' CREATE LOGIN '+QUOTENAME(@newLoginName, ']')+CHAR(10)
                        +' WITH PASSWORD='''+@pwd+'''' +CHAR(10)
                        +', DEFAULT_DATABASE = ' + QUOTENAME(@defaultdb, ']')+CHAR(10)
                  IF ( @is_policy_checked IS NOT NULL )
                        BEGIN
                          SET @loginCloneSQL = @loginCloneSQL + ', CHECK_POLICY = ' + @is_policy_checked+CHAR(10)
                        END
                  IF ( @is_expiration_checked IS NOT NULL )
                  BEGIN
                    SET @loginCloneSQL = @loginCloneSQL + ', CHECK_EXPIRATION = ' + @is_expiration_checked+CHAR(10)
                  END
            END
      END
      ELSE IF @loginName=@newLoginName
      BEGIN
            IF (@type IN ( 'G', 'U'))
            BEGIN --NT authenticated account/group
                        SELECT @defaultdb=default_database_name
                        from sys.server_principals
                        WHERE name=@loginName
              SET @loginCloneSQL =@loginCloneSQL+ 'Create LOGIN '
                        + QUOTENAME( @loginName,']' )
                        + ' FROM WINDOWS WITH DEFAULT_DATABASE = '
                        + QUOTENAME(@defaultdb , ']')+CHAR(10)
            END
            ELSE
            BEGIN
                  --PRINT '---------------'
                  SELECT  @sid=CONVERT(VARCHAR(85),p.sid,1), @is_disabled= p.is_disabled
                  , @defaultdb=p.default_database_name
                  ,@is_policy_checked= CASE is_policy_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' end
                  ,@is_expiration_checked= CASE is_expiration_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' END
                  ,@password_hash=CONVERT(VARCHAR(256),password_hash , 1)
            FROM    sys.sql_logins p
            WHERE name=@loginName
            SET @loginCloneSQL=@loginCloneSQL+' CREATE LOGIN '+QUOTENAME(@loginName, ']')+CHAR(10)
                  +' WITH PASSWORD='+@password_hash+ ' HASHED '+CHAR(10)
                  +',SID='+@sid +CHAR(10)
                  +', DEFAULT_DATABASE = ' + QUOTENAME(@defaultdb, ']')+CHAR(10)
            IF ( @is_policy_checked IS NOT NULL )
                        BEGIN
                          SET @loginCloneSQL = @loginCloneSQL + ', CHECK_POLICY = ' + @is_policy_checked+CHAR(10)
                        END
                  IF ( @is_expiration_checked IS NOT NULL )
                  BEGIN
                    SET @loginCloneSQL = @loginCloneSQL + ', CHECK_EXPIRATION = ' + @is_expiration_checked+CHAR(10)
                  END
        END
      END
      --PRINT @loginCloneSQL
      
    --IF (@denylogin = 1)
    --BEGIN --login is denied access
    --  SET @loginCloneSQL = @loginCloneSQL + ' DENY CONNECT SQL TO ' + QUOTENAME( @newLoginName )+CHAR(10)
    --END
    --ELSE IF (@hasaccess = 0)
    --BEGIN --login exists but does not have access
    --  SET @loginCloneSQL = @loginCloneSQL + ' REVOKE CONNECT SQL TO ' + QUOTENAME( @newLoginName )+CHAR(10)
    --END
    IF (@is_disabled = 1)
    BEGIN --login is disabled
      SET @loginCloneSQL = @loginCloneSQL + ' Alter LOGIN ' + QUOTENAME( @newLoginName ) + 'DISABLE' +CHAR(10)
    END
   
    DECLARE @versionNum AS INT
    SET @versionNum = SUBSTRING(@@VERSION, 22, 4)
    IF @versionNum >= 2012
        BEGIN
            SELECT  @loginCloneSQL = ISNULL(@loginCloneSQL, '')
                    + ISNULL(STUFF((SELECT      
                            CASE WHEN ISNULL(ISNULL(o.name, e.name), ag.name) IS NULL
                                      AND sp.state <> 'W'
                                 THEN sp.state_desc COLLATE Chinese_PRC_CI_AS + ' ' + sp.permission_name
                                      + ' TO ' + QUOTENAME(@newLoginName, '[') + CHAR(10)
                                 WHEN ISNULL(ISNULL(o.name, e.name), ag.name) IS NULL
                                      AND sp.state = 'W'
                                 THEN 'GRANT ' + sp.permission_name + ' TO ' + QUOTENAME(@newLoginName, '[')
                                      + ' ' + ' WITH GRANT OPTION' + CHAR(10)
                                 WHEN ISNULL(ISNULL(o.name, e.name), ag.name) IS NOT NULL
                                      AND class = 101
                                      AND sp.state <> 'W'
                                 THEN sp.state_desc COLLATE Chinese_PRC_CI_AS + ' ' + sp.permission_name
                                      + ' ON LOGIN::' + QUOTENAME(o.name, '[') + ' TO '
                                      + QUOTENAME(@newLoginName, '[') + CHAR(10)
                                 WHEN ISNULL(ISNULL(o.name, e.name), ag.name) IS NOT NULL
                                      AND class = 101
                                      AND sp.state = 'W'
                                 THEN 'GRANT ' + sp.permission_name + ' ON LOGIN::' + QUOTENAME(o.name,
                                                                                        '[') + ' TO '
                                      + QUOTENAME(@newLoginName, '[') + ' ' + ' WITH GRANT OPTION' + CHAR(10)
                                 WHEN ISNULL(ISNULL(o.name, e.name), ag.name) IS NOT NULL
                                      AND class = 105
                                      AND sp.state <> 'W'
                                 THEN sp.state_desc + ' ' + sp.permission_name + ' ON ENDPOINT::'
                                      + QUOTENAME(@newLoginName, '[') + ' TO ' + QUOTENAME(s.name, '[')
                                      + CHAR(10)
                                 WHEN ISNULL(ISNULL(o.name, e.name), ag.name) IS NOT NULL
                                      AND class = 105
                                      AND sp.state = 'W'
                                 THEN 'GRANT ' + sp.permission_name + ' ON ENDPOINT::'
                                      + QUOTENAME(e.name, '[') + ' TO ' + QUOTENAME(@newLoginName, '[') + ' '
                                      + ' WITH GRANT OPTION' + CHAR(10)
                                 WHEN ISNULL(ISNULL(o.name, e.name), ag.name) IS NOT NULL
                                      AND class = 108
                                      AND sp.state <> 'W'
                                 THEN sp.state_desc + ' ' + sp.permission_name + ' ON ENDPOINT::'
                                      + QUOTENAME(ag.name, '[') + ' TO ' + QUOTENAME(@newLoginName, '[')
                                      + CHAR(10)
                                 WHEN ISNULL(ISNULL(o.name, e.name), ag.name) IS NOT NULL
                                      AND class = 108
                                      AND sp.state = 'W'
                                 THEN 'GRANT ' + sp.permission_name + ' ON AVAILABILITY GROUP::'
                                      + QUOTENAME(ag.name, '[') + ' TO ' + QUOTENAME(@newLoginName, '[') + ' '
                                      + ' WITH GRANT OPTION' + CHAR(10)
                            END
                    FROM    sys.server_permissions sp
                    LEFT JOIN sys.server_principals p ON p.principal_id = sp.grantor_principal_id
                    LEFT JOIN sys.server_principals o ON sp.major_id = o.principal_id
                                                         AND class_desc = 'SERVER_PRINCIPAL'
                    LEFT JOIN sys.server_principals s ON s.principal_id = sp.grantee_principal_id
                    LEFT JOIN sys.endpoints e ON e.endpoint_id = sp.major_id
                                                 AND class_desc = 'ENDPOINT'
                    LEFT JOIN sys.availability_replicas ar ON ar.replica_metadata_id = sp.major_id
                                                              AND replica_metadata_id IS NOT NULL
                    LEFT JOIN sys.availability_groups ag ON ag.group_id = ar.group_id
                    WHERE   s.name = @loginName
             FOR   XML PATH('') ,
                       TYPE).value('.', 'varchar(max)'), 1, 0, ''), '')
        END
    ELSE
        BEGIN
            SELECT  @loginCloneSQL = ISNULL(@loginCloneSQL, '')
                    + ISNULL(STUFF((
                              SELECT  CASE WHEN ISNULL(o.name, e.name) IS NULL
                                  AND sp.state <> 'W'
                             THEN sp.state_desc COLLATE Chinese_PRC_CI_AS + ' ' + sp.permission_name
                                  + ' TO ' + QUOTENAME(@newLoginName, '[') + CHAR(10)
                             WHEN ISNULL(o.name, e.name) IS NULL
                                  AND sp.state = 'W'
                             THEN 'GRANT ' + sp.permission_name + ' TO ' + QUOTENAME(@newLoginName, '[')
                                  + ' WITH GRANT OPTION' + CHAR(10)
                             WHEN ISNULL(o.name, e.name) IS NOT NULL
                                  AND class = 101
                                  AND sp.state <> 'W'
                             THEN sp.state_desc COLLATE Chinese_PRC_CI_AS + ' ' + sp.permission_name
                                  + ' ON LOGIN::' + QUOTENAME(o.name, '[') + ' TO '
                                  + QUOTENAME(@newLoginName, '[') + CHAR(10)
                             WHEN ISNULL(o.name, e.name) IS NOT NULL
                                  AND class = 101
                                  AND sp.state = 'W'
                             THEN 'GRANT ' + sp.permission_name + ' ON LOGIN::'
                                                  + QUOTENAME(o.name,'[') + ' TO '
                                  + QUOTENAME(@newLoginName, '[') + ' ' + ' WITH GRANT OPTION' + CHAR(10)
                             WHEN ISNULL(o.name, e.name) IS NOT NULL
                                  AND class = 105
                                  AND sp.state <> 'W'
                             THEN sp.state_desc + ' ' + sp.permission_name + ' ON ENDPOINT::'
                                  + QUOTENAME(e.name, '[') + ' TO ' + QUOTENAME(@newLoginName, '[')
                                  + CHAR(10)
                             WHEN ISNULL(o.name, e.name) IS NOT NULL
                                  AND class = 105
                                  AND sp.state = 'W'
                             THEN 'GRANT ' + sp.permission_name + ' ON ENDPOINT::'
                                  + QUOTENAME(e.name, '[') + ' TO ' + QUOTENAME(@newLoginName, '[') + ' '
                                  + ' WITH GRANT OPTION' + CHAR(10)
                        END   
                FROM    sys.server_permissions sp
                LEFT JOIN sys.server_principals p ON p.principal_id = sp.grantor_principal_id
                LEFT JOIN sys.server_principals o ON sp.major_id = o.principal_id
                                                     AND class_desc = 'SERVER_PRINCIPAL'
                LEFT JOIN sys.server_principals s ON s.principal_id = sp.grantee_principal_id
                LEFT JOIN sys.endpoints e ON e.endpoint_id = sp.major_id
                                             AND class_desc = 'ENDPOINT'
                WHERE   s.name = @loginName
             FOR   XML PATH('') ,
                       TYPE).value('.', 'varchar(max)'), 1, 0, ''), '')
            
        END
      --登陸名所屬角色(包括用戶創建的服務器角色)
    SELECT  @loginCloneSQL = ISNULL(@loginCloneSQL, '')
            + ISNULL(STUFF((SELECT  'EXEC sp_addsrvrolemember ' + QUOTENAME(@newLoginName,'[') + ',' + role.name + CHAR(10)
                            FROM    sys.server_role_members svrm
                            JOIN    sys.server_principals AS role ON svrm.role_principal_id = role.principal_id
                            JOIN    sys.server_principals AS member ON svrm.member_principal_id = member.principal_id
                            WHERE   member.name = @loginName
                     FOR   XML PATH('') ,
                               TYPE).value('.', 'varchar(max)'), 1, 0, ''), '')
      SELECT @loginCloneSQL=@loginCloneSQL+' '
END
GO
EXECUTE sys.sp_MS_marksystemobject 'sp_DBA_LoginPermissionsClone';
GO

如果想更爲及時的獲取最新文章,可以搜索注公衆 MSQLServer,將有更多精彩。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章