简体   繁体   English

还原 SQL Server 2005 数据库后将所有用户链接到登录

[英]Linking ALL Users to Login after restoring a SQL Server 2005 database

(Note this question asks about linking ALL Users, unlike the possible duplicate that asks about linking a single user) (注意这个问题询问链接所有用户,不像询问链接单个用户的可能重复)

I wish to move a database between two servers, I have backed the database up from the first server and done a database restore on the 2nd server, so far so good.我希望在两台服务器之间移动数据库,我已经从第一台服务器备份了数据库并在第二台服务器上进行了数据库恢复,到目前为止一切顺利。

However our application makes use of a lot of database users that are defined in the database.然而,我们的应用程序使用了许多在数据库中定义的数据库用户。 These have to be linked to logins that are defined in the master database.这些必须链接到在 master 数据库中定义的登录名。 The server I have restored the database to has all the logins defined, however they have different sids.我将数据库恢复到的服务器定义了所有登录名,但是它们具有不同的 sid。

I am not a T-SQL expert….我不是 T-SQL 专家……

I think sp_change_users_login is part of the solution, but I can't find out how to get it to automatically link all users in the restored database to the login of the same name.我认为sp_change_users_login是解决方案的一部分,但我不知道如何让它自动将恢复的数据库中的所有用户链接到同名登录。

The database creation scripts we use for our application create the users and logins, however it does not specify the SID when creating the login, hence this problem.我们用于应用程序的数据库创建脚本创建了用户和登录名,但是它在创建登录名时没有指定 SID,因此出现了这个问题。 Now if I had a time machine...现在如果我有一台时光机......

(When I Google I get lots of hits, however they are mostly sites that won't let you see the answer without having to register on the site first.) (当我谷歌时,我得到了很多点击,但是它们大多是网站,如果您不必先在网站上注册,就不会让您看到答案。)

Yes, you can do that by executing:是的,您可以通过执行:

EXEC sp_change_users_login 'Auto_Fix' , 'TheUserName';

However if your question was can I fix all users automatically then this won't do that.但是,如果您的问题是我可以自动修复所有用户,那么这不会这样做。

I came up with the following.我想出了以下内容。 It works great because it shows you:它非常有效,因为它向您展示了:

  1. All the current orphaned users.当前所有的孤立用户。
  2. Which ones were fixed.哪些是固定的。
  3. Which ones couldn't be fixed.哪些不能修复。

Other solutions require you to know the orphaned user name before hand in order to fix.其他解决方案要求您事先知道孤立的用户名才能进行修复。

The following code could run in a sproc that is called after restoring a database to another server.以下代码可以在将数据库还原到另一台服务器后调用的 sproc 中运行。

Script:脚本:

EXEC sp_change_users_login 'report'--See all orphaned users in the database.
DECLARE @OrphanedUsers TABLE
(
  IndexKey Int IDENTITY(1,1) PRIMARY KEY,
  UserName SysName,--nVarChar(128)
  UserSID  VarBinary(85)
)
INSERT INTO @OrphanedUsers
    EXEC sp_change_users_login 'report'

DECLARE @CRLF as nVarChar
    SET @CRLF = CHAR(10) + '&' + CHAR(13)--NOTE: Carriage-Return/Line-Feed will only appear in PRINT statements, not SELECT statements.
DECLARE @Sql as nVarChar(MAX)
    SET @Sql = N''
DECLARE @IndexKey as Int
    SET @IndexKey = 1
DECLARE @MaxIndexKey as Int
    SET @MaxIndexKey = (SELECT COUNT(*) FROM @OrphanedUsers)
DECLARE @Count as Int
    SET @Count = 0
DECLARE @UsersFixed as nVarChar(MAX)
    SET @UsersFixed = N''
DECLARE @UserName as SysName--This is an orphaned Database user.

WHILE (@IndexKey <= @MaxIndexKey)
  BEGIN
    SET @UserName = (SELECT UserName FROM @OrphanedUsers WHERE IndexKey = @IndexKey)
    IF 1 = (SELECT COUNT(*) FROM sys.server_principals WHERE Name = @UserName)--Look for a match in the Server Logins.
      BEGIN
        SET @Sql = @Sql + 'EXEC sp_change_users_login ''update_one'', [' + @UserName + '], [' + @UserName + ']' + @CRLF
        SET @UsersFixed = @UsersFixed + @UserName + ', '
        SET @Count = @Count + 1
      END
    SET @IndexKey = @IndexKey + 1
  END

PRINT @Sql
EXEC sp_executesql @Sql
PRINT   'Total fixed: ' + CAST(@Count as VarChar) + '.  Users Fixed: ' + @UsersFixed
SELECT ('Total fixed: ' + CAST(@Count as VarChar) + '.  Users Fixed: ' + @UsersFixed)[Fixed]
EXEC sp_change_users_login 'report'--See all orphaned users still in the database.

Result:结果:

在此处输入图片说明

*Note: The 4 that were not fixed (in my example screenshot above) did not have a corresponding User in the destination Server that the database was restored to. *注意:未修复的 4 个(在我上面的示例屏幕截图中)在数据库恢复到的目标服务器中没有相应的用户。

If:如果:

EXEC sp_change_users_login 'Auto_Fix' , 'TheUserName';

Doest't work, try this:不行,试试这个:

EXEC sp_change_users_login 'Auto_Fix', 'Username', NULL, 'p@ssword123'

I found it here: http://dbadiaries.com/using-sp_change_users_login-to-fix-sql-server-orphaned-users我在这里找到它: http : //dbadiaries.com/using-sp_change_users_login-to-fix-sql-server-orphaned-users

List of all orphan user details with corresponding DB name具有相应数据库名称的所有孤立用户详细信息的列表

Simple step简单的步骤


    EXEC master.sys.sp_MSforeachdb ' USE [?]
    Select ''?'' 
      EXEC ?.dbo.sp_change_users_login   ''report'' '

I found the following script from Microsoft KB918992 - run it on the original server and it will create a stored procedure called 'sp_help_revlogin' which generates another script to run on the destination server, creating all user accounts with the same passwords and sids.我从Microsoft KB918992 中找到了以下脚本 - 在原始服务器上运行它,它将创建一个名为“sp_help_revlogin”的存储过程,它生成另一个脚本以在目标服务器上运行,使用相同的密码和 sid 创建所有用户帐户。 Worked wonders for our upgrade from SQL2000 to 2008.为我们从 SQL2000 升级到 2008 创造了奇迹。

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(256) OUTPUT
AS
DECLARE @charvalue varchar(256)
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 @xstatus int
DECLARE @binpwd  varbinary (256)
DECLARE @txtpwd  sysname
DECLARE @tmpstr  varchar (256)
DECLARE @SID_varbinary varbinary(85)
DECLARE @SID_string varchar(256)

IF (@login_name IS NULL)
  DECLARE login_curs CURSOR FOR 
    SELECT sid, name, xstatus, password FROM master..sysxlogins 
    WHERE srvid IS NULL AND name <> 'sa'
ELSE
  DECLARE login_curs CURSOR FOR 
    SELECT sid, name, xstatus, password FROM master..sysxlogins 
    WHERE srvid IS NULL AND name = @login_name
OPEN login_curs 
FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @xstatus, @binpwd
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 ''
PRINT 'DECLARE @pwd sysname'
WHILE (@@fetch_status <> -1)
BEGIN
  IF (@@fetch_status <> -2)
  BEGIN
    PRINT ''
    SET @tmpstr = '-- Login: ' + @name
    PRINT @tmpstr 
    IF (@xstatus & 4) = 4
    BEGIN -- NT authenticated account/group
      IF (@xstatus & 1) = 1
      BEGIN -- NT login is denied access
        SET @tmpstr = 'EXEC master..sp_denylogin ''' + @name + ''''
        PRINT @tmpstr 
      END
      ELSE BEGIN -- NT login has access
        SET @tmpstr = 'EXEC master..sp_grantlogin ''' + @name + ''''
        PRINT @tmpstr 
      END
    END
    ELSE BEGIN -- SQL Server authentication
      IF (@binpwd IS NOT NULL)
      BEGIN -- Non-null password
        EXEC sp_hexadecimal @binpwd, @txtpwd OUT
        IF (@xstatus & 2048) = 2048
          SET @tmpstr = 'SET @pwd = CONVERT (varchar(256), ' + @txtpwd + ')'
        ELSE
          SET @tmpstr = 'SET @pwd = CONVERT (varbinary(256), ' + @txtpwd + ')'
        PRINT @tmpstr
    EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT
        SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name 
          + ''', @pwd, @sid = ' + @SID_string + ', @encryptopt = '
      END
      ELSE BEGIN 
        -- Null password
    EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT
        SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name 
          + ''', NULL, @sid = ' + @SID_string + ', @encryptopt = '
      END
      IF (@xstatus & 2048) = 2048
        -- login upgraded from 6.5
        SET @tmpstr = @tmpstr + '''skip_encryption_old''' 
      ELSE 
        SET @tmpstr = @tmpstr + '''skip_encryption'''
      PRINT @tmpstr 
    END
  END
  FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @xstatus, @binpwd
  END
CLOSE login_curs 
DEALLOCATE login_curs 
RETURN 0
GO

I have a nice script that you can use to create logins from database users,which I came across after searching for this issue this script is using a stored procedure.我有一个很好的脚本,您可以使用它从数据库用户创建登录名,这是我在搜索此问题后遇到的,该脚本使用的是存储过程。 you can find some other useful scripts here also at this url http://www.sqlserveroptimizer.com/2011/08/how-to-script-logins-from-user-database-in-sql-server-20052008-r2/您也可以在此网址上找到其他一些有用的脚本http://www.sqlserveroptimizer.com/2011/08/how-to-script-logins-from-user-database-in-sql-server-20052008-r2/

USE MyDatabaseName

DECLARE @login nvarchar(50)

DECLARE logins_cursor CURSOR FOR SELECT l.name FROM sys.database_principals u INNER JOIN sys.server_principals l ON u.sid=l.sid

OPEN logins_cursor FETCH NEXT FROM logins_cursor INTO @login

WHILE @@FETCH_STATUS = 0 BEGIN EXEC sp_help_revlogin @login FETCH NEXT FROM logins_cursor INTO @login END

CLOSE logins_cursor DEALLOCATE logins_cursor GO

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM