В предыдущем посте я описал начальную настройку балансировщика KEMP VLM. Чтобы продолжить его настройку под Exchange 2010 необходимо сделать некоторые действия с сервером Exchange. А именно:

  • Создать во внутренней DNS-зоне a-запись для подключения клиентов.
  • Необходимо будет создать CAS Array.
  • Имеет смысл зафиксировать порты для сервисов MSExchangeRpc и MSExchangeAB.

Я в лабе использую так называемую 1-arm конфигурацию, то есть и клиенты и серверы находятся в одной сети и балансировщик использует один сетевой интерфейс. Общая конфигурация лабы следующая:

Сервер IP Роль
dc.o365lab.pro 192.168.1.10 DC,DNS,CA
ex1.o365lab.pro 192.168.1.50 CAS,HT,MBX
ex2.o365lab.pro 192.168.1.51 CAS,HT,MBX
lb1001.o365lab.pro 192.168.1.150 VLM

Для клиентского доступа я создам а-запись outlook в зоне o365lab.pro:

> outlook
Server:  dc.o365lab.pro
Address:  192.168.1.10

Name:    outlook.o365lab.pro
Address:  192.168.1.52

Следующий шаг – создание CAS Array:

New-ClientAccessArray -Name outlook -Fqdn outlook.o365lab.pro
-Site Default-First-Site-Name

Затем – фиксация портов для сервисов MSExchangeRpc и MSExchangeAB на всех серверах Exchange: Continue Reading »

Для балансировки нагрузки клиентских подключений Microsoft рекомендует в большинстве случаев использовать аппаратные балансировщики нагрузки. Компания KEMP Technologies помимо аппаратных так же производит виртуальные балансировщики нагрузки. Давайте посмотрим как их можно использовать с Exchange 2010, Exchange 2013 и с аналогичными версиями Lync Server.

Виртуальная машина для Hyper-V представляет собой файл жёсткого диска (vhd) и файл с конфигурационными настройками:

PS C:DistrLoadMaster-VLM-6.0-40CMa-Hyper-V> ls | ft Mode, Name -AutoSize
Mode  Name
----  ----
d---- Snapshots
d---- Virtual Hard Disks
d---- Virtual Machines
-a--- config.xml

Необходимо всё это импортировать на нужный нам хост Hyper-V. Небольшие рекомендации по импорту:

  • В процессе импорта необходимо выбрать копирование виртуальной машины (Copy the virtual machine (create a new unique ID)). Если из одного образа будем делать несколько балансировщиков, то стоит указать галку  Duplicate all files so the same virtual machine can be imported again.
  • MAC-адрес виртуальных адаптеров импортированного балансировщика должен быть статическим. Поэтому в свойствах адаптера переключаем MAC-адрес на Static и не забываем поставить галку Enable spoofing of MAC address. Код доступа, на основании которого генерируется лицензия, зависит от MAC-адреса виртуалки. Поэтому важно, чтобы он был статическим. Иначе, при переносе виртуалки на другой хост придётся получать лицензию заново.

После того как виртуалка будет импортирована и сетевые карты настроены, её нужно будет запустить и подождать пока она загрузится. Сначала она попытается получить адреса на сетевые интерфейсы через DHCP-сервер, а если такого не найдётся, то первый интерфейс получит принудительно адрес 192.168.1.101:

kemp1

После этого нужно будет подключиться к балансировщику через веб-интерфейс (https://192.168.1.101) или через консоль. Учётные данные для подключения:

  • Логин: bal
  • Пароль: 1fourall

Дальнейшие действия:

  • Меняем на интерфейсе eth0 ip-адрес (System Configuration → Interfaces → eth0)
  • При необходимости меняем имя хоста (System Configuration → Local DNS Configuration → Hostname Configuration)
  • Добавляем DNS-серверы (System Configuration → Local DNS Configuration → DNS Configuration)
  • При необходимости задаём используемый по умолчанию гейтвей (System Configuration → Route Management → Default Gateway)
  • Меняем пароль пользователя bal, добавляем других пользователей (System Configuration → System Administration → User Management)

На этом общую настройку балансировщика можно завершить.

Выступаем с Пашкой Нагаевым на ТехЭде 28 ноября. Будем показывать свои скромные изыскания в PowerShell относительно почтовых серверов. Так что приглашаю. Кто не сможет присутсвовать лично, можно смотреть онлайн.

Ну а завтра, 27 ноября, я буду делать краткий обзор новых технологий в новом SMB 3.0 в серверной зоне. Приглашаю обсудить данный вопрос в 12 часов на серверный стенд.

Ранее писал заметку про использование дополнительного компонента IIS – Application Request Routing. Для настройки полноценного RP для сервера Lync совершаем следующие дополнительные шаги:

  • В свойствах фермы в Routing Rules включаем параметр Use URL Rewrite to inspect incoming requests:

  • В настройках правила, созданного по умолчанию при создании фермы (ARR_FarmName_loadbalance) в Match URL вносим следуюший шаблон, не забывая переключиться на использование регулярных выражений (в выпадающем списке Using в Match URL выбираем Regular Expressions):
((?:dialin|meet|Fonts|Abs|Autodiscover|CertProv|ColabContent|GroupExpansion|
LMStaticData|Mcx|MeetingContent|MeetingFiles|Reach|RequestHandlerExt|RgsClients|
WebTicket).*)
  • В настройках правила, созданного по умолчанию при создании фермы (ARR_FarmName_loadbalance) в Action Properties в списке Scheme выбираем https://

Для публикации сервера Exchange можно использовать следующий шаблон:

((?:owa|OAB|Microsoft-Server-ActiveSync|EWS|ecp|Autodiscover).*)

Взято здесь.

Известно, что при необходимости, мы можем разрешить кому-либо отправлять письма от имени нужного почтового ящика. Для этого используется командлет Add-ADPermission:

Add-ADPermission "Mailbox" -User "DomainUser" -ExtendedRights "Send As"

Менее известно, что при наличии необходимых обновлений для Outlook 2003/2007/2010 становился доступен ключ DelegateSentItemsStyle в ветке реестра HKСUSoftwareMicrosoftOfficexx.0OutlookPreferences, который позволял при такой отправке помещать письма не в папку Sent Items отправляющего пользователя, а в папку Sent Items нужного почтового ящика.

И уж почти не известно, что с выходом Rollup Update 4 для Exchange 2010 SP2 появилась возможность управлять этим процессом с сервера, с помощью следующих командлетов Get-MailboxSentItemsConfiguration и Set-MailboxSentItemsConfiguration. Первый командлет выводит текущие настройки процесса обработки исходящих писем в случае отправки от чужого почтового ящика:

[PS] C:>Get-MailboxSentItemsConfiguration tempstas

RunspaceId                  : 537ce593-b8e1-4110-b99f-076e92f6f1d2
SendAsItemsCopiedTo         : Sender
SendOnBehalfOfItemsCopiedTo : Sender
Identity                    :
IsValid                     : True

С помощью командлета Set-MailboxSentItemsConfiguration мы можем значения этих параметров SendAsItemsCopiedTo и SendOnBehalfOfItemsCopiedTo поменять на SenderAndFrom. Эти параметры могут принимаать следующие значения:

  • Sender. Значение по умолчанию. Указывает на то, что при отправке от имени чужого почтового ящика письма будут попадать в папку Sent Items отправителя.
  • SenderAndFrom. Указывает на то, что при отправке от имени чужого почтового ящика письма будут попадать в папку Sent Items как отправителя письма, там и того ящика, от имени которого письмо отсылается.
  • From. Это особо секретный параметр. Пока, что его нет в документации и применять его не рекомендуется. При последующей доработке будет использоваться для размещения отправленного письма в папку Sent Items ящика от имени которого отправляем письмо. Но на текущий момент эффект от этого ключа такой же как и от SenderAndFrom.

Самое главное – оба эти командлета применяются к ящику, от имени которого необходимо будет отправлять письма. В дальнейшем, все, кто имеет права на отправку получат описанное выше поведение почтового клиента. Небольшая ложка дёгтя – при наличии на клиенте ключа DelegateSentItemsStyle имеющего значение 1 эти новые настройки срабатывать не будут.

Но и это ещё не всё! Доступ к этим настройкам имеется через OWA:

Написано на основе записи.

Задача – выгрузить список общих (с которыми работают несколько пользователей) ящиков Exchange 2010 с:

  • почтовыми адресами,
  • списком тех, у кого есть полный доступ на ящик,
  • менеджером,
  • размером ящика

Итоговый вывод примерно следующий будет:

"MailboxName1":"Email1":"FAUser1;FAUser2;":"Manager1":"MBSize1"
"MailboxName2":"Email2":"FAUser3;FAUser4;":"Manager2":"MBSize2"
....

Первые два столбца получаются через

Get-Mailbox -Database "Database" -ResultSize unlimited | Select DisplayName,
PrimarySmtpAddress

Мы предполагаем, что общие ящики находятся в одной базе, и кроме них в этой базе других ящиков (пользовательских) нет. Список пользователей, имеющих права доступа мы можем получить, используя командлет Get-MailboxPermission. Причём, нас интересуют только пользователи, которым Full Access дан непосредственно на сам общий ящик, а не на объект, находящийся выше по иерархии (то есть отфильтровываем наследуемые записи для которых параметр IsInherited принимает значение $true). Заодним убираем объект NT AUTHORITYSELF.

$tmpUsersPermissions = Get-Mailbox $_ | Get-MailboxPermission |
?{($_.IsInherited -eq $false) -and ($_.user -notlike "NT AUTHORITYSELF")} |
Select User

Далее массив получённых учётных записей надо “склеить”:

$UserPermissionString = "";
foreach ($UserPermission in $tmpUsersPermissions) {
     $UserPermissionString = $UserPermissionString + $UserPermission.User + "; "}

В итоге, в переменной $UserPermissionString окажется требуемый список пользователей с правами Full Access на ящик.

Следующий, интересующий нас объект – менеджер ящика (на самом деле учётной записи, к которой прикреплён ящик). Так как сам почтовый ящик уже помещён в переменную $_, то можно её использовать для того, чтобы вытащить через Get-User из параметра Manager учётную запись менеджера почтового ящика

(Get-User $_).Manager.Name

Аналогично, через Get-MailboxStatistics и переменную $_ получаем размер ящика. Для уменьшения количества цифр конвертируем его в мегабайты

($_ | Get-MailboxStatistics).TotalItemSize.Value.ToMB()

Теперь осталось всё собрать в одну строку и вывести в csv-файл. В итоге получается примерно следующая конструкция

Get-Mailbox -Database "Database" -ResultSize unlimited | Select DisplayName,
PrimarySmtpAddress,
@{Name="FullAccess";expression={
$tmpUsersPermissions = Get-Mailbox $_ | Get-MailboxPermission |
?{($_.IsInherited -eq $false) -and ($_.user -notlike "NT AUTHORITYSELF")} |
Select User;
$UserPermissionString = "";
foreach ($UserPermission in $tmpUsersPermissions) {
     $UserPermissionString = $UserPermissionString + $UserPermission.User + "; "};
$UserPermissionString;}},
@{Name="Manager";expression={(Get-User $_).Manager.Name}},
@{Name="MailboxSize";expression={
($_ | Get-MailboxStatistics).TotalItemSize.Value.ToMB()}} |
Export-Csv c:Tempmailboxes.txt -Delimiter :

В качестве разделителя использую “:”, так как стандартный разделитель “,” может встречаться в имени почтового ящика. Это может сильно испортить процесс дальнейшей обработки выходных данных.

Так как в заголовке указано, что данные предназначены для аудита, то список для выгрузки можно дополнить, например, списком тех у кого есть права на отсылку, или датой последнего изменения.

Некоторое время назад получил крайне экзотическую задачу – необходимо было посчитать число писем отправленных и полученных некоторой группой сотрудников за каждый день прошедшего месяца и вывести эту информацию в виде удобном для обработки. Так как необходимо посчитать число писем за определённый день, то необходимо использовать командлет  Get-MessageTrackingLog, причём считать будем только события “RECEIVE”. Письма, в которых сотрудник будет указан в получателях, считаются им полученными, в которых отправителем – отправленными (Капитан Очевидность умер от зависти). Данные можно поместить в две переменные $Received и $Sent:

# block1
$Received = Get-TransportServer | Get-MessageTrackingLog -ResultSize unlimited
-Start $TmpDate -End $TmpDate.AddDays(1) -EventId "RECEIVE" -Recipients $SMTP |
Measure-Object;

$Sent = Get-TransportServer | Get-MessageTrackingLog -ResultSize unlimited
-Start $TmpDate -End $TmpDate.AddDays(1) -EventId "RECEIVE" -Sender $SMTP |
Measure-Object;

Здесь в переменных $TmpDate будет находиться дата, на которую мы считаем письма, а в $SMTP – адрес конкретного сотрудника. Для удобства хранения полученной информации создадим новый объект, который будет хранить адрес сотрудника, указанную дату, число полученных и отправленных писем (спасибо Вадимсу Подансу за подсказку, как это можно сделать):

# block 2
$tmpObject = New-Object psobject -Property @{
smtp = $SMTP;
date = $TmpDate.ToShortDateString();
rcount = $Received.Count;
scount = $Sent.Count;  }

Осталось указанное выше завернуть в цикл и с шагом в один день, до тех пор, пока не упрёмся в последний нужный день посчитать письма:

$StartDate = Get-Date "01.01.2012";
$EndDate = $StartDate.AddMonths(1);
# block 3
$TmpDate = $StartDate;
While ($TmpDate -ne $EndDate) {
<block 1>
<block 2>
$TmpDate = $TmpDate.AddDays(1);
$tmpObject | select smtp, date, rcount, scount; }

Здесь $StartDate – дата, с которой начинаем считать (в эту переменную можно значение ввести через Get-Date, как это сделал я, можно через Read-Host, можно любым другим способом), $EndDate – дата, на которой заканчиваем считать письма (у меня она смещена на один месяц, по сравнению со $StartDate, но можно её указать любым другим способом). В конце собранные данные выводятся на экран, но вывод можно сделать в файл (File-Out, например).

Осталось теперь данные собрать по всем сотрудникам. Для этого их почтовые адреса передаём в переменную-массив и по каждому члену массива делаем обсчёт.

$SMTPs = "user1@domain.com", "user2@domain.com";
ForEach ($SMTP in $SMTPs) {
<block 3>; }

Почтовые адреса в переменную можно передать прямым списком (как написано у меня), можно импортировать из csv-файла через Import-Csv. Итоговый скрипт выглядит следующим образом:

$StartDate = Get-Date "01.05.2012";
$EndDate = $StartDate.AddMonths(1);
$SMTPs = "user1@domain.com", "user2@domain.com";
ForEach ($SMTP in $SMTPs) {
$TmpDate = $StartDate;
While ($TmpDate -ne $EndDate) {
$Received = Get-TransportServer | Get-MessageTrackingLog -ResultSize unlimited
-Start $TmpDate -End $TmpDate.AddDays(1) -EventId "RECEIVE" -Recipients $SMTP |
Measure-Object;

$Sent = Get-TransportServer | Get-MessageTrackingLog -ResultSize unlimited
-Start $TmpDate -End $TmpDate.AddDays(1) -EventId "RECEIVE" -Sender $SMTP |
Measure-Object;

$tmpObject = New-Object psobject -Property @{
smtp = $SMTP;
date = $TmpDate.ToShortDateString();
rcount = $Received.Count;
scount = $Sent.Count;  }
$TmpDate = $TmpDate.AddDays(1);
$tmpObject | select smtp, date, rcount, scount; } }

Есть одна тонкость, которую следует помнить – данные в логах по умолчанию хранятся за последние 30 дней. Поэтому, чтобы иметь возможность посчитать письма на более ранние даты необходимо срок хранения увеличить, например до 90 дней:

Set-TransportServer -Identity ServerName -MessageTrackingLogMaxAge 90.00:00:00

Недавно успешно завершился кейс с крайне странной проблемой, которая заключалась в следующем: после миграции почтового ящика пользователя с Exchange 2007 на Exchange 2010 клиент Lync перестал сохранять сообщения в папку Conversation History. При этом, все эти сообщения вполне успешно складировались в папку %user%AppDataLocalMicrosoftCommunicator%sip_address%History Spooler, но не пересылались в почтовый ящик.

В ходе борьбы с проблемой случайно выяснилось, что когда в ящике содержится чуть меньше тысячи папок, то сохранение истории разговоров начинает работать. При создании нескольких дополнительных папок (и при превышении порога в тысячу папок) сохранение перестаёт работать. Начинаем подозревать throttling policy. Политика throttling policy, применяемая по умолчанию ко всем почтовым ящикам, содержит интересный ключ EWSFindCountLimit, который равен 1000!

Дальнейшая операция создания и назначения новой throttling policy и задания в ней EWSFindCountLimit в NULL закрыло проблему. Скрипт следующий:

New-ThrottlingPolicy -Name "EWSFindCountLimit unlimited" -EWSFindCountLimit $null
Set-Mailbox -Identity UserName -ThrottlingPolicy "EWSFindCountLimit unlimited"

В процессе сохранения истории разговоров клиент Lync пробует использовать EWS. Если не получается использовать EWS, то используется MAPI. В процессе использования EWS, по всей видимости, используется функция FindFolder для перечисления папок ящика. Она как раз и возвращает значение, которое фильтруется параметром EWSFindCountLimit. Соответственно, при возвращаемом значении, которое больше тысячи, мы получаем ошибку и невозможность сохранять историю разговоров. Так ли это или нет, достоверно утверждать не могу, так как в открытых источниках отсутствует информация о том как клиент Lync через EWS сохраняет историю разговоров в папку Conversation History (либо я не смог найти эту информацию).

Дополнительные ссылки по проблеме:
Throttling Policies and the EWSFindCountLimit
Another fix for Lync Conversation History problems
Lync 2010 and Outlook 2010 cannot save conversation history

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

Версия Область технологий Воздействие Размер ящиков
Exchange 2000/2003 SAN и кластеры Рост количества пользователей 100MB
Exchange 2007 PKI и пространства имён Рост количества устройств и способов доступа 500MB
Exchange 2010 Балансировка и высокая доступность (CAS/ISA) BYOD – возможность подключения любых устройств пользователя 5GB
Exchange 2013 Выполнение требований законодательства, поиск данных, обработка больших массивов неструктурированных данных Тесная интеграция с  SharePoint и Lync 100GB

Комментарии:

  • Область технологий – то что требовалось хорошо знать при проектировании решений
  • Воздействие – те задачи/условия, которые повлияли на формирование области технологий
  • Размер ящиков – рекомендуемые ограничения по размерам почтовых ящиков пользователей
  • В оригинале область технологий для Ex2013 выглядит следующим образом – “Compliance, discovery, data mining”

Так что, добро пожаловать в эпоху взрывного роста данных и их интеллектуальной обработки.

Относительно недавно получил вопрос, вынесенный в заголовок. Известно, что при планировании конференции Lync мы получаем веб ссылку в формате https://meet.domain.com/User-name/ID. Она позволяет подключаться к конференции даже спустя несколько дней после её завершения. Но как долго она остаётся рабочей?

Чтобы немного освежить теорию, можно обратиться к замечательному ресурс-киту для Lync Server. А именно к четвёртой части – “Conferencing and Collaboration”. Процесс создания конференции выглядит следующим образом:

  1. The Online Meeting Add-in for Lync 2010 uses the
    Lync APIs and the Domain Name System (DNS) lookup or the manually configured server address to connect Outlook, through the Lync client, to the Focus Factory. The add-in then bundles the following information, required by the Focus Factory to create a conference, into a SIP SERVICE request:

    • The conference ID
    • A participant list
    • User role information
    • An expiration date
  2. The Focus Factory writes the following conferencing information to the conferencing database located in the Back End Server:
    • Conference ID
    • PSTN Meeting ID
    • Expiration date and time of conference
    • List of conference participant roles and the privileges associated with those roles
    • Conference key for participants without an identity in Active Directory® Domain Services (AD DS)
    • Supported media types
    • Authorization types (including locked, invited attendee, my company, and everyone)

The conferencing data is contained within two databases: RTC and RTCDyn. The information listed previously is stored in real-time communications (RTC).

Получается, что ссылка на встречу хранится не вечно, есть время окончания хранения. При этом само время не указано. Как его настраивать (и можно ли?) тоже непонятно. Экспериментальным путём, создавая разные типы конференций Lync и используя

dbanalyze /sqlserver:name /report:conf /user:sipid /conf:confid

можно получить данные по времени хранения для разных типов конференций. В базе RTC в таблице Conference есть замечательное поле ExpiringTime, в котором и хранится информация о том, когда данные конференции будут удалены из базы, что означает, что ссылка на конференцию станет нерабочей. Судя по информации из ресурс-кита для OCS эти цифры не поменялись и на текущий момент (для Lync Server) выглядят следующим образом:

  • For one-time scheduled conferences, set the expiration time to be the scheduled end time plus 14 days.
  • For recurring scheduled conferences with an end date, set the expiration time to be the scheduled end time of the last occurrence plus 14 days.
  • For recurring scheduled conferences without specified end dates, do not set an expiration time or set null as the expiration time.
  • For ad hoc IM or A/V conferences, set the expiration time to be eight hours.

То есть цифры эти жёстко прошиты в клиенте, который участвует в планировании конференции и изменить их по своему усмотрению мы не сможем.

Полезные ссылки:
Live Meeting: Best Before Date
Lync 2010 Conference ID Expirtation
OCS 2007 On-Premise Web Conferencing Meeting Expiration