Exchange Management Shell в Exchange 2010 запускается следующим скриптом (посмотреть можно в свойствах ярлыка):

... -command ". '.RemoteExchange.ps1'; Connect-ExchangeServer -auto"

Фактически при запуске шелла используется функция Connect-ExchangeServer с ключом auto. Сама функция описана в скрипте ConnectFunctions.ps1, который находится в папке с бинарными файлами (там же где и скрипт RemoteExchange.ps1). Ключ auto в свою очередь обращается к функции _AutoDiscoverAndConnect, которая описана в том же файле:

if ($Auto)
{
_AutoDiscoverAndConnect $credential $Forest -useWIA:$useWIA
}

Теперь самое интересное – при запуске этой функции мы используем функции, которые позволяют определить хост, на котором запускается скрипт, лес и структуру окружающих его сайтов с тем, чтобы подключить клиента к “ближайшему” серверу Exchange. Почему я написал “ближайший” в кавычках станет ясно в конце этой небольшой статьи. Итак, по порядку.

Хост получаем через функцию _GetHostFqdn примерно следующим образом:

[System.Net.Dns]::GetHostByName("LocalHost").HostName

Лес определяем через функцию _GetLocalForest:

[System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain().Forest.Name

Сайты ищем через функцию _GetSites. Функция эта фактически возвращает массив, состоящий из имён сайтов. Первый член массива – текущий сайт, в котором находится сервер, с которого мы запускаем EMS:

$localSite=[System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite()

Следующие – так называемые смежные сайты (AdjacentSites). Здесь мы берём все сайт-линки для нашего текущего сайта (фактически те, в которых он имеется в наличии) и вытаскиваем из них либо первый, либо второй сайт и добавляем его имя в наш массив. Выглядит это следующим образом:

if ($localSite.SiteLinks -ne $null)
{
foreach ($siteLink in $localSite.SiteLinks)
{
$siteDN = $null
# block going backwords
if (($siteLink.Sites[0] -ne $null) -and ($siteLink.Sites[0].Name -ne $localSite.Name))
{
$siteDN = $siteLink.Sites[0].GetDirectoryEntry().DistinguishedName
}
elseif ($siteLink.Sites[1] -ne $null)
{
$siteDN = $siteLink.Sites[1].GetDirectoryEntry().DistinguishedName
}
if ($siteDN -ne $null)
{
[void] $SiteList.Add($siteDN)
}
}
}

Ну и наконец, добавляем в массив символ *, которым будут обозначаться все остальные сайты, не попавшие в смежные сайты:

[void] $SiteList.Add("*")

Тут возникает первый момент, который пока мне остался непонятным. Если у нас сайт-линков несколько, то они попадают все в свойство SiteLinks нашего текущего сайта. Выглядеть это будет примерно так:

[PS] C:Windowssystem32>$localSite | fl SiteLinks

SiteLinks : {SITELINK1, SITELINK2, SITELINK3}

То есть фактически это будет массив. Как в нём группируются сайт-линки (в каком порядке перечисляются) – непонятно. А ведь от этого зависит какой сайт-линк будет обрабатываться первым, какой вторым итд. Аналогичный момент возникает с массивом сайтов в сайт-линке:

[PS] C:Windowssystem32>$localSite.SiteLinks[0] | fl Sites

Sites : {SITE1, SITE2, SITE3}

Сайтов обычно будет несколько, и в каком порядке они перечисляются тоже не совсем ясно.

Возвращаясь к нашей функции. После получения списка сайтов мы пробуем получить список серверов Exchange в каждом из них через функцию _GetExchangeServersInSite. Функция эта ищет все объекты класса msExchExchangeServer в сайте старше определённой версии. Например, для Exchange Server 2010 SP3 это будет выглядеть так:

$configNC=([ADSI]"LDAP:/$Forest/RootDse").configurationNamingContext
$search = new-object DirectoryServices.DirectorySearcher([ADSI]"LDAP:/$Forest/$configNC")
$search.Filter = "(&(objectClass=msExchExchangeServer)(versionNumber>=1937801568)
(msExchServerSite=$siteDN))"
$search.PageSize=1000
$search.PropertiesToLoad.Clear()
[void] $search.PropertiesToLoad.Add("msexchcurrentserverroles")
[void] $search.PropertiesToLoad.Add("networkaddress")
[void] $search.PropertiesToLoad.Add("serialnumber")
$search.FindAll()

И наконец со списком серверов доходим до функции _ConnectToAnyServer, которая и занимается созданием удалённого (через New-PSSession) подключения к первому доступному из списка серверу Exchange. Причём, сначала пытаемся подключаться к серверам с ролью CAS, затем ко всем остальным.

К чему я это веду. А к тому что, данная процедура не предусматривает оценки стоимости сайт-линков, а тупо перебирает доступные объекты. В итоге администратор удалённого сайта может попытаться подключаться к серверам Exchange, которые находятся совсем не в ближайшем к нему (по стоимости) сайте, а совсем даже на другой континент, например.

Это к слову о пользе правильной архитектуры сайтов AD.