Отчёт по событиям из календарей 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

10 способов внести свой вклад в PowerShell


Хорошая статья о том, как внести свой вклад в развитие проекта PowerShell https://joskw.gitbook.io/blog/powershell_contributing

Хоть и на английском, но читается легко. Рекомендую использовать как первое руководство, если у вас есть желание что-то исправить в самом PowerShell или документации.

Ожидаем PowerShell 7.0 RC2


После выхода в декабре 2019 года PowerShell 7.0 RC1 в январе 2020 ожидался выход окончательной версии.

Планы изменились. Сейчас выйдет RC2, а релиз в начале февраля. Причина банальна: неожиданно было получено много отзывов на RC1 и было сделано много мелких исправлений. Всё это должно быть проверено перед выпуском окончательной версии.

Не откладывайте на потом и пишите отзывы сейчас https://github.com/PowerShell/PowerShell/

Кстати посмотрите как растет использование PowerShell Core. Число запусков в месяц перевалило за 80 миллионов. Не так давно это число не превышало 20 миллионов. Большая часть запусков по-прежнему на Linux — более 70 миллионов. Ситуация должна измениться с выходом 7-й версии: большое количество Windows модулей работает на 7.0, и всё больше пользователей будут использовать PowerShell Core на Windows.

PowerShell Module Browser


А вы знаете, что есть такой сервис PowerShell Module Browser? Иногда полезно без установки модуля познакомиться с его возможностями.

Вышел PowerShell 7.0 Preview6


Вышла последняя предварительная версия PowerShell 7.0 перед RC, который ожидается через месяц.

Найти описание и дистрибудив можно по ссылке https://github.com/PowerShell/PowerShell/releases/tag/v7.0.0-preview.6

Как всегда множество исправлений и несколько новинок.

Появились новые операторы — null-conditional operators.

Обновился портированный Test-Connection. Теперь он более пригодный для использования, хотя проблемы ещё остались.

Запуск Windows PowerShell из PowerShell Core происходит более корректно (в смысле поиска и загрузки модулей).

Появился более удобный механизм использования несовместимых с PowerShell Core модулей — https://github.com/PowerShell/PowerShell/pull/10973 По сути создается «удаленная» сессия, в которой запущен Windows PowerShell. Это не решает всех проблем из-за сериализации, но это работает!

Как всегда улучшена производительность в некоторыз сценариях.

Командлет Select-String получил новый параметр Culture, который позволяет не только использовать правила конретного языка для поиска, но и выполнять самый быстрый бинарный поиск (Ordinal). Рекомендую попробовать.

Целый ряд непортированных командлетов добавлены обратно для лучшей совместимости скриптов с Windows PowerShell — Get-Counter, Get-ClipboardSet-Clipboard, Out-Printer, Clear-RecycleBin, Out-GridViewShow-Command и Get-Help -ShowWindow.

Не забываем про новый Get-Error, который постоянно улучшается.

И ещё много чего найдёте по ссылке.

Обновлённый Select-String


После долгой эпопеи (это тема для отдельного поста, но история ещё не закончилась) командлет Select-String получил новый параметр Culture.

По умолчанию Select-String использует значение CurrentCulture. Это подразумевает преобразования текста в соответствии с правилами текущего языка сессии. Что если нужно выполнить поиск в файле с другим языком? Ранее у нас не было выбора. Теперь можно указать конкретный язык.

Но не только. Языковые преобразования замедляют поиск. Многие утилиты предлагают самый быстрый вариант поиска — двоичный. Теперь это возможно в Select-String! Укажите параметр Culture со значением Ordinal. Попробуйте выполнить поиск в большом лог файле, и вы убедитесь, что это быстрее.

Помимо это теперь Select-String умеет выделять цветом найденные элементы в отображаемой строке. Это включено по умолчанию. Отключить можно параметром NoEmphasis.

Наступают последние дни когда можно внести изменения в PowerShell Core перед выходом релиза 7.0. Пробуйте последние предварительные сборки и пишите замечания.

PowerShell 7.0 Preview5


Начинаю привыкать писать PowerShell 7.0 без Core. Это уже официальное имя. Да и намерение Microsoft сделать этот продукт полноценной заменой Windows PowerShell 5.1 уже не выглядит фантастичным.

Чем же нас порадует и удивит очередная предварительная версия?

Прежде чем рассмотреть новшества, стоит отметить ближайшие планы. Очередная предварительная версия Preview6 выйдет в ноябре. Затем в декабре будет RC на базе .Net Core 3.1. И релиз в январе 2020 года. Это будет LTS версия, что означает поддержку в течение 3 лет. Как я уже писал, выпуски PowerShell будут следовать в русле версий .Net Core. Так .Net Core 3.1 является LTS версией, и, соответственно, PowerShell на её базе также будет LTS. Через пару лет выйдет .Net Core 5.0, которая по всей видимости заменит .Net Framework, и, соответственно, мы можем предположить, что PowerShell на её основе заменит Windows PowerShell.

Теперь о Preview5. Конечно в ней есть всё что появилось в предыдущих предварительных версиях, и об этом смотрите в предыдущих постах.

1. Get-Hotfix теперь снова работает, но только на Windows. Постепенно возвращаются командлеты, которые невозможно портировать. Ранее правило было жёстким: в PowerShell Core должны быть только портированные командлеты, т.е. только те, которые работают на всех поддерживаемых платформах. Но курс на замену Windows PowerShell гнёт в свою сторону.

2. Select-String научился делать выделение найденных фрагментов.

Пишите отзывы, пока есть время до релиза.

3. Операторы && и || для цепочек команд

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

4. Операторы ?? и ??=

Это так называемые Null-coalescing operators. Работают точно также как в языках программирования: вернуть значение переменной, если это не null, иначе правую часть.

5. IntelliSense работает для Enum типов и атрибутов (type constraints)

Попробуйте:

$ErrorActionPreference = <tab>

[ValidateSet(1, 2)][int]$a= <tab>

6. Format-Hex значительно улучшен. Разнородные объекты выводятся в более удобном виде. Примеры можно посмотреть тут.

7. Изменен формат вывода ошибок в консоли. Он стал более дружественным и лаконичным. Для вывода полной информации об ошибке теперь есть новый командлет Get-Error. Посмотрите, попробуйте и напишите отзывы, пока есть время до релиза.

ПопробуйтеЖ

1/0

Get-Error

8. При запуске интерактивной сессии вы теперь можете получить уведомление о наличии новой версии. Не знаю насколько это нужно. Оповещение можно отключить переменной окружения POWERSHELL_UPDATECHECK_OPTOUT = 0 или запустив pwsh -NoLogo.

9. PSReadLine 2.0.0-beta6

Скачивайте и работайте. Обратная связь.

10. Ternary Operator

Это оператор «?». Работает точно также как в языках программирования.

Попробуйте:

$IsWindows ? «Yes» : «No»

Полный список изменений в Release Notes