Scripting SQL Server permissions

前端 未结 9 1950
轮回少年
轮回少年 2021-01-30 02:58

I want to copy all the permission I\'ve set on stored procedures and other stuff from my development database to my production database. It\'s incredibly cumbersome, not to ment

相关标签:
9条回答
  • 2021-01-30 03:52
    SELECT
        dp.state_desc + ' ' 
           + dp.permission_name collate latin1_general_cs_as
           + ISNULL((' ON ' + QUOTENAME(s.name) + '.' + QUOTENAME(o.name)),'')
           + ' TO ' + QUOTENAME(dpr.name)
    FROM sys.database_permissions AS dp
      LEFT JOIN sys.objects AS o ON dp.major_id=o.object_id
      LEFT JOIN sys.schemas AS s ON o.schema_id = s.schema_id
      LEFT JOIN sys.database_principals AS dpr ON dp.grantee_principal_id=dpr.principal_id
    WHERE dpr.name NOT IN ('public','guest')
    

    Slight change of the accepted answer if you want to grab permissions that are applied at database level in addition to object level. Basically switch to LEFT JOIN and make sure to handle NULL for object and schema names.

    0 讨论(0)
  • 2021-01-30 03:53

    The database's built-in catalog views provide the information to do this. Try this query:

    SELECT
      (
        dp.state_desc + ' ' +
        dp.permission_name collate latin1_general_cs_as + 
        ' ON ' + '[' + s.name + ']' + '.' + '[' + o.name + ']' +
        ' TO ' + '[' + dpr.name + ']'
      ) AS GRANT_STMT
    FROM sys.database_permissions AS dp
      INNER JOIN sys.objects AS o ON dp.major_id=o.object_id
      INNER JOIN sys.schemas AS s ON o.schema_id = s.schema_id
      INNER JOIN sys.database_principals AS dpr ON dp.grantee_principal_id=dpr.principal_id
    WHERE dpr.name NOT IN ('public','guest')
    --  AND o.name IN ('My_Procedure')      -- Uncomment to filter to specific object(s)
    --  AND dp.permission_name='EXECUTE'    -- Uncomment to filter to just the EXECUTEs
    

    This will spit out a bunch of commands (GRANT/DENY) for each of the permissions in the database. From this, you can copy-and-paste them into another query window and execute, to generate the same permissions that were in place on the original. For example:

    GRANT EXECUTE ON [Exposed].[EmployeePunchoutReservationRetrieve] TO [CustomerAgentRole]
    GRANT EXECUTE ON [Exposed].[EmployeePunchoutReservationStore] TO [CustomerAgentRole]
    GRANT EXECUTE ON [Exposed].[EmployeePunchoutSendOrderLogStore] TO [CustomerAgentRole]
    GRANT EXECUTE ON [Exposed].[EmployeeReportSubscriptions] TO [CustomerAgentRole]
    

    Note the bottom line, commented out, that's filtering on permission_name. Un-commenting that line will cause the query to only spit out the EXECUTE permissions (i.e., those for stored procedures).

    0 讨论(0)
  • 2021-01-30 03:58

    Our version:

    SET NOCOUNT ON
    
    DECLARE @message NVARCHAR(MAX)
    
    -- GENERATE LOGINS CREATE SCRIPT
    
    
    USE [master]
    
    -- creating accessory procedure
    
    IF EXISTS (SELECT 1 FROM    sys.objects WHERE   object_id = OBJECT_ID(N'sp_hexadecimal') AND type IN ( N'P', N'PC' )) 
    DROP PROCEDURE [dbo].[sp_hexadecimal]
    EXEC('
    CREATE PROCEDURE [dbo].[sp_hexadecimal]
        @binvalue varbinary(256),
        @hexvalue varchar (514) OUTPUT
    AS
    DECLARE @charvalue varchar (514)
    DECLARE @i int
    DECLARE @length int
    DECLARE @hexstring char(16)
    SELECT @charvalue = ''0x''
    SELECT @i = 1
    SELECT @length = DATALENGTH (@binvalue)
    SELECT @hexstring = ''0123456789ABCDEF''
    WHILE (@i <= @length)
    BEGIN
      DECLARE @tempint int
      DECLARE @firstint int
      DECLARE @secondint int
      SELECT @tempint = CONVERT(int, SUBSTRING(@binvalue,@i,1))
      SELECT @firstint = FLOOR(@tempint/16)
      SELECT @secondint = @tempint - (@firstint*16)
      SELECT @charvalue = @charvalue +
        SUBSTRING(@hexstring, @firstint+1, 1) +
        SUBSTRING(@hexstring, @secondint+1, 1)
      SELECT @i = @i + 1
    END
    
    SELECT @hexvalue = @charvalue')
    
    SET @message = '-- CREATE LOGINS' + CHAR(13) + CHAR(13) +'USE [master]' + CHAR(13)
    
    DECLARE @name sysname
    DECLARE @type varchar (1)
    DECLARE @hasaccess int
    DECLARE @denylogin int
    DECLARE @is_disabled int
    DECLARE @PWD_varbinary  varbinary (256)
    DECLARE @PWD_string  varchar (514)
    DECLARE @SID_varbinary varbinary (85)
    DECLARE @SID_string varchar (514)
    DECLARE @tmpstr  NVARCHAR(MAX)
    DECLARE @is_policy_checked varchar (3)
    DECLARE @is_expiration_checked varchar (3)
    
    DECLARE @defaultdb sysname
    
    DECLARE login_curs CURSOR FOR
          SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin FROM 
    sys.server_principals p LEFT JOIN sys.syslogins l
          ON ( l.name = p.name ) WHERE p.type IN ( 'S', 'G', 'U' ) AND p.name <> 'sa'
    
    OPEN login_curs
    
    FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin
    IF (@@fetch_status = -1)
    BEGIN
      PRINT 'No login(s) found.'
      CLOSE login_curs
      DEALLOCATE login_curs
    END
    
    WHILE (@@fetch_status <> -1)
    BEGIN
      IF (@@fetch_status <> -2)
      BEGIN
    
        IF (@type IN ( 'G', 'U'))
        BEGIN -- NT authenticated account/group
    
          SET @tmpstr = 'IF NOT EXISTS (SELECT loginname FROM master.dbo.syslogins WHERE name = ''' + @name + ''' AND dbname = ''' + @defaultdb + ''')' + CHAR(13) +
                        'BEGIN TRY' + CHAR(13) +
                        '   CREATE LOGIN ' + QUOTENAME( @name ) + ' FROM WINDOWS WITH DEFAULT_DATABASE = [' + @defaultdb + ']'
    
        END
        ELSE BEGIN -- SQL Server authentication
            -- obtain password and sid
                SET @PWD_varbinary = CAST( LOGINPROPERTY( @name, 'PasswordHash' ) AS varbinary (256) )
            EXEC sp_hexadecimal @PWD_varbinary, @PWD_string OUT
            EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT
    
            -- obtain password policy state
            SELECT @is_policy_checked = CASE is_policy_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' ELSE NULL END FROM sys.sql_logins WHERE name = @name
            SELECT @is_expiration_checked = CASE is_expiration_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' ELSE NULL END FROM sys.sql_logins WHERE name = @name
    
                SET @tmpstr = 'IF NOT EXISTS (SELECT loginname FROM master.dbo.syslogins WHERE name = ''' + @name + ''' AND dbname = ''' + @defaultdb + ''')' + CHAR(13) +
                        'BEGIN TRY' + CHAR(13) +
                        '   CREATE LOGIN ' + QUOTENAME( @name ) + ' WITH PASSWORD = ' + @PWD_string + ' HASHED, SID = ' + @SID_string + ', DEFAULT_DATABASE = [' + @defaultdb + ']'
    
            IF ( @is_policy_checked IS NOT NULL )
            BEGIN
              SET @tmpstr = @tmpstr + ', CHECK_POLICY = ' + @is_policy_checked
            END
            IF ( @is_expiration_checked IS NOT NULL )
            BEGIN
              SET @tmpstr = @tmpstr + ', CHECK_EXPIRATION = ' + @is_expiration_checked
            END
        END
        IF (@denylogin = 1)
        BEGIN -- login is denied access
          SET @tmpstr = @tmpstr + '; DENY CONNECT SQL TO ' + QUOTENAME( @name )
        END
        ELSE IF (@hasaccess = 0)
        BEGIN -- login exists but does not have access
          SET @tmpstr = @tmpstr + '; REVOKE CONNECT SQL TO ' + QUOTENAME( @name )
        END
        IF (@is_disabled = 1)
        BEGIN -- login is disabled
          SET @tmpstr = @tmpstr + '; ALTER LOGIN ' + QUOTENAME( @name ) + ' DISABLE'
        END
    
        SET @tmpstr = @tmpstr + CHAR(13) + 'END TRY' + CHAR(13) + 'BEGIN CATCH' + CHAR(13) + 'END CATCH'
    
        SET @message = @message + CHAR(13) + @tmpstr
    
      END
    
      FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin
       END
    CLOSE login_curs
    DEALLOCATE login_curs
    
    --removing accessory procedure
    
    DROP PROCEDURE [dbo].[sp_hexadecimal]
    
    
    -- GENERATE SERVER PERMISSIONS
    USE [master]
    
    DECLARE @ServerPrincipal SYSNAME
    DECLARE @PrincipalType SYSNAME 
    DECLARE @PermissionName SYSNAME
    DECLARE @StateDesc SYSNAME
    
    SET @message = @message + CHAR(13) + CHAR(13) + '-- CREATE SERVER PERMISSIONS' + CHAR(13) + CHAR(13) +'USE [master]' + CHAR(13)
    
    DECLARE server_permissions_curs CURSOR FOR
    SELECT
      [srvprin].[name] [server_principal], 
      [srvprin].[type_desc] [principal_type], 
      [srvperm].[permission_name], 
      [srvperm].[state_desc]  
    FROM [sys].[server_permissions] srvperm 
      INNER JOIN [sys].[server_principals] srvprin 
        ON [srvperm].[grantee_principal_id] = [srvprin].[principal_id] 
    WHERE [srvprin].[type] IN ('S', 'U', 'G') AND [srvprin].name NOT IN ('sa', 'dbo', 'information_schema', 'sys')
    ORDER BY [server_principal], [permission_name]; 
    
    OPEN server_permissions_curs
    
    FETCH NEXT FROM server_permissions_curs INTO @ServerPrincipal, @PrincipalType, @PermissionName, @StateDesc 
    
    WHILE (@@fetch_status <> -1)
    BEGIN
    
        SET @message = @message + CHAR(13) + 'BEGIN TRY' + CHAR(13) + 
                        @StateDesc + N' ' + @PermissionName + N' TO ' + QUOTENAME(@ServerPrincipal) + 
                        + CHAR(13) + 'END TRY' + CHAR(13) + 'BEGIN CATCH' + CHAR(13) + 'END CATCH'
    
        FETCH NEXT FROM server_permissions_curs INTO @ServerPrincipal, @PrincipalType, @PermissionName, @StateDesc 
    END
    CLOSE server_permissions_curs
    DEALLOCATE server_permissions_curs
    
    --GENERATE USERS AND PERMISSION SCRIPT FOR EVERY DATABASE
    
    SET @message = @message + CHAR(13) + CHAR(13) + N'--ENUMERATE DATABASES'
    
    DECLARE @databases TABLE (
        DatabaseName SYSNAME,
        DatabaseSize INT,
        Remarks SYSNAME NULL
    )
    
    INSERT INTO
    @databases EXEC sp_databases
    
    DECLARE @DatabaseName SYSNAME
    
    
    DECLARE database_curs CURSOR FOR
    SELECT DatabaseName FROM @databases WHERE DatabaseName IN (N'${DatabaseName}')
    
    OPEN database_curs
    
    FETCH NEXT FROM database_curs INTO @DatabaseName
    WHILE (@@fetch_status <> -1)
    BEGIN
    
        SET @tmpStr = 
    
        N'USE ' + QUOTENAME(@DatabaseName) + '
    
        DECLARE @tmpstr  NVARCHAR(MAX)
    
        SET @messageOut = CHAR(13) + CHAR(13) + ''USE ' + QUOTENAME(@DatabaseName) + ''' + CHAR(13)
    
        -- GENERATE USERS SCRIPT 
    
        SET @messageOut = @messageOut + CHAR(13) + ''-- CREATE USERS '' + CHAR(13)
    
        DECLARE @users TABLE (
        UserName SYSNAME Null,  
        RoleName SYSNAME Null,  
        LoginName SYSNAME Null, 
        DefDBName SYSNAME Null, 
        DefSchemaName SYSNAME Null, 
        UserID INT Null,    
        [SID] varbinary(85) Null
        )
    
        INSERT INTO
        @users   EXEC sp_helpuser
    
        DECLARE @UserName SYSNAME
        DECLARE @LoginName SYSNAME 
        DECLARE @DefSchemaName SYSNAME
    
        DECLARE user_curs CURSOR FOR
        SELECT UserName, LoginName, DefSchemaName FROM @users
    
        OPEN user_curs
    
        FETCH NEXT FROM user_curs INTO @UserName, @LoginName, @DefSchemaName
        WHILE (@@fetch_status <> -1)
        BEGIN
    
            SET @messageOut = @messageOut + CHAR(13) + 
                            ''IF NOT EXISTS (SELECT * FROM sys.database_principals WHERE name = N''''''+ @UserName +'''''')''
                            + CHAR(13) + ''BEGIN TRY'' + CHAR(13) + 
                            ''  CREATE USER '' + QUOTENAME(@UserName)
    
            IF (@LoginName IS NOT NULL)
                SET @messageOut = @messageOut + '' FOR LOGIN '' + QUOTENAME(@LoginName)
            ELSE
                SET @messageOut = @messageOut + '' WITHOUT LOGIN''  
    
            IF (@DefSchemaName IS NOT NULL)
                SET @messageOut = @messageOut + '' WITH DEFAULT_SCHEMA = ''  + QUOTENAME(@DefSchemaName)
    
            SET @messageOut = @messageOut + CHAR(13) + ''END TRY'' + CHAR(13) + ''BEGIN CATCH'' + CHAR(13) + ''END CATCH''
    
            FETCH NEXT FROM user_curs INTO @UserName, @LoginName, @DefSchemaName
        END
        CLOSE user_curs
        DEALLOCATE user_curs
    
        -- GENERATE ROLES
    
        SET @messageOut = @messageOut + CHAR(13) + CHAR(13) + ''-- CREATE ROLES '' + CHAR(13)
    
        SELECT @messageOut = @messageOut + CHAR(13) + ''BEGIN TRY'' + CHAR(13) + 
                            N''EXEC sp_addrolemember N''''''+ rp.name +'''''', N''''''+ mp.name +''''''''
                            + CHAR(13) + ''END TRY'' + CHAR(13) + ''BEGIN CATCH'' + CHAR(13) + ''END CATCH''
        FROM sys.database_role_members drm
        join sys.database_principals rp ON (drm.role_principal_id = rp.principal_id)
        join sys.database_principals mp ON (drm.member_principal_id = mp.principal_id)
        WHERE mp.name NOT IN (N''dbo'')
    
    
        -- GENERATE PERMISSIONS
    
        SET @messageOut = @messageOut + CHAR(13) + CHAR(13) + ''-- CREATE PERMISSIONS '' + CHAR(13)
    
        SELECT @messageOut = @messageOut + CHAR(13) + ''BEGIN TRY'' + CHAR(13) + 
                            ''  GRANT '' + dp.permission_name collate latin1_general_cs_as +
                            '' ON '' + QUOTENAME(s.name) + ''.'' + QUOTENAME(o.name) + '' TO '' + QUOTENAME(dpr.name)  +
                            + CHAR(13) + ''END TRY'' + CHAR(13) + ''BEGIN CATCH'' + CHAR(13) + ''END CATCH''
        FROM sys.database_permissions AS dp
        INNER JOIN sys.objects AS o ON dp.major_id=o.object_id
        INNER JOIN sys.schemas AS s ON o.schema_id = s.schema_id
        INNER JOIN sys.database_principals AS dpr ON dp.grantee_principal_id=dpr.principal_id
        WHERE dpr.name NOT IN (''public'',''guest'')'
    
        EXECUTE sp_executesql @tmpStr, N'@messageOut NVARCHAR(MAX) OUTPUT', @messageOut = @tmpstr OUTPUT
    
        SET @message = @message + @tmpStr
    
        FETCH NEXT FROM database_curs INTO @DatabaseName
    END
    CLOSE database_curs
    DEALLOCATE database_curs
    
    SELECT @message
    
    0 讨论(0)
提交回复
热议问题