Today, I would like to share a script, which is helpful to create a clone of an existing database user, with all of its rights/permissions and securables. This script was originally written by GREG LARSEN for SQL Server 2000, I just made necessary changes so it can be used for SQL Server 2008.
(To Copy this script, first past in MS Word document file and then copy to SQL Server)
(To Copy this script, first past in MS Word document file and then copy to SQL Server)
CREATE PROCEDURE USP_GEN_USER_RIGHTS_BASED_ON_EXISTING_LOGIN@OLDLOGIN VARCHAR(200), -- EXISTING LOGIN NAME (COPY FROM)@NEWLOGIN VARCHAR(200), -- NEW LOGIN NAME (COPY TO)@NEWUSER VARCHAR(128), -- NEW USER NAME@PASSWORD VARCHAR(200) = '', -- PASSWORD FOR SQL SERVER AUTHENTICATED USERS@CREATE_SCRIPT_ONLY BIT = 1 -- 1 IF TO GET ONLY TSQL SCRIPT, 0 IF WANT TO CREATE USER DIRECTLYAS --DECLARE @INDX INTSET NOCOUNT ONDECLARE @TEXT CHAR(100)DECLARE @CNT INTDECLARE @CMD NVARCHAR(200)DECLARE @DB NVARCHAR(128)DECLARE @OLDUSER VARCHAR(100)-- Temp Table to hold generated commandsCREATE TABLE #TMP_LOGIN_RIGHTS ( RIGHTS_TEXT VARCHAR(MAX) )------------------------------------------------------------------------------- Check if given OldLogin existsSELECT @CNT = COUNT(*)FROM [MASTER].[DBO].[SYSLOGINS]WHERE LOGINNAME = @OLDLOGINIF @CNT = 0BEGINRAISERROR ( '@OLDLOGIN IS NOT A VALID USER OF SQL SERVER', 16, 1 )RETURNEND-- Check if given NewUser allready exists on serverSELECT @CNT = COUNT(*)FROM [MASTER].[DBO].[SYSLOGINS]WHERE LOGINNAME = @NEWLOGIN---- IF @NEWLOGIN EXIST ABORTIF @CNT > 0BEGINRAISERROR ( '@NEWLOGIN ALREADY EXISTS ON SQL SERVER', 16, 1 )RETURNEND-- IF @NEWLOGIN CONTAINS '\' THEN NT LOGINSELECT @INDX = CHARINDEX('\', @NEWLOGIN)IF @INDX > 0-- GENERATE COMMANDS TO ADD NT USERINSERT INTO #TMP_LOGIN_RIGHTSSELECT 'EXECUTE [MASTER].[DBO].[SP_GRANTLOGIN] ''' + @NEWLOGIN+ '''' + CHAR(13)+ 'EXECUTE [MASTER].[DBO].[SP_DEFAULTDB] '''+ @NEWLOGIN + ''',''' + RTRIM(DBNAME) + '''' AS RIGHTS_TEXTFROM [MASTER].[DBO].[SYSLOGINS]WHERE LOGINNAME = @OLDLOGINELSEBEGINIF @PASSWORD = ''BEGINRAISERROR ( '@PASSWORD MUST BE SPECIFIED FOR SQL SERVER AUTHENTICATION',16, 1 )RETURNEND ---- GENERATE COMMANDS TO ADD SQL SERVER AUTHENTICATION USERINSERT INTO #TMP_LOGIN_RIGHTSSELECT 'EXECUTE [MASTER].[DBO].[SP_ADDLOGIN] '''+ @NEWLOGIN + ''',''' + @PASSWORD + '''' + CHAR(13)+ 'EXECUTE [MASTER].[DBO].[SP_DEFAULTDB] '''+ @NEWLOGIN + ''',''' + RTRIM(DBNAME) + '''' AS RIGHTS_TEXTFROM [MASTER].[DBO].[SYSLOGINS]WHERE LOGINNAME = @OLDLOGINEND-------------------------------------------------------------------------------SET NOCOUNT ONSET @CMD = '[MASTER].[DBO].[SP_HELPUSER]'-- GET THE NAME OF ALL DATABASESDECLARE ALLDATABASES CURSORFOR SELECT NAMEFROM [MASTER].[DBO].[SYSDATABASES]OPEN ALLDATABASESFETCH NEXT FROM ALLDATABASES INTO @DB-- CREATE TABLE TO HOLD LIST OF USERS IN CURRENT DATABASECREATE TABLE #TMPUSERS(USERNAME VARCHAR(100),GROUPNAME VARCHAR(100),LOGINNAME VARCHAR(100),DEFDBNAME VARCHAR(100),USERID CHAR(10),SCHEMANAME VARCHAR(100),SUSERID SMALLINT)WHILE ( @@FETCH_STATUS = 0 )BEGIN-- COMMAND TO RETURN ALL USERS IN DATABASESET @CMD = '[' + @DB + ']' + '.[DBO].[SP_HELPUSER]'-- GET ALL USERS IN DATABASE INTO TEMPORARY TABLEINSERT INTO #TMPUSERS (USERNAME,GROUPNAME,LOGINNAME,DEFDBNAME,USERID,SCHEMANAME,SUSERID)EXEC ( @CMD)-- DETERMINE WHETHER OLD USER IS IN DATABASESELECT @CNT = COUNT(*)FROM #TMPUSERSWHERE LOGINNAME = @OLDLOGIN-- IF OLD USER IS IN DATABASE THEN ADD NEW USER TO DATABASEIF @CNT > 0BEGIN-- DETERMINE IF @NEWUSER ALREADY EXIST IN DATABASESELECT @CNT = COUNT(*)FROM #TMPUSERSWHERE USERNAME = @NEWUSER-- IF USER EXIST ABORTIF @CNT > 0BEGIN-- CLOSE AND DEALLOCATE CURSOR OF DATABASES SO NEXT TIME AROUND NO ERROR OCCURSCLOSE ALLDATABASESDEALLOCATE ALLDATABASES-- SET TEXT OF ERROR MESSAGESET @TEXT = '@NEWUSER ALREADY EXIST IN DATABASE '+ @DB-- RAISE ERROR AND RETURNRAISERROR ( @TEXT, 16, 1 )RETURNEND-- GENERATE COMMAND TO ADD @NEWLOGIN TO CURRENT DATABASEINSERT INTO #TMP_LOGIN_RIGHTSSELECT 'EXECUTE [' + @DB+ '].[DBO].[SP_GRANTDBACCESS] '''+ @NEWLOGIN + ''',''' + RTRIM(@NEWUSER)+ '''' AS RIGHTS_TEXTFROM ( SELECT DISTINCTUSERNAME,LOGINNAMEFROM #TMPUSERSWHERE LOGINNAME = @OLDLOGIN) AEND-- TRUNCATE TABLE FOR NEXT DATABASETRUNCATE TABLE #TMPUSERS-- GET NEXT DATABASEFETCH NEXT FROM ALLDATABASES INTO @DBEND -- WHILE (@@FETCH_STATUS = 0)-- CLOSE CURSOR OF DATABASESCLOSE ALLDATABASES--------------------------------------------------------------------------------OPEN ALLDATABASESFETCH NEXT FROM ALLDATABASES INTO @DBWHILE ( @@FETCH_STATUS = 0 )BEGIN-- SET COMMAND TO FIND USER PERMISSIONS HAS IN CURRENT DATABASESET @CMD = '[' + @DB + '].[DBO].[SP_HELPUSER]'-- EMPTY TEMPORARY TABLE #TMPUSERSTRUNCATE TABLE #TMPUSERS-- GET USER PERMISSIONS FOR ALL USERS IN CURRENT DATABASEINSERT INTO #TMPUSERS (USERNAME,GROUPNAME,LOGINNAME,DEFDBNAME,USERID,SCHEMANAME,SUSERID)EXEC ( @CMD)-- DETERMINE WHETHER THE OLD USER IS IN A ROLESELECT @CNT = COUNT(*)FROM #TMPUSERSWHERE LOGINNAME = @OLDLOGINAND GROUPNAME <> 'PUBLIC'-- IF OLD USER IS IN A ROLE THEN ADD NEW USER TO THAT ROLEIF @CNT > 0-- GENERATE COMMANDS TO ADD @NEWUSER TO APPROPRIATE ROLES IN CURRENT DATABASEINSERT INTO #TMP_LOGIN_RIGHTSSELECT DISTINCT'EXECUTE [' + @DB+ '].[DBO].[SP_ADDROLEMEMBER] '''+ RTRIM(A.GROUPNAME) + ''',''' + RTRIM(@NEWUSER)+ '''' AS RIGHTS_TEXTFROM #TMPUSERS AWHERE A.LOGINNAME = @OLDLOGINAND A.GROUPNAME <> 'PUBLIC'-- GET NEXT DATABASEFETCH NEXT FROM ALLDATABASES INTO @DBEND -- WHILE (@@FETCH_STATUS = 0)CLOSE ALLDATABASESDROP TABLE #TMPUSERS------------------------------------------------------------------------------- CREATE TABLE TO HOLD SERVER ROLESCREATE TABLE #TMPSRVROLES(SERVERROLE VARCHAR(100),MEMBERNAME VARCHAR(100),MEMBERSID VARBINARY(85))-- COMMAND TO GET SERVER ROLESSET @CMD = '[MASTER].[DBO].[SP_HELPSRVROLEMEMBER]'-- GET SERVER ROLES INTO TEMPORARY TABLEINSERT INTO #TMPSRVROLESEXEC ( @CMD)-- DETERMINE WHETHER THE OLD USER IS IN A SERVER ROLESELECT @CNT = COUNT(*)FROM #TMPSRVROLESWHERE MEMBERNAME = @OLDLOGIN-- IF OLD USER IS IN A ROLE THEN ADD NEW USER TO THAT SERVER ROLEIF @CNT > 0-- GENERATE COMMANDS TO ADD @NEWLOGIN INTO THE APPROPRIATE SERVER ROLESINSERT INTO #TMP_LOGIN_RIGHTSSELECT 'EXECUTE [MASTER].[DBO].[SP_ADDSRVROLEMEMBER] ' + ''''+ RTRIM(@NEWLOGIN) + '''' + ',[' + RTRIM(A.SERVERROLE)+ ']' AS RIGHTS_TEXTFROM #TMPSRVROLES AWHERE A.MEMBERNAME = @OLDLOGIN-- DROP SERVER ROLE TABLEDROP TABLE #TMPSRVROLES-- GRANT USER PERMISSIONS TO OBJECTS AND STATEMENTS--------------------------------------------------------------------------------- CREATE TEMPORARY TABLE TO HOLD INFORMATION ABOUT OBJECTS PERMISSIONSCREATE TABLE #TMPPROTECT(OWNER VARCHAR(100),OBJECT VARCHAR(100),GRANTEE VARCHAR(100),GRANTOR VARCHAR(100),PROTECTTYPE CHAR(10),ACTION VARCHAR(20),COLUMNX VARCHAR(100))OPEN ALLDATABASESSET @CMD = 'SELECT @OLDUSER=NAME FROM [' + @DB+ '].[DBO].[SYSUSERS] WHERE SID = (SELECT SID FROM [MASTER].[DBO].[SYSLOGINS]WHERE LOGINNAME = '+ CHAR(39) + @OLDLOGIN + CHAR(39) + ')'FETCH NEXT FROM ALLDATABASES INTO @DBWHILE ( @@FETCH_STATUS = 0 )BEGIN-- INITIALIZE @OLDUSER VARIABLESET @OLDUSER = ''--GENERATE COMMAND TO SET @OLDUSER TO THE USER NAME IN DATABASE-- IF @OLDLOGIN HAS ACCESS TO CURRENT DATABASESET @CMD = 'SELECT @OLDUSER=NAME FROM [' + @DB+ '].[DBO].[SYSUSERS] WHERE SID = (SELECT SID FROM [MASTER].[DBO].[SYSLOGINS]WHERE LOGINNAME = '+ CHAR(39) + @OLDLOGIN + CHAR(39) + ')'-- EXECUTE COMMAND TO SET @OLDUSER TO THE USER NAME IN DATABASE-- IF @OLDLOGIN HAS ACCESS TO CURRENT DATABASEEXEC [MASTER].[DBO].[SP_EXECUTESQL] @CMD,N'@OLDUSER CHAR(200) OUTPUT', @OLDUSER OUT-- IF @OLDUSER IS NOT BLANK THEN @OLDLOGIN HAS ACCESS TO CURRENT DATABASEIF @OLDUSER <> ''BEGIN-- GENERATE COMMAND TO GET OBJECT PERMISSIONS FOR CURRENT DATABASESET @CMD = '[' + @DB + '].[DBO].[SP_HELPROTECT]'-- GET OBJECT PERMISSIONS INTO TEMPORARY TABLEINSERT INTO #TMPPROTECTEXEC ( @CMD)-- DETERMINE IF THERE ARE ANY OBJECT PERMISSIONS FOR @OLDUSERSELECT @CNT = COUNT(*)FROM #TMPPROTECTWHERE GRANTEE = @OLDUSERIF @CNT > 0-- SWITCH TO THE APPROPRIATE DATABASEINSERT INTO #TMP_LOGIN_RIGHTSSELECT 'USE [' + @DB + ']'-- GENERATE COMMANDS TO GRANT OBJECTS PERMISSIONS FOR REFERENCES, SELECT, UPDATE TO @NEWUSERINSERT INTO #TMP_LOGIN_RIGHTSSELECT CASE WHEN RTRIM(PROTECTTYPE) = 'GRANT_WGO'THEN 'GRANT ' + ACTION + ' ON ['+ @DB + '].[' + OWNER + '].['+ OBJECT + '] TO ['+ RTRIM(@NEWUSER) + ']'+ ' WITH GRANT OPTION'ELSE 'GRANT ' + ACTION + ' ON ['+ @DB + '].[' + OWNER + '].['+ OBJECT + '] TO ['+ RTRIM(@NEWUSER) + ']'END AS RIGHTS_TEXTFROM #TMPPROTECTWHERE GRANTEE = @OLDUSERAND OBJECT <> '.'AND COLUMNX = '(ALL+NEW)'-- GRANT COLUMN PERMISSION ON OBJECTSINSERT INTO #TMP_LOGIN_RIGHTSSELECT CASE WHEN RTRIM(PROTECTTYPE) = 'GRANT_WGO'THEN 'GRANT ' + ACTION + ' ON ['+ @DB + '].[' + OWNER + '].['+ OBJECT + ']([' + COLUMNX+ '])' + ' TO ['+ RTRIM(@NEWUSER) + ']'+ ' WITH GRANT OPTION'ELSE 'GRANT ' + ACTION + ' ON ['+ @DB + '].[' + OWNER + '].['+ OBJECT + ']([' + COLUMNX+ '])' + ' TO ['+ RTRIM(@NEWUSER) + ']'END AS RIGHTS_TEXTFROM #TMPPROTECTWHERE GRANTEE = @OLDUSERAND OBJECT <> '.'AND COLUMNX <> '(ALL+NEW)'AND COLUMNX <> '.'-- GRANT INSERT, DELETE, AND EXECUTE PERMISSION ON OBJECTSINSERT INTO #TMP_LOGIN_RIGHTSSELECT CASE WHEN RTRIM(PROTECTTYPE) = 'GRANT_WGO'THEN 'GRANT ' + ACTION + ' ON ['+ @DB + '].[' + OWNER + '].['+ OBJECT + '] TO ['+ RTRIM(@NEWUSER) + ']'+ ' WITH GRANT OPTION'ELSE 'GRANT ' + ACTION + ' ON ['+ @DB + '].[' + OWNER + '].['+ OBJECT + '] TO ['+ RTRIM(@NEWUSER) + ']'END AS RIGHTS_TEXTFROM #TMPPROTECTWHERE GRANTEE = @OLDUSERAND OBJECT <> '.'AND ACTION IN ( 'INSERT', 'DELETE','EXECUTE' )AND COLUMNX = '.'-- GRANT STATEMENT PERMISSIONSINSERT INTO #TMP_LOGIN_RIGHTSSELECT 'GRANT ' + ACTION + ' TO ['+ RTRIM(@NEWUSER) + ']' AS RIGHTS_TEXTFROM #TMPPROTECTWHERE GRANTEE = @OLDUSERAND OBJECT = '.'-- REMOVE RECORDS FOR TEMPORARY TABLE IN PREPARATION FOR THE NEXT DATABASE TO BE PROCESSESTRUNCATE TABLE #TMPPROTECTEND-- GET NEXT DATABASE TO PROCESSFETCH NEXT FROM ALLDATABASES INTO @DBEND -- WHILE (@@FETCH_STATUS = 0)CLOSE ALLDATABASESDEALLOCATE ALLDATABASES-- DROP TEMPORARY TABLE THAT HELD OBJECT PERMISSIONSDROP TABLE #TMPPROTECT----------------------------------------------------------------------------------- GET ALL THE GENERATED COMMANDSDECLARE COMMANDS CURSORFOR SELECT *FROM #TMP_LOGIN_RIGHTSOPEN COMMANDSFETCH NEXT FROM COMMANDS INTO @CMDWHILE ( @@FETCH_STATUS = 0 )BEGINIF @CREATE_SCRIPT_ONLY = 1PRINT @CMDELSEEXEC (@CMD)FETCH NEXT FROM COMMANDS INTO @CMDENDCLOSE COMMANDSDEALLOCATE COMMANDS--DROP TEMPORARY TABLESDROP TABLE #TMP_LOGIN_RIGHTS

When I try to Cut Paste this script, I Have 3 lines with 3000 caracters !
ReplyDeleteIs it possible to add a download script feature?
Thanks
To Copy this script, first past in MS Word document file and then copy to SQL Server
DeleteThis comment has been removed by the author.
ReplyDelete