Отчёт по событиям из календарей Outlook


Для управления рабочим временем (Time management) существует множество подходов и программных продуктов их поддерживающих.

Самое простое средство для планирования и управления рабочим временем это календари Outlook. Outlook обладает хорошими возможностями для управления рабочим временем (Time management) на базе календарей даже без всяких надстроек. Существует много статей и книг по этому вопросу.

Проблема в том, что календари ведутся автономно. А что если нужен ответ на простой вопрос: «Насколько много сотрудники неоправдано отвлекаются на совещания?». Неужели для этого придется закупать bи внедрять систему Time management и настраивать систему отчётов?

Посмотрим как можно собрать информацию из календарей пользователей, используя Exchange Server API.

Во-первых, нам нужна учётная запись, которая будет формировать отчёт. Этой учётной записи нужны права доступа ко всем календарям. Как их предоставить? Можно назначить права доступа командлетом или захватить права на почтовую базу (в стиле Exchange Server 2003). Самый правильный подход — использовать RBAC. Нам нужна имперсонализация:

New-ManagementRoleAssignment -Role ApplicationImpersonation -User <имя нашей учётки>

Разновидностей отчётов может быть бесконечное множество. Поэтому мы запустим PowerShell от имени учётой записи, для которой мы настроили имперсонализацию, и выгрузим все события из всех календарей со всеми свойствами в файл в CSV формате. Затем эту информацию можно загрузить в базу данных или Excel для анализа.

$StartDate = Get-Date 1/1/2020
$EndDate = Get-Date 1/31/2020

# Исправьте этот путь для вашей версии Exchange Server
# Это вообще не нужно для EWS
Add-Type -Path "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Microsoft.Exchange.WebServices.Auth.dll"
$Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1)

$result = Get-MailBox -ResultSize Unlimited | ForEach-Object {

  $SmtpAddress = $_.PrimarySmtpAddress.Address

  Write-Host "MailBox: $SmtpAddress"

  $Service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $SmtpAddress);

  [void]$Service.AutodiscoverUrl($SmtpAddress)

  # Bind to the calendar folder of the mailbox
  $FolderId = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar,$SmtpAddress)
  $Calendar = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service,$FolderId)

  # Define the calendar view
  $CalendarView = New-Object Microsoft.Exchange.WebServices.Data.CalendarView($StartDate,$EndDate)
  $Calendarview.MaxItemsReturned = 1000 	# 1000 is the maximum number of items that can be returned in a CalendarView

  $AppointmentItems = @()
  $AppointmentItems = $Service.FindAppointments($Calendar.Id,$CalendarView)

  if ($AppointmentItems.TotalCount -eq 0)
  {
      #Write-Host "MailBox: $SmtpAddress : AppointmentItems is empty."
      #return;
  } 

  $properties = New-Object Microsoft.Exchange.WebServices.Data.PropertySet(
      [Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties,
      [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::RequiredAttendees,
      [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::OptionalAttendees);

  $res = $service.LoadPropertiesForItems($AppointmentItems, $properties)
  $service.LoadPropertiesForItems($AppointmentItems, $properties)

} | Select-Object -ExpandProperty Item -Property @{name="User"; expression={ $SmtpAddress }},@{name="Count"; expression={ CountMembers $_ }} |
    Select-Object -Property * -ExcludeProperty Body |
    Export-CSV -Path all_items.csv -NoTypeInformation

function CountMembers ($item) {
    $count = 0

    $item.Item.RequiredAttendees |
        ForEach-Object {
           $count += if ($_.MailboxType -eq "PublicGroup") { (Get-ADGroup -Identity $_.Name -Properties members).Members.Count } else { 1 }
        }

    $item.Item.OptionalAttendees |
        ForEach-Object {
           $count += if ($_.MailboxType -eq "PublicGroup") { (Get-ADGroup -Identity $_.Name -Properties members).Members.Count } else { 1 }
        }

    return $count
}

Как бонус скрипт подсчитывает число участников собраний.

Я не буду описывать, как создать какой-то конкретный отчёт в Excel на основе этой информации — это не благодарное дело. Используя фильтры Excel, вы можете найти организаторов собраний, выделить собрания по уникальному идентификтору, вычислить длительность собраний, построить сравнительные графики рабочего времени и много чего ещё.

Для полноты картины вы можете добавить информацию о пользователях из Active Directory (или другой системы). Тогда вы сможете делать анализ, например, по подразделениям.

Полезные ссылки:

  1. New-ManagementRoleAssignment
  2. Configure impersonation
  3. Auditing Exchange Rooms for Double Bookings
  4. Create appointments and meetings by using EWS in Exchange 2013

AppLocker и CRL


Проверка списков отзыва сертификатов (CRL) полезная вещь позволяющая нам избежать взаимодействия с системами, у которых скомпрометирован сертификат.

Со временем политика использования сертификатов на Windows системах ужесточается. Мы все ощутили это в то время, когда RDP клиент на Windows 7 начал делать жесткие проверки сертификатов. Многие инфраструктуры пришлось тогда подчистить и подправить, чтобы пользователи не испытывали проблем с подключениями к удаленным рабочим столам.

Проверки CRL также могут вызывать проблемы — в виде задержек. Это уже было в нашем опыте с Sharepoint и Exchange серверами. Собственно это все тот же CAPI.

На днях выяснилось, что этой проблеме подвержен AppLocker. Оказывается, даже если он выключен, он всё равно работает где-то в недрах системы, пытается что-то проверять и даже провоцирует проверки сертификатов и CRL. А уж если он включен, и настроены правила Publisher, то и подавно.

Это имеет один неожиданный побочный эффект. Собственно так это и было обнаружено. Суть в том, что PowerShell имеет встроенную поддержку AppLocker, т.е. делает специальные вызовы API, чтобы проверить можно ли запускать тот или иной скрипт. Побочный эффект в том, что из-за проверок CRL в AppLocker PowerShell может работать медленнее: задержка запуска, задержки при загрузке модулей, задержки при выполнении скриптов.

Надо отметить, что эта проблема чаще всего возникает в изолированных сетях. Но иной раз и в сетях, которые просто неправильно сконфигурированы (фаервол и, особенно, DNS).

Неправильно сконфигурированные сети надо лечить.

Рекомендация для изолированных сетей простая: групповыми политиками уменьшить тайм-аут проверки CRL.

Ссылки:

Рекомендация отсюда

Обсуждение PowerShell

Exchange Server 2013 Extended Support


На днях вышло последнее кумулятивное обновление для Exchange Server 2013 — CU21. Exchange Server 2013 переходит в фазу расширенной поддержки с 19 сентября 2018 (хотя фактически уже сейчас). Это означает, что обновлений функциональности (кумулятивных обновлений) больше выпускаться не будет — только обновления безопасности.  Хотя Майкрософт говорит, что может выпускать ещё и обновления для совместимости с Office 365.

Полезные ссылки:

  1. https://blogs.technet.microsoft.com/exchange/2018/06/19/released-june-2018-quarterly-exchange-updates/
  2. https://blogs.technet.microsoft.com/exchange/2018/04/10/exchange-server-2013-enters-extended-support-lifecycle-phase/

Лабиринт обновлений Exchange Server


Microsoft регулярно выпускает обновления для Exchange Server 2013/2016 в виде кумулятивных пакетов. Каждый из этих пакетов требует определенные версии .Net, с которыми он совместим. Все это превращает процесс обновления Exchange Server со старых версий до последних в нетривиальную задачу: надо сначала поставить определенную версию CU, потом только можно обновить .Net, и только затем ставить ещё более новую версию CU…

Чтобы не ломать голову, используйте статью Upgrade Paths for CU’s & .NET с картинками :-)

Почему надо активировать почтовый ящик административной учётной записи Exchange Server


Рубрика «Хозяйке на заметку». В Active Directory мы часто создаём специальные учётные для выполнения тех или иных административных задач. Это работает. В Exchange Server 2013/2016 мы поступаем также, только учётная запись должна иметь почтовый ящик. И это может не работать в некоторых сценариях управления. Почему? Потому что надо создать почтовый ящик не только формально (Enable-Mailbox), но и фактически, для чего в него надо зайти хотя бы один раз.

Почему продукты на базе управляемого кода могут стать эффективнее


В скором времени в публичных версиях C# появятся две новые конструкции языка Span<T> и Memory<T>. Это может оказать заметное позитивное влияние на PowerShell и Exchange Server (как впрочем и на другие продукты написание на управляемом коде (managed code)). Читать далее

Как поломать Autodiscover безобидной настройкой


Сегодня с коллегой разбирались с некой проблемой на Exchange Server 2013 и попутно увидели в логах предупреждение за номером Event ID:2002 «The number of outstanding requests for guard TargetBackend («») has exceeded the max limit 150. Current request will be rejected.» На фронтендах добавили в web.config строчку <add key=”HttpProxy.ConcurrencyGuards.TargetBackendLimit” value=”2000″ />. Предупреждение ушло. Когда разобрались с основной проблемой, эта настройка осталась в конфиге.

Через некоторое время пользователи пожаловались, что не работает почта (клиенты) снаружи из Интернет. Проверка на https://testconnectivity.microsoft.com показала, что сломался autodiscover. Снаружи. Внутри работает. Перебрали всю цепочку — все в норме, но проблема есть. Коллега подключился из браузера по линку /Microsoft-Server-ActiveSync/, и среди прочей информации мы с удивлением обнаружили  выше упомянутую строчку подсвеченную красным! Убрали из конфигов — autodiscover снаружи ожил.

Отличие Autodiscover внутри и снаружи — внутри аутентификация Windows, снаружи — Basic. Как это все связано непонятно.

Вот такая забавная ситуация. Если будете менять стандартные конфиги, будьте готовы, что разные сервисы могут отнестись к этому по-разному.