Exporting SQL Logons
by , 15th August 2012 at 09:44 AM (1473 Views)
Another diversion from my usual blog posts - but this one came out of necessity, when I had issues with my SQL databases for SIMS and FMS. Many of you may know that FMS has its own "SQL" logins, as does SIMS - but at least with that, you can set it to use Windows Authentication.
Anyway, my problem - I was greeted by FMS with the lovely "Cannot rollback atomic" error whenever logging in. It turns out this error (after some digging) has lots of causes - none of them really to do with SIMS or FMS.
This error is documented here FMS Fault most recently, and FMS problem historically. There are also some SupportNet articles on it too.
It is, as the error states an SQL error. Essentially - what has happened is that a transaction is in a "stuck state" relating to a login. Ways of clearing it... well first off - when was your last backup - and have you been doing backups using DBAttach.
If not, then we are going to need a copy of all the SQL logins so we can recreate them. If you detattach and reattach a SIMS/FMS DB without it (ie move a server) - then you wont have you logins brought across.
The script to do this is as shown below. You need SQL Management Studio for this, and then you are thinking - how do I run it? Well, copy and paste it into a "New Query" (yes - click the "New Query" button in Studio. Then, its Execute. The output from this needs saving somewhere safe.
Next up, run DBAttach to dettach the database. This will run its own backup - but I would still take your own first. Then - go into your SQL Data folder, and copy (yes, copy) the two database files for FMS (and or SIMS) out somewhere else for safe keeping. Rename them something sensible (like add the date and time on the end). Remove them from the SQL Data folder... as when you run DBAttach to re-attach the DBS (point at your backup, or the files you just had) - it will copy them back into the SQL Data folder.
Check after doing the DBAttach (to dettach...confused with all that yet!) that the DB has gone from SQL Studio. Also look in the Logins under Security whether your user accounts are still there. If the first time of this full procedure fails, I would try removing your offending logins - as the import script (the output of running the query script shown here) will recreate them.
Hope this helps.
Of course - this is all at your own risk, and will not be supported by Capita. That being said, this is likely what they do if they have to have your DB to look at - and its what I did with my local support team.
Code:USE master GO IF OBJECT_ID ('sp_hexadecimal') IS NOT NULL DROP PROCEDURE sp_hexadecimal GO CREATE PROCEDURE 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 GO IF OBJECT_ID ('sp_help_revlogin') IS NOT NULL DROP PROCEDURE sp_help_revlogin GO CREATE PROCEDURE sp_help_revlogin @login_name sysname = NULL AS 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 varchar (1024) DECLARE @is_policy_checked varchar (3) DECLARE @is_expiration_checked varchar (3) DECLARE @defaultdb sysname IF @login_name IS NULL) 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' ELSE 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 = @login_name 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 RETURN -1 END SET @tmpstr = '/* sp_help_revlogin script ' PRINT @tmpstr SET @tmpstr = '** Generated ' + CONVERT (varchar, GETDATE()) + ' on ' + @@SERVERNAME + ' */' PRINT @tmpstr PRINT '' WHILE (@@fetch_status <> -1) BEGIN IF (@@fetch_status <> -2) BEGIN PRINT '' SET @tmpstr = '-- Login: ' + @name PRINT @tmpstr IF (@type IN ( 'G', 'U')) BEGIN -- NT authenticated account/group SET @tmpstr = '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 = '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 PRINT @tmpstr END FETCH NEXT FROM login_curs INTO @sid_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin END CLOSE login_curs DEALLOCATE login_curs RETURN 0 GO



Email Blog Entry
