Recreating Logins From 1 Server to Apply to Another

A little background on this script.
We had to build out a new TEST environment along with a new security schema.
We had to apply it to PROD first due to issues and then migrate it down.
With nearly 500 DBs on multiple servers, I didn't want to have to try to redo all of the permissions to each object manually.

I build this script to cycle thru all of the logins on the server that fit a particular AD pattern and generate the CREATE script for them with the TEST name instead. 
Once the script was run, all I had to do was copy it, paste it in the TEST environment, and run it. 
It automatically adds the logins to each DB not just to the server itself.

Each environment has an AD group for the DB in a standard pattern that is specific to that environment.
The pattern is something like this:
PROD - PRD_DBName_Read or PRD_DBName_Edit (depends on level of permissions)
TEST - TST_DBName_Read or TST_DBName_Edit (depends on level of permissions)
DEV - DEV_DBName_Read or DEV_DBName_Edit (depends on level of permissions)

DBName is the actual name of the database or a short name for it if it was an oddly named one.

This is a very granular level of security but we needed to do it for various reasons.

Each application has it's own login that is put into the AD group.
This lets the DBA not have to deal with most permissions issues after the original AD groups have been set up. 
Application A has a login it runs under and that is added to the PRD_DBName_Read/Edit AD group.
Users can be added to the PRD_DBName_Read/Edit AD group by an admin.
When a user leaves, they are automatically removed so the DBA doesn't have to manage them anymore.

Now for the script itself.:

DECLARE
@DBName VARCHAR (500)
, @sqltext NVARCHAR(MAX)
, @CreateUser NVARCHAR(MAX)

SELECT @DBName = ''
SELECT @sqltext = ''
SELECT @CreateUser = ''

IF OBJECT_ID('[tempdb]..#Logins') IS NOT NULL
BEGIN
DROP TABLE #Logins
END 
CREATE TABLE #Logins
(
[LoginString] VARCHAR(MAX)
)

SELECT
@CreateUser = @CreateUser + 'USE [master]; CREATE LOGIN [' + 
REPLACE(CONVERT(VARCHAR(500),[sp].[name]),'PRD_', 'TST_') +
'] FROM WINDOWS
;'
FROM
[sys].[server_principals] AS [sp] WITH (NOLOCK)
WHERE
[sp].[name] LIKE 'domain\PRD_%'
AND [sp].[name] NOT LIKE 'domain\TST_%'

INSERT INTO [#Logins] SELECT @CreateUser

DECLARE DBNames_Cursor CURSOR STATIC FOR 
SELECT -- * ,
[s].[name]
FROM 
master.dbo.[sysdatabases] AS [s]    WITH (NOLOCK)
WHERE 
[s].[name] <> 'master'
ORDER BY 
[s].[name]

OPEN DBNames_Cursor
FETCH NEXT FROM DBNames_Cursor INTO @DBName

WHILE (@@FETCH_STATUS <> -1)
BEGIN /* @@FETCH_STATUS <> -1 */
IF (@@FETCH_STATUS <> -2)
BEGIN /* @@FETCH_STATUS <> -2 */
--
SELECT @sqltext = @sqltext + '
SELECT ''USE [' + @DBName +']; 
CREATE USER ['' + REPLACE(CONVERT(VARCHAR(500),[dbp].[name]),''PRD_'', ''TST_'') 
+ ''] FOR LOGIN [''
+ REPLACE(CONVERT(VARCHAR(500),[dbp].[name]),''PRD_'', ''TST_'') 
+ ''];''
FROM
[' + @DBName + '].[sys].[database_principals] AS [dbp] WITH (NOLOCK)
WHERE
[dbp].[name] LIKE ''domain\PRD_%''
AND [dbp].[name] NOT LIKE ''domain\TST_%'''

BEGIN TRY
PRINT @sqltext
INSERT INTO #Logins
EXECUTE [sys].[sp_executesql] @sqltext
END TRY
BEGIN CATCH
SELECT  
ERROR_NUMBER() AS ErrorNumber  
,ERROR_SEVERITY() AS ErrorSeverity  
,ERROR_STATE() AS ErrorState  
,ERROR_PROCEDURE() AS ErrorProcedure  
,ERROR_LINE() AS ErrorLine  
,ERROR_MESSAGE() AS ErrorMessage  
, @sqltext
END CATCH

SELECT @sqltext = ''

END /* @@FETCH_STATUS <> -2 */
FETCH NEXT FROM DBNames_Cursor INTO @DBName
END /* @@FETCH_STATUS <> -1 */
CLOSE DBNames_Cursor
DEALLOCATE DBNames_Cursor

SELECT * FROM #Logins;


#MicrosoftSQL
#Logins
#DynamicSQL
#BuckTheSQLDude

Comments

Popular posts from this blog

Recreating Permissions from 1 server to another for a different group

SP to Cycle thru All Linked Servers