Как удаленно обнаружить экземпляры SQL Server на машине? Часть IV

Содержание предыдущей серии.

Базовым способом получения информации об экземплярах SQL Server на удаленной машине является получить к ней доступ и осмотреть имеющиеся там сервисы или залезть в реестр, что предпочтительнее, т.к. из него можно вытянуть более полную информацию. Открывать удаленный доступ к реестру кому ни попадя не есть хорошо, как справедливо заметил Олег в комментариях, поэтому производным способом является посадить на машину своего агента, своего рода. посредника, который соберет на ней интересующую нас информацию, и общаться впоследствии снаружи только с ним. Ярким примером такого посредника может выступать SQL Browser Service, который является встроенным функционалом SQL Server. Производители другого ПО могут насаждать своих агентов, например, для задач инвентаризации. Не менее яркий пример – System Center. Кроме того, существуют вспомогательные средства .NET и готовые утилиты, решающие сабж. В большинстве своем они основываются на базовых методах и службе SQL Browser. Друг Гарри в комментариях к первой части уже предлагал одно из таких средств -

SqlDataSourceEnumerator в ADO.NET.

SqlDataSourceEnumerator является классом в пространстве имен System.Data.Sql и обладает единственным значимым методом GetDataSources, который обнаруживает экземпляры SQL Server и возвращает информацию о них в виде DataTable с полями ServerName, InstanceName, IsClustered и Version. Значения этих полей SqlDataSourceEnumerator берет, очевидно, от службы SQL Browser. Мы видели этот список на Рис.11 предыдущего поста.

Неудобством является невозможность ограничить диапазон поиска на какую-то конкретную машину или несколько машин. Таймаута тоже выставлять нельзя. Метод GetDataSources() не принимает никаких параметров. Он тупо ищет по всему диапазону, до которого может дотянуться броадкастом, в связи с чем в документации содержится предупреждение: «Содержимое списка может изменяться в зависимости от таких факторов, как время ожидания и сетевой трафик.Это может привести к тому, что при двух последовательных вызовах будут получены разные списки.В список входят только серверы, находящиеся в одной сети.Широковещательные пакеты обычно не проходят через маршрутизаторы, поэтому некоторый сервер может отсутствовать в списке, но будет стабильно работать». Как мы понимаем из предыдущего поста, это означает, что он шлет пакеты CLNT_BCAST_EX. Пример обнаружения:

[System.Data.DataTable] $revealedInstances = [System.Data.Sql.SqlDataSourceEnumerator]::Instance.GetDataSources() 
$revealedInstances | Sort-Object -Property InstanceName

Скрипт 1

В данном случае исходящий файрвол (на машине, откуда обнаруживаем) должен пропускать броадкасты. Если на входящих машинах поднята служба SQL Browser и открыт на вход порт UDP 1434, мы увидим следующую картину:

Рис. 1

После того, как я закрыл на w7x86sql08r2 порт UDP 1434 на вход, SqlDataSourceEnumerator перестал обнаруживать экземпляры с этой машины:

Рис. 2

Это странно. Я ожидал, что если SQL Browser на машине недоступна, то SqlDataSourceEnumerator попытается получить с нее хотя бы имена экземпляров, тем более, что в документации сказано: «Сведения о серверах из списка могут включать или не включать такие дополнительные данные, как IsClustered и версия.Это зависит от того, каким образом был получен список.В списках серверов, полученных с помощью службы обозревателя SQL Server, присутствует больше сведений, чем в списках серверов, найденных с помощью инфраструктуры Windows и содержащих только имена». Все дырки для WMI на машине w7x86sql08r2 оставлены, и способ, который мы, например, разбирали в 1-й части, прекрасно работает. Имена экземпляров с нее достать можно:

Рис. 3

Тем не менее SqlDataSourceEnumerator не хочет ничего показывать. Поэтому, что в документации понимается под «инфраструктурой Windows» , я не знаю.

EnumAvailableSqlServers() в SMO.

Наиболее существенная разница между SmoApplication.EnumAvailableSqlServers() и SqlDataSourceEnumerator.GetDataSources(), на мой взгляд, состоит в том, что SqlDataSourceEnumerator доступен непосредственно в .NET Framework, а для EnumAvailableSqlServers надо ставить библиотеку SQL Management Objects (SMO). SMO ставится вместе с SQL Server, а отдельно их надо брать из Feature Pack’a. Они там называются Shared Management Objects, короче, это то, что лежит перед ADOMD.NET.

Кроме того, метод EnumAvailableSqlServers() имеет параметр. Если параметром является boolean, то в случае true он показывает только экземпляры SQL Server на локальной машине, в случае false – ищет броадкастом по сети. Если параметр строковый, то ищет только на машине с таким именем. Вызов без параметра эквивалентен параметру false.

Пример обнаружения:

[Void] [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") 
[System.Data.DataTable] $revealedInstances = [Microsoft.SqlServer.Management.Smo.SmoApplication]::EnumAvailableSqlServers("w7x86sql08r2") 
$revealedInstances | Sort-Object -Property Instance

Скрипт 2

У EnumAvailableSqlServers() наблюдается такое же поведение, как у SqlDataSourceEnumerator – все работает замечательно, пока снаружи доступен SQL Browser. Однако есть нюанс: Скрипт 2 упорно не желает показывать именованный инстанс SQL Server Express на машине w7x86sql08r2:

Рис. 4

Если изменить параметр метода с названия машины на $false, т.е. показывать экземпляры по всем машинам, до которых удается достучаться броадкастом, SQLEXPRESS, как по волшебству, появляется:

Рис. 5

Параметр $true означает показать установленные экземпляры с локальной машины. В моем случае их нет:

Рис. 6

Когда руками ничего писать неохота, а узнать, что за SQL Serverы в округе, очень надо, можно взять готовую утилиту. Их существует безбрежное море, как производства Microsoft, так и независимых производителей, и разбирать каждую в отдельности я, с вашего позволения, не буду. Иначе тема, которую первоначально предполагалось уложить в один пост, не закончится никогда. В качестве примеров можно привести: производства Microsoft – это всем хорошо известная тула sqlcmd. sqlcmd.exe предназначена для работы с SQL Server из командной строки. Как и SMO, она ставится в составе SQL Server и так же может быть скачана отдельно из состава Feature Pack (cм. Microsoft® SQL Server® 2008 R2 Command Line Utilities). Помимо прочего, у нее есть ключ –L, который означает list servers. Это поведение построено по принципу броадкаста. В качестве примера производства независимых поставщиков - SQLPing. Ее пишет Chip Andrews и традиционно выкладывает на sqlsecurity.com. Последней на данный момент в там выложена версия 3. Первоначально она тоже использовала службу SQL Browser, но сейчас по заверениям в ней зашито восемь различных способов обнаружения. Она может сканировать диапазон IP-адресов и не только обнаруживать экземпляры, но и пытаться соединиться с ними c использованием списка паролей для получения более подробной информации @@version.

Автор: Алексей Шуленин