Quantcast
Channel: SQL Server High Availability and Disaster Recovery forum
Viewing all articles
Browse latest Browse all 4689

Sync_logins stored proc does not work in Always On

$
0
0

hi,

On a daily basis at 2:00 AM this sp is executed regardless a failover happened or not and most of times I am receiving errors:

I find three casusitry

1-Could not drop login domain\user as the user is currently logged i as the user is currently logged in.

Amended looking for sessions and applying KILL before to do the DROP and CREATE

2-The server principal domain\user already exists.

It does not make any sense because my stored procedure is callingsp_validatelogins

3-Cannot find the login domain\user, because it does not exist or you do not have permission.

same than point 2.

I am wondering how to trigger this sp only when a failover happen

CREATE PROCEDURE [dbo].[ScriptLogins]

AS

SET NOCOUNT ON

DECLARE
	@StatementToRun VARCHAR(MAX) = ''
	,@CurrentRow INT
	,@TotalRows INT
	,@sid VARBINARY(85)
	,@name SYSNAME
	,@type CHAR(1)
	,@is_disabled INT
	,@default_database_name SYSNAME
	,@hasaccess INT
	,@denylogin INT
	,@password_hash VARBINARY(256)
	,@PasswordHashString NVARCHAR(300)
	,@SIDString NVARCHAR(100)
	,@is_policy_checked VARCHAR(3)
	,@is_expiration_checked VARCHAR(3)
	,@RoleName SYSNAME
	,@LoginName SYSNAME
	,@PermState NVARCHAR(60)
	,@PermName SYSNAME
	,@Class TINYINT
	,@ClassDesc NVARCHAR(60)
	,@MajorID INT
	,@SubLoginName SYSNAME
	,@SubEndPointName SYSNAME

/**********************************************************************
Usage:

Run from the instance that the logins will be created on:
DECLARE @StatementToRun VARCHAR(MAX)
SELECT @StatementToRun = StatementToRun FROM OPENQUERY("linkedservername", 'EXEC master.dbo.ScriptLogins')
EXEC (@StatementToRun)
**********************************************************************/

/**********************************************************************
Credits:

Created by Tomas Lind 2014
http://media.tomaslind.net/2014/02/ScriptLogins.txt

Most of the functionality in this procedure is copied from two sources:

Microsoft Support: sp_help_revlogin
(http://support.microsoft.com/kb/918992)

SQLSoldier: dba_CopyLogins
(http://www.sqlsoldier.com/wp/wp-content/uploads/Scripts/dba_CopyLogins.sql)

**********************************************************************/


/**********************************************************************
@sp_validatelogins
Results from sp_validatelogins is used to filter out users
no longer in AD.
**********************************************************************/
DECLARE @sp_validatelogins TABLE
    (
        [sid] VARBINARY(85) NOT NULL
        ,NTLogin SYSNAME NOT NULL
    )
 
INSERT INTO @sp_validatelogins
EXEC sp_validatelogins


/**********************************************************************
@Logins
The logins to transfer
**********************************************************************/
DECLARE @Logins TABLE
	(
		LoginId INT IDENTITY(1,1) NOT NULL PRIMARY KEY
		,[sid] VARBINARY(85) NOT NULL
		,[name] SYSNAME NOT NULL
		,[type] CHAR(1) NOT NULL
		,is_disabled INT NOT NULL
		,default_database_name SYSNAME NOT NULL
		,hasaccess INT NOT NULL
		,denylogin INT NOT NULL
		,password_hash VARBINARY(256) NULL
		,is_policy_checked VARCHAR(3) NULL
		,is_expiration_checked VARCHAR(3) NULL
	)
INSERT
	@Logins ([sid], [name], [type], is_disabled, default_database_name, hasaccess, denylogin, password_hash, is_policy_checked, is_expiration_checked)
SELECT
	principals.[sid]
	,principals.[name]
	,principals.[type]
	,principals.is_disabled
	,principals.default_database_name
	,logins.hasaccess
	,logins.denylogin
	,sqllogins.password_hash
	,CASE sqllogins.is_policy_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' ELSE NULL END
	,CASE sqllogins.is_expiration_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' ELSE NULL END
FROM
	sys.server_principals AS principals
LEFT OUTER JOIN
	sys.syslogins AS logins
ON
	principals.[name] = logins.[name]
LEFT OUTER JOIN
	sys.sql_logins AS sqllogins
ON
	principals.principal_id = sqllogins.principal_id
WHERE
	principals.[type] IN ('S', 'U', 'G') --S = SQL login, U = Windows login, G = Windows group
AND
	principals.[sid] <> 0x01 --sa even if it is renamed
AND
	principals.[name] NOT LIKE '##%' --system users
AND
	principals.[name] NOT LIKE 'BUILTIN%' --system users
AND
	principals.[name] NOT LIKE 'NT %' --system users
AND
	SUBSTRING(principals.[name], 1, ABS(CHARINDEX('\', principals.[name])-1)) <> SUBSTRING(@@SERVERNAME, 1, ABS(CHARINDEX('\', @@SERVERNAME)-1)) --local machine users
AND
	principals.[name] NOT IN (SELECT NTLogin FROM @sp_validatelogins) --users no longer in AD.


/**********************************************************************
@Roles
The roles to transfer
**********************************************************************/
DECLARE @Roles TABLE
	(
		RoleId INT IDENTITY(1,1) NOT NULL PRIMARY KEY
		,RoleName SYSNAME NOT NULL
		,LoginName SYSNAME NOT NULL
	)

INSERT
	@Roles (RoleName, LoginName)
SELECT
	role_principals.name
	,login_principals.name
FROM
	sys.server_role_members AS role_members
JOIN
	sys.server_principals AS role_principals
ON
	role_members.role_principal_id = role_principals.principal_id
JOIN
	sys.server_principals AS login_principals
ON
	role_members.member_principal_id = login_principals.principal_id
WHERE
	login_principals.[type] IN ('S', 'U', 'G') --S = SQL login, U = Windows login, G = Windows group
AND
	login_principals.[sid] <> 0x01 --sa even if it is renamed
AND
	login_principals.[name] NOT LIKE '##%' --system users
AND
	login_principals.[name] NOT LIKE 'BUILTIN%' --system users
AND
	login_principals.[name] NOT LIKE 'NT %' --system users
AND
	SUBSTRING(login_principals.[name], 1, ABS(CHARINDEX('\', login_principals.[name])-1)) <> SUBSTRING(@@SERVERNAME, 1, ABS(CHARINDEX('\', @@SERVERNAME)-1)) --local machine users
AND
	login_principals.[name] NOT IN (SELECT NTLogin FROM @sp_validatelogins) --users no longer in AD.
AND
	role_principals.[type] = 'R'


/**********************************************************************
@Permissions
The permissions to transfer
**********************************************************************/
DECLARE @Permissions TABLE
	(
		PermissionId INT IDENTITY(1,1) NOT NULL PRIMARY KEY
		,LoginName SYSNAME NOT NULL
		,PermState NVARCHAR(60) NOT NULL
		,PermName SYSNAME NOT NULL
		,Class TINYINT NOT NULL
		,ClassDesc NVARCHAR(60) NOT NULL
		,MajorID INT NOT NULL
		,SubLoginName SYSNAME NULL
		,SubEndPointName SYSNAME NULL
	)

INSERT
	@Permissions (LoginName, PermState, PermName, Class, ClassDesc, MajorID, SubLoginName, SubEndPointName)
SELECT
	Tprincipals.name COLLATE database_default
	,Tpermissions.state_desc
	,Tpermissions.[permission_name]
	,Tpermissions.class
	,Tpermissions.class_desc
	,Tpermissions.major_id
	,TServerPrincipal.name COLLATE database_default
	,Tendpoints.name COLLATE database_default
FROM
	sys.server_principals AS Tprincipals
JOIN
	sys.server_permissions AS Tpermissions
ON
	Tprincipals.principal_id = Tpermissions.grantee_principal_id
LEFT OUTER JOIN
	sys.server_principals AS TServerPrincipal
ON
	TServerPrincipal.principal_id = Tpermissions.major_id
AND
	Tpermissions.class = 101
LEFT OUTER JOIN
	sys.endpoints AS Tendpoints
ON
	Tendpoints.endpoint_id = Tpermissions.major_id
AND
	Tpermissions.class = 105
WHERE
	Tprincipals.[type] IN ('S', 'U', 'G') --S = SQL login, U = Windows login, G = Windows group
AND
	Tprincipals.[sid] <> 0x01 --sa even if it is renamed
AND
	Tprincipals.[name] NOT LIKE '##%' --system users
AND
	Tprincipals.[name] NOT LIKE 'BUILTIN%' --system users
AND
	Tprincipals.[name] NOT LIKE 'NT %' --system users
AND
	SUBSTRING(Tprincipals.[name], 1, ABS(CHARINDEX('\', Tprincipals.[name])-1)) <> SUBSTRING(@@SERVERNAME, 1, ABS(CHARINDEX('\', @@SERVERNAME)-1)) --local machine users
AND
	Tprincipals.[name] NOT IN (SELECT NTLogin FROM @sp_validatelogins) --users no longer in AD.


/**********************************************************************
Add the logins to the script
**********************************************************************/
SELECT @TotalRows = COUNT(*), @CurrentRow = 1 FROM @Logins

WHILE @CurrentRow <= @TotalRows BEGIN

	SELECT @sid = [sid] ,@name = [name] ,@type = [type] ,@is_disabled = is_disabled ,@default_database_name = default_database_name ,@hasaccess = hasaccess, @denylogin = denylogin, @password_hash = password_hash, @is_policy_checked = is_policy_checked, @is_expiration_checked = is_expiration_checked
	FROM @Logins
	WHERE LoginId = @CurrentRow

	IF (@type IN ('G', 'U')) BEGIN --NT authenticated account/group
		SET @StatementToRun = @StatementToRun +
			CHAR(13) + CHAR(13) + '
			IF EXISTS (SELECT * FROM sys.server_principals WHERE [name] = ''' + @name + ''') BEGIN
				DROP LOGIN ' + QUOTENAME(@name) + '
			END
			IF EXISTS (SELECT * FROM sys.databases WHERE [name] = ''' + @default_database_name + ''') BEGIN
				CREATE LOGIN ' + QUOTENAME(@name) + ' FROM WINDOWS WITH DEFAULT_DATABASE = [' + @default_database_name + ']' + '
			END
			ELSE BEGIN
				CREATE LOGIN ' + QUOTENAME(@name) + ' FROM WINDOWS WITH DEFAULT_DATABASE = [master]
			END'
	END
    ELSE BEGIN --SQL Server authentication
		SET @PasswordHashString = '0x' + CAST('' AS XML).value('xs:hexBinary(sql:variable("@password_hash"))', 'nvarchar(300)')
		SET @SIDString = '0x' + CAST('' AS XML).value('xs:hexBinary(sql:variable("@sid"))', 'nvarchar(100)')

		SET @StatementToRun = @StatementToRun +
			CHAR(13) + CHAR(13) + '
			IF EXISTS (SELECT * FROM sys.server_principals WHERE [name] = ''' + @name + ''') BEGIN
				DROP LOGIN ' + QUOTENAME(@name) + '
			END
			IF EXISTS (SELECT * FROM sys.databases WHERE [name] = ''' + @default_database_name + ''') BEGIN
				CREATE LOGIN ' + QUOTENAME(@name) + ' WITH PASSWORD = ' + @PasswordHashString + ' HASHED, SID = ' + @SIDString + ', DEFAULT_DATABASE = [' + @default_database_name + ']' + '
			END
			ELSE BEGIN
				CREATE LOGIN ' + QUOTENAME(@name) + ' WITH PASSWORD = ' + @PasswordHashString + ' HASHED, SID = ' + @SIDString + ', DEFAULT_DATABASE = [master]
			END'

			IF (@is_policy_checked IS NOT NULL) BEGIN
				SET @StatementToRun = @StatementToRun + '
			ALTER LOGIN ' + QUOTENAME(@name) + ' WITH CHECK_POLICY = ' + @is_policy_checked
			END
			IF (@is_expiration_checked IS NOT NULL) BEGIN
				SET @StatementToRun = @StatementToRun + ', CHECK_EXPIRATION = ' + @is_expiration_checked
			END

	END

	IF (@denylogin = 1) BEGIN -- login is denied access
		SET @StatementToRun = @StatementToRun + '; DENY CONNECT SQL TO ' + QUOTENAME(@name)
    END
    ELSE IF (@hasaccess = 0) BEGIN -- login exists but does not have access
		SET @StatementToRun = @StatementToRun + '; REVOKE CONNECT SQL TO ' + QUOTENAME(@name)
    END
    IF (@is_disabled = 1) BEGIN -- login is disabled
		SET @StatementToRun = @StatementToRun + '
			ALTER LOGIN ' + QUOTENAME(@name) + ' DISABLE'
    END

	SET @CurrentRow = @CurrentRow + 1
END


/**********************************************************************
Add the roles to the script
**********************************************************************/
SELECT @TotalRows = COUNT(*), @CurrentRow = 1 FROM @Roles

WHILE @CurrentRow <= @TotalRows BEGIN
	SELECT @RoleName = RoleName, @LoginName = LoginName
	FROM @Roles
	WHERE RoleId = @CurrentRow

	SET @StatementToRun = @StatementToRun + 
	CHAR(13) + '
			EXEC sp_addsrvrolemember @rolename = ' + @RoleName + ', @loginame = ' + QUOTENAME(@LoginName)

	SET @CurrentRow = @CurrentRow + 1
END


/**********************************************************************
Add the permisssions to the script
**********************************************************************/
SELECT @TotalRows = COUNT(*), @CurrentRow = 1 FROM @Permissions

WHILE @CurrentRow <= @TotalRows BEGIN
	SELECT @LoginName = LoginName, @PermState = PermState, @PermName = PermName, @Class = Class, @ClassDesc = ClassDesc, @MajorID = MajorID, @SubLoginName = SubLoginName, @SubEndPointName = SubEndPointName
	FROM @Permissions
	WHERE PermissionId = @CurrentRow

	SET @StatementToRun = @StatementToRun + 
	CHAR(13) + '
			' + @PermState + ' ' + @PermName + ' ' +
			CASE @Class WHEN 101 THEN 'ON LOGIN::' + QUOTENAME(@SubLoginName) WHEN 105 THEN 'ON ' + @ClassDesc + '::' + QUOTENAME(@SubEndPointName)  ELSE '' END +
			' TO ' + QUOTENAME(@LoginName)

	SET @CurrentRow = @CurrentRow + 1
END

SELECT @StatementToRun AS StatementToRun
GO

Thanks,


Viewing all articles
Browse latest Browse all 4689

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>