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,