次の方法で共有


SQL Server のインスタンス間でログインとパスワードを転送する

この記事では、Windows で実行されている SQL Server の異なるインスタンス間で、ログインとパスワードを転送する方法について説明します。

元の製品バージョン: SQL Server
元の KB 番号: 918992、246133

はじめに

この記事では、Microsoft SQL Server の異なるインスタンス間で、ログインとパスワードを転送する方法について説明します。 インスタンスが同じサーバー上にあるか、異なるサーバー上にあり、それらのバージョンが異なる場合があります。

SQL Server インスタンス間でログインを転送する理由

この記事では、サーバー A とサーバー B はサーバーです。

サーバー A 上の SQL Server インスタンスからサーバー B 上の SQL Server インスタンスにデータベースを移動すると、ユーザーはサーバー B 上のデータベース サーバーにログインできないことがあります。さらに、ユーザーは次のエラー メッセージを受け取る可能性があります。

ユーザー 'MyUser' はログインできませんでした。 (Microsoft SQL Server、エラー:18456)

この問題は、サーバー A 上の SQL Server インスタンスからのログインがサーバー B の SQL Server インスタンスに存在しないために発生します。

エラー 18456 は他の多くの理由で発生します。 これらの原因とその解決策の詳細については、 MSSQLSERVER_18456を参照してください。

ログインを転送する手順

ログインを転送するには、状況に応じて、次のいずれかの方法を使用します。

方法 1: ソース サーバー上の SSMS を使用してスクリプトを生成し、移行先サーバーで SQL Server ログインのパスワードを手動でリセットする

データベースの Generate Scripts オプションを使用して、SQL Server Management Studio (SSMS) でログイン スクリプトを生成

ソース サーバー上の SSMS 経由でスクリプトを生成し、移行先サーバー上の SQL Server ログインのパスワードを手動でリセットするには、次の手順に従います。

  1. ソース SQL Server をホストしているサーバー A に接続します。

  2. [データベース] ノードを展開します。

  3. 任意のユーザー データベースを右クリックし、 Tasks>Generate Scripts を選択します。

  4. [説明] ページが開きます。 [次へ] を選択して、Choose Objects ページを開きます。 [データベース全体とすべてのデータベース オブジェクトのスクリプトを作成] を選択します。

  5. [次へ] を選択し、 [スクリプト作成オプションの設定] ページを開きます。

  6. スクリプト ログイン オプションの Advanced ボタンを選択します。

  7. Advancedリストで、Script Loginsを見つけ、オプションをTrueに設定し、OKを選択します。

  8. [スクリプトオプションの設定]に戻りスクリプトの保存方法を選択し[新しいクエリ ウィンドウで開く]を選択します

  9. 次へを 2 回選択し、 Finish を選択します。

  10. ログインを含むスクリプト内のセクションを見つけます。 通常、生成されたスクリプトには、このセクションの先頭に次のコメントが含まれるテキストが含まれています。

    /* For security reasons the login is created disabled and with a random password. */

    Note

    これは、SQL Server 認証ログインがランダムなパスワードで生成され、既定で無効になっていることを示します。 パスワードをリセットし、移行先サーバーでこれらのログインを再度有効にする必要があります。

  11. 生成された大きなスクリプトからコピー先の SQL Server にログイン スクリプトを適用します。

  12. SQL Server 認証ログインの場合は、移行先の SQL Server でパスワードをリセットし、それらのログインを再度有効にします。

方法 2: 移行元サーバー (サーバー A) で生成されたスクリプトを使用して、ログインとパスワードを移行先サーバー (サーバー B) に転送する

  1. ログインとそのパスワードの転送に必要なスクリプトを生成するために、ストアド プロシージャを作成します。 これを行うには、SQL Server Management Studio (SSMS) またはその他のクライアント ツールを使用してサーバー A に接続し、次のスクリプトを実行します。

    USE [master]
    GO
    IF OBJECT_ID('dbo.sp_hexadecimal') IS NOT NULL
        DROP PROCEDURE dbo.sp_hexadecimal
    GO
    CREATE PROCEDURE dbo.sp_hexadecimal
        @binvalue [varbinary](256)
        ,@hexvalue [nvarchar] (514) OUTPUT
    AS
    BEGIN
        DECLARE @i [smallint]
        DECLARE @length [smallint]
        DECLARE @hexstring [nchar](16)
        SELECT @hexvalue = N'0x'
        SELECT @i = 1
        SELECT @length = DATALENGTH(@binvalue)
        SELECT @hexstring = N'0123456789ABCDEF'
        WHILE (@i < =  @length)
        BEGIN
            DECLARE @tempint   [smallint]
            DECLARE @firstint  [smallint]
            DECLARE @secondint [smallint]
            SELECT @tempint = CONVERT([smallint], SUBSTRING(@binvalue, @i, 1))
            SELECT @firstint = FLOOR(@tempint / 16)
            SELECT @secondint = @tempint - (@firstint * 16)
            SELECT @hexvalue = @hexvalue
                + SUBSTRING(@hexstring, @firstint  + 1, 1)
                + SUBSTRING(@hexstring, @secondint + 1, 1)
            SELECT @i = @i + 1
        END
    END
    GO
    IF OBJECT_ID('dbo.sp_help_revlogin') IS NOT NULL
        DROP PROCEDURE dbo.sp_help_revlogin
    GO
    CREATE PROCEDURE dbo.sp_help_revlogin
        @login_name [sysname] = NULL
    AS
    BEGIN
        DECLARE @name                  [sysname]
        DECLARE @type                  [nvarchar](1)
        DECLARE @hasaccess             [int]
        DECLARE @denylogin             [int]
        DECLARE @is_disabled           [int]
        DECLARE @PWD_varbinary         [varbinary](256)
        DECLARE @PWD_string            [nvarchar](514)
        DECLARE @SID_varbinary         [varbinary](85)
        DECLARE @SID_string            [nvarchar](514)
        DECLARE @tmpstr                [nvarchar](4000)
        DECLARE @is_policy_checked     [nvarchar](3)
        DECLARE @is_expiration_checked [nvarchar](3)
        DECLARE @Prefix                [nvarchar](4000)
        DECLARE @defaultdb             [sysname]
        DECLARE @defaultlanguage       [sysname]
        DECLARE @tmpstrRole            [nvarchar](4000)
        IF @login_name IS NULL
        BEGIN
            DECLARE login_curs CURSOR
            FOR
            SELECT p.[sid],p.[name],p.[type],p.is_disabled,p.default_database_name,l.hasaccess,l.denylogin,default_language_name = ISNULL(p.default_language_name,@@LANGUAGE)
            FROM sys.server_principals p
            LEFT JOIN sys.syslogins l ON l.[name] = p.[name]
            WHERE p.[type] IN ('S' /* SQL_LOGIN */,'G' /* WINDOWS_GROUP */,'U' /* WINDOWS_LOGIN */)
                AND p.[name] <> 'sa'
                AND p.[name] not like '##%'
            ORDER BY p.[name]
        END
        ELSE
            DECLARE login_curs CURSOR
            FOR
            SELECT p.[sid],p.[name],p.[type],p.is_disabled,p.default_database_name,l.hasaccess,l.denylogin,default_language_name = ISNULL(p.default_language_name,@@LANGUAGE)
            FROM sys.server_principals p
            LEFT JOIN sys.syslogins l ON l.[name] = p.[name]
            WHERE p.[type] IN ('S' /* SQL_LOGIN */,'G' /* WINDOWS_GROUP */,'U' /* WINDOWS_LOGIN */)
                AND p.[name] <> 'sa'
                AND p.[name] NOT LIKE '##%'
                AND p.[name] = @login_name
            ORDER BY p.[name]
        OPEN login_curs
        FETCH NEXT FROM login_curs INTO @SID_varbinary,@name,@type,@is_disabled,@defaultdb,@hasaccess,@denylogin,@defaultlanguage
        IF (@@fetch_status = - 1)
        BEGIN
            PRINT '/* No login(s) found for ' + QUOTENAME(@login_name) + N'. */'
            CLOSE login_curs
            DEALLOCATE login_curs
            RETURN - 1
        END
        SET @tmpstr = N'/* sp_help_revlogin script
    ** Generated ' + CONVERT([nvarchar], GETDATE()) + N' on ' + @@SERVERNAME + N'
    */'
        PRINT @tmpstr
        WHILE (@@fetch_status <> - 1)
        BEGIN
            IF (@@fetch_status <> - 2)
            BEGIN
                PRINT ''
                SET @tmpstr = N'/* Login ' + QUOTENAME(@name) + N' */'
                PRINT @tmpstr
                SET @tmpstr = N'IF NOT EXISTS (
        SELECT 1
        FROM sys.server_principals
        WHERE [name] = N''' + @name + N'''
        )
    BEGIN'
                PRINT @tmpstr
                IF @type IN ('G','U') -- NT-authenticated Group/User
                BEGIN -- NT authenticated account/group 
                    SET @tmpstr = N'    CREATE LOGIN ' + QUOTENAME(@name) + N'
        FROM WINDOWS
        WITH DEFAULT_DATABASE = ' + QUOTENAME(@defaultdb) + N'
            ,DEFAULT_LANGUAGE = ' + QUOTENAME(@defaultlanguage)
                END
                ELSE
                BEGIN -- SQL Server authentication
                    -- obtain password and sid
                    SET @PWD_varbinary = CAST(LOGINPROPERTY(@name, 'PasswordHash') AS [varbinary](256))
                    EXEC dbo.sp_hexadecimal @PWD_varbinary, @PWD_string OUT
                    EXEC dbo.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 = NCHAR(9) + N'CREATE LOGIN ' + QUOTENAME(@name) + N'
        WITH PASSWORD = ' + @PWD_string + N' HASHED
            ,SID = ' + @SID_string + N'
            ,DEFAULT_DATABASE = ' + QUOTENAME(@defaultdb) + N'
            ,DEFAULT_LANGUAGE = ' + QUOTENAME(@defaultlanguage)
    
                    IF @is_policy_checked IS NOT NULL
                    BEGIN
                        SET @tmpstr = @tmpstr + N'
            ,CHECK_POLICY = ' + @is_policy_checked
                    END
    
                    IF @is_expiration_checked IS NOT NULL
                    BEGIN
                        SET @tmpstr = @tmpstr + N'
            ,CHECK_EXPIRATION = ' + @is_expiration_checked
                    END
                END
                IF (@denylogin = 1)
                BEGIN -- login is denied access
                    SET @tmpstr = @tmpstr
                        + NCHAR(13) + NCHAR(10) + NCHAR(9) + N''
                        + NCHAR(13) + NCHAR(10) + NCHAR(9) + N'DENY CONNECT SQL TO ' + QUOTENAME(@name)
                END
                ELSE IF (@hasaccess = 0)
                BEGIN -- login exists but does not have access
                    SET @tmpstr = @tmpstr
                        + NCHAR(13) + NCHAR(10) + NCHAR(9) + N''
                        + NCHAR(13) + NCHAR(10) + NCHAR(9) + N'REVOKE CONNECT SQL TO ' + QUOTENAME(@name)
                END
                IF (@is_disabled = 1)
                BEGIN -- login is disabled
                    SET @tmpstr = @tmpstr
                        + NCHAR(13) + NCHAR(10) + NCHAR(9) + N''
                        + NCHAR(13) + NCHAR(10) + NCHAR(9) + N'ALTER LOGIN ' + QUOTENAME(@name) + N' DISABLE'
                END
                SET @Prefix =
                    NCHAR(13) + NCHAR(10) + NCHAR(9) + N''
                    + NCHAR(13) + NCHAR(10) + NCHAR(9) + N'EXEC [master].dbo.sp_addsrvrolemember @loginame = N'''
                SET @tmpstrRole = N''
                SELECT @tmpstrRole = @tmpstrRole
                    + CASE WHEN sysadmin = 1 THEN @Prefix + LoginName + N''', @rolename = N''sysadmin''' ELSE '' END
                    + CASE WHEN securityadmin = 1 THEN @Prefix + LoginName + N''', @rolename = N''securityadmin''' ELSE '' END
                    + CASE WHEN serveradmin = 1 THEN @Prefix + LoginName + N''', @rolename = N''serveradmin''' ELSE '' END
                    + CASE WHEN setupadmin = 1 THEN @Prefix + LoginName + N''', @rolename = N''setupadmin''' ELSE '' END
                    + CASE WHEN processadmin = 1 THEN @Prefix + LoginName + N''', @rolename = N''processadmin''' ELSE '' END
                    + CASE WHEN diskadmin = 1 THEN @Prefix + LoginName + N''', @rolename = N''diskadmin''' ELSE '' END
                    + CASE WHEN dbcreator = 1 THEN @Prefix + LoginName + N''', @rolename = N''dbcreator''' ELSE '' END
                    + CASE WHEN bulkadmin = 1 THEN @Prefix + LoginName + N''', @rolename = N''bulkadmin''' ELSE '' END
                FROM (
                    SELECT
                        SUSER_SNAME([sid])AS LoginName
                        ,sysadmin
                        ,securityadmin
                        ,serveradmin
                        ,setupadmin
                        ,processadmin
                        ,diskadmin
                        ,dbcreator
                        ,bulkadmin
                    FROM sys.syslogins
                    WHERE (    sysadmin <> 0
                            OR securityadmin <> 0
                            OR serveradmin <> 0
                            OR setupadmin <> 0
                            OR processadmin <> 0
                            OR diskadmin <> 0
                            OR dbcreator <> 0
                            OR bulkadmin <> 0
                            )
                        AND [name] = @name
                    ) L
                IF @tmpstr <> '' PRINT @tmpstr
                IF @tmpstrRole <> '' PRINT @tmpstrRole
                PRINT 'END'
            END
            FETCH NEXT FROM login_curs INTO @SID_varbinary,@name,@type,@is_disabled,@defaultdb,@hasaccess,@denylogin,@defaultlanguage
        END
        CLOSE login_curs
        DEALLOCATE login_curs
        RETURN 0
    END
    

    Note

    このスクリプトは、マスター データベースに 2 つのストアド プロシージャを作成します。 プロシージャの名前は sp_hexadecimalsp_help_revlogin です。

  2. SSMS クエリ エディターで、[結果からテキストへ] オプションを選択します。

  3. 同じクエリ ウィンドウまたは新しいクエリ ウィンドウで次のステートメントを実行します。

    EXEC sp_help_revlogin
    
  4. sp_help_revlogin ストアド プロシージャで生成される出力スクリプトは、ログイン スクリプトです。 このログイン スクリプトは、元のセキュリティ識別子 (SID) と元のパスワードでのログインを行います。

  5. 移行先サーバーでの手順の実装に進む前に、 Remarks セクションの情報を確認して従ってください。

  6. Remarks セクションから該当する手順を実装したら、任意のクライアント ツール (SSMS など) を使用して移行先サーバー B に接続します。

  7. サーバー A からの sp_helprevlogin の出力として生成されたスクリプトを実行します。

解説

サーバー B 上のインスタンスで出力スクリプトを実行する前に、次の情報を確認します。

パスワード ハッシュ情報

  • パスワードは、次の方法でハッシュされている可能性があります。

    • VERSION_SHA1: このハッシュは SHA1 アルゴリズムを使用して生成され、SQL Server 2000 から SQL Server 2008 R2 で使用されます。
    • VERSION_SHA2: このハッシュは SHA2 512 アルゴリズムを使用して生成され、SQL Server 2012 以降のバージョンで使用されます。
  • 出力スクリプトでは、暗号化されたパスワードを使用してログインが作成されます。 これは、CREATE LOGIN ステートメントのHASHED引数が原因です。 この引数は、 PASSWORD 引数の後に入力されたパスワードが既にハッシュされていることを指定します。

ドメインの変更を処理する方法

移行元サーバーと移行先サーバーは異なるドメインにありますか? 出力スクリプトを注意深く確認してください。 サーバー A とサーバー B が異なるドメインにある場合は、出力スクリプトを変更する必要があります。 次に、 CREATE LOGIN ステートメントで新しいドメイン名を使用して、元のドメイン名を置き換える必要があります。 新しいドメインでアクセスが許可されている統合ログインには、元のドメインのログインと同じ SID がありません。 そのため、ユーザーはこれらのログインを行えずに孤立します。 これらの孤立したユーザーを解決する方法の詳細については、「 孤立したユーザーをトラブルシューティングする (SQL Server)ALTER USER」を参照してください。

サーバー A とサーバー B が同じドメイン内にある場合は、同じ SID が使用されます。 そのため、ユーザーが孤立する可能性は低いです。

すべてのログインを表示および選択するためのアクセス許可

既定では、sysadmin 固定サーバー ロールのメンバーのみが sys.server_principals ビューから SELECT ステートメントを実行できます。 sysadmin 固定サーバー ロールのメンバーが必要なアクセス許可をユーザーに付与しない限り、ユーザーは出力スクリプトを作成または実行できません。

既定のデータベース設定はスクリプト化および転送されません

この記事の手順では、特定のログインの既定のデータベース情報は転送されません。 これは、既定のデータベースがサーバー B に常に存在するとは限らないためです。ログインの既定のデータベースを定義するには、ログイン名と既定のデータベースを引数として渡して、 ALTER LOGIN ステートメントを使用します。

移行元サーバーと移行先サーバー間で異なる並べ替え順序に対処する方法

ソース サーバーと移行先サーバーの並べ替え順序に違いがあるか、同じ場合があります。 各シナリオの対処方法を次に示します。

  • 大文字と小文字を区別しないサーバー A と大文字と小文字を区別するサーバー B: サーバー A の並べ替え順序では大文字と小文字が区別されず、サーバー B の並べ替え順序では大文字と小文字が区別される可能性があります。 この場合、ユーザーは、ログインとパスワードをサーバー B のインスタンスに転送した後、すべて大文字でパスワードを入力する必要があります。

  • 大文字と小文字を区別するサーバー A と大文字と小文字を区別しないサーバー B: サーバー A の並べ替え順序では大文字と小文字が区別され、サーバー B の並べ替え順序では大文字と小文字が区別されない場合があります。 この場合、ユーザーは、次のいずれかの条件に該当しない限り、サーバー B 上のインスタンスに転送するログインとパスワードを使用してログインすることはできません。

    • 元のパスワードには文字が含まれていない。
    • 元のパスワードのすべての文字は大文字です。
  • 両方のサーバーで大文字と小文字を区別するか、大文字と小文字を区別しない: サーバー A とサーバー B の両方の並べ替え順序で大文字と小文字が区別される場合や、サーバー A とサーバー B の両方の並べ替え順序で大文字と小文字が区別されない場合があります。 このような場合、ユーザーに問題はありません。

移行先サーバーに既に存在するログインに対処する方法

このスクリプトは、ログインが移行先サーバーに存在するかどうかを確認し、存在しない場合にのみログインを作成するように設計されています。 ただし、サーバー B のインスタンスで出力スクリプトを実行するときに次のエラー メッセージが表示される場合は、このセクションの手順に従って手動で解決する必要があります。

メッセージ 15025、レベル 16、状態 1、行 1
サーバー プリンシパル 'MyLogin' は既に存在します。

同様に、サーバー B のインスタンスに既に存在するログインには、出力スクリプトの SID と同じ SID がある場合があります。 この場合、サーバー B 上のインスタンスで出力スクリプトを実行すると、次のエラー メッセージが表示されます。

Msg 15433、レベル 16、状態 1、行 1 指定されたパラメータ sid は使用中です。

問題を手動で解決するには、次の手順に従います。

  1. 出力スクリプトを注意深く確認してください。
  2. サーバー B のインスタンスの sys.server_principals ビューの内容を調べます。
  3. 必要に応じて、これらのエラー メッセージに対処します。

SQL Server 2005 以降では、ログインの SID を使用してデータベース レベルのアクセスを管理します。 場合によっては、異なるデータベース内のユーザーにマップすると、ログインに異なる SID が割り当てられます。 この問題は、データベースが別のサーバーから手動で組み合わされている場合に発生する可能性があります。 このような場合、ログインは、データベース プリンシパルの SID が sys.server_principals ビューの SID と一致するデータベースにのみアクセスできます。 この問題を解決するには、 DROP USER ステートメントを使用して、SID が一致しないデータベース ユーザーを手動で削除します。 次に、 CREATE USER ステートメントを使用してユーザーをもう一度追加し、正しいログイン (サーバー プリンシパル) にマップします。

サーバーとデータベース プリンシパルを区別する方法の詳細については、CREATE USER および CREATE LOGIN を参照してください。

関連情報