Во время миграции баз данных SQL Server 2012 из ранее используемого кластерного экземпляра SQL Server на физических серверах в новый кластерный экземпляр в виртуальной среде Hyper-V столкнулся с одной интересной проблемой. Сразу скажу, что она никак не связана ни с Hyper-V, ни с виртуализацией в целом, а скорее с простым незнанием некоторых аспектов работы SQL Server.
При копировании баз данных была предпринята попытка использования мастера копирования баз (Copy Database Wizard), который доступен нам в составе SQL Server Management Studio по аналогии с ранее описанной процедурой. Процедура копирования контентной базы данных одного из веб-приложений SharePoint и связанных с ней SQL-логинов была прервана с ошибкой, говорящей о том, что один из SQL-логинов невозможно найти в домене. Выяснилось, что этот SQL-логин когда-то ранее было создан на SQL Server с привязкой к существующей на тот момент доменной учетной записи пользователя, однако на текущий момент учётной записи с таким именем в домене действительно нет. Это подтвердил также и вывод хранимой процедуры sp_validatelogins, которая умеет обнаруживать “осиротевшие” SQL-логины:
EXEC sp_validatelogins; GO
В нашем примере проблемный SQL-логин имел имя KOM\s-KOM-SP-ORD. Соответственно этому SQL-логину ранее и были права необходимые для работы с контентной базой данных веб-приложения SharePoint, но вместе с этим само веб-приложение в SharePoint на текущий момент времени работало от имени совершенно другой учетной записи – KOM\s-KOM-SP-IRS. Это ввело меня в некоторый ступор. Как такое вообще возможно… И пока до меня не “дошло”, в чём же на самом деле заключается проблема, выполнялись разного рода манипуляции. Например, будучи уверенным в том, что учетной записи веб-приложения таки нужен доступ к его контентной базе данных SharePoint, я попытался добавить в SQL Server новый SQL-логин - KOM\s-KOM-SP-IRS. Но в ответ получил странное сообщение о том, что такой логин в SQL Server уже присутствует…
Create failed for Login 'XXX\XXX'. (Microsoft.SqlServer.Smo) ... The server principal 'XXX\XXX' already exists. (Microsoft SQL Server, Error: 15025)
Но как? Ведь я не вижу этого логина в консоли…
И тут меня осенило, что скорее всего, нынешняя доменная учетная запись KOM\s-KOM-SP-IRS это и есть учётная запись KOM\s-KOM-SP-ORD, просто переименованная в домене после того, как в SQL Server был создан сопряжённый с ней SQL-логин. Чтобы проверить это предположение, нужно было выяснить доменный идентификатор безопасности (SID) хранимый в SQL Server для SQL-логина KOM\s-KOM-SP-ORD и сравнить его с SID пользователя KOM\s-KOM-SP-IRS в домене на данный момент. Новой сложностью стало то, что SQL Server возвращает значение SID в формате VARBINARY(85), а в домене оно хранится в другом формате.
Выполнить преобразование полученного из SQL Server значения SID в формат аналогичный атрибуту objectSid для учетных записей в домене Active Directory помог SQL-скрипт из статьи Help: SQL Server - SQL Internals - How to map login SID to domain account?, за что её автору большое спасибо…
DECLARE @varBinarySID VARBINARY(85) -- в переменной varBinarySID указываем значение SID в формате varbinary(85) SELECT @varBinarySID = 0x010500000000000515000000685889B0E3259CD7E0ED9A5545030300 DECLARE @StringSID VARCHAR(100) DECLARE @len AS INT SET @len = LEN(@varBinarySID) DECLARE @loop AS INT SELECT @StringSID = 'S-' SELECT @StringSID = @StringSID + CONVERT(VARCHAR, CONVERT(INT, CONVERT(VARBINARY, SUBSTRING(@varBinarySID, 1, 1)))) SELECT @StringSID = @StringSID + '-' SELECT @StringSID = @StringSID + CONVERT(VARCHAR, CONVERT(INT, CONVERT(VARBINARY, SUBSTRING(@varBinarySID, 3, 6)))) SET @loop = 9 WHILE @loop < @len BEGIN DECLARE @temp_var BINARY (4) SELECT @temp_var = SUBSTRING(@varBinarySID, @loop, 4) SELECT @StringSID = @StringSID + '-' + CONVERT(VARCHAR, CONVERT(BIGINT, CONVERT(VARBINARY, REVERSE(CONVERT(VARBINARY, @temp_var))))) SET @loop = @loop + 4 END SELECT @StringSID 'String SID'
Итак, значение objectSid в более привычном формате получено и теперь всё что остаётся сделать, это сравнить это значение с учетной записью KOM\s-KOM-SP-IRS. Методов для этого много разных, как один из самых простых и быстрых воспользоваться обратным преобразованием SID в имя с помощью утилиты Марка Руссиновича - Psgetsid
Получается, что действительно, SQL-логин KOM\s-KOM-SP-ORD имеет привязку к доменному SID учетной записи KOM\s-KOM-SP-IRS. Как я уже и сказал, такая ситуация возможна в случае если в домене учетная запись была переименована после создания соответствующего логина в SQL Server. Теперь, чтобы окончательно поставить всё на свои места осталось только переименовать SQL-логин в актуальное для доменной учетной записи имя.
Великолепно! Очень помогло - спасибо.