Powershell. Создание и выборка событий календаря Outlook
15 Dec 2016Предложил своему руководителю вести учет простоев объектов вместо Excel таблицы в общем календаре Outlook. А раз назвался груздем, то и полезай в кузов, нужно как-то реализовать предложение. Решением задачи стало написание двух скриптов на powershell.
Первый скрипт создает новое событие в общем календаре Outlook с нужными данными. Тема события формируется из номера объекта и описания события разделенных ';'. Место события и идентификатор общего календаря (в котором будут создаваться новые события) берутся из конфигурационного файла SBS-ATMEvents.conf. В форме ввода нового события есть автозавершение номера объекта (нужно заполнить файл SBS-ATMList.txt необходимыми значениями).
Второй скрипт делает выборку событий за период. Результатом работы скрипта будет объект, с которым можно работать дальше (сортировать, фильтровать и т.п.). Скрипту Get-ATMEvents.ps1 можно указать в качестве параметров начало и конец периода выборки событий, а если запустить без параметров, выйдет форма выбора дат.
Текст скрипта создания события в общем календаре Outlook:
New-ATMEvent.ps1
```powershell
<#
Скрипт создания события в общем календаре Outlook
03.11.2016 Сатин Павел
#>
#Следующая фигня перезапускает скрипт в однопоточном режиме. Только для дого, что-бы форме работал AutoComplete
if ([System.Threading.Thread]::CurrentThread.ApartmentState -eq [System.Threading.ApartmentState]::MTA)
{
powershell.exe -Sta -File $MyInvocation.MyCommand.Path
return
}
#Определяем путь от куда запущен скрипт
$Global:CurrPath = $MyInvocation.MyCommand.Definition | split-path -parent
#Загружаем переменные из конфигурационного файла
Get-Content "$Global:CurrPath\SBS-ATMEvents.conf" | ForEach-Object { $ExecutionContext.InvokeCommand.InvokeScript($_) }
#Заполняем список УС
$Global:FileListUS = "$Global:CurrPath\$Global:FileListUS"
$Global:ListUS = Get-Content $Global:FileListUS
function NewOutlookEvent {
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Новое событие УС"
$objForm.Size = New-Object System.Drawing.Size(300,240)
$objForm.StartPosition = "CenterScreen"
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,160)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$OKButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($OKButton)
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(150,160)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)
$objLabelStart = New-Object System.Windows.Forms.Label
$objLabelStart.Location = New-Object System.Drawing.Size(10,20)
$objLabelStart.Size = New-Object System.Drawing.Size(280,20)
$objLabelStart.Text = "Дата события:"
$objForm.Controls.Add($objLabelStart)
$datePicker = New-Object Windows.Forms.DateTimePicker
$datePicker.ShowUpDown = $false
#$datePicker.MinDate = $now
#$datePicker.MaxDate = $now.AddMonths(3); #arbitrary
#$datePicker.MaxSelectionCount = 1
$datePicker.Location = New-Object System.Drawing.Size(10,40)
$datePicker.Size = New-Object System.Drawing.Size(260,20)
#$datePicker.Width = 350
$datePicker.Format = "Custom"
$datePicker.CustomFormat = "dd.MM.yyyy HH:mm"
$datePicker.Enabled = $true
$objForm.Controls.Add($datePicker)
$objLabelUS = New-Object System.Windows.Forms.Label
$objLabelUS.Location = New-Object System.Drawing.Size(10,60)
$objLabelUS.Size = New-Object System.Drawing.Size(280,20)
$objLabelUS.Text = "Номер УС:"
$objForm.Controls.Add($objLabelUS)
$objComboBoxUS = New-Object System.Windows.Forms.ComboBox
$objComboBoxUS.Location = New-Object System.Drawing.Size(10,80)
$objComboBoxUS.Size = New-Object System.Drawing.Size(260,20)
#$objComboBoxUS.Height = 80
#Заполняем значения
$Global:ListUS | ForEach-Object {[void] $objComboBoxUS.Items.Add($_)}
$objComboBoxUS.Sorted = $true
$objComboBoxUS.AutoCompleteMode = [System.Windows.Forms.AutoCompleteMode]::SuggestAppend
$objComboBoxUS.AutoCompleteSource = [System.Windows.Forms.AutoCompleteSource]::ListItems
$objForm.Controls.Add($objComboBoxUS)
$objLabelDecr = New-Object System.Windows.Forms.Label
$objLabelDecr.Location = New-Object System.Drawing.Size(10,100)
$objLabelDecr.Size = New-Object System.Drawing.Size(280,20)
$objLabelDecr.Text = "Описание события:"
$objForm.Controls.Add($objLabelDecr)
$objEditBoxDescr = New-Object System.Windows.Forms.TextBox
$objEditBoxDescr.Location = New-Object System.Drawing.Size(10,120)
$objEditBoxDescr.Size = New-Object System.Drawing.Size(260,20)
$objForm.Controls.Add($objEditBoxDescr)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
$resultForm = $objForm.ShowDialog()
if ($resultForm -eq [System.Windows.Forms.DialogResult]::OK) {
$EventSubjectUS = $objComboBoxUS.Text
$EventSubjectDescr = $objEditBoxDescr.Text
Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace("MAPI")
$folder = $namespace.GetFolderFromID($olFolders)
$olAppointmentItem = 1
$appt = $folder.Items.Add($olAppointmentItem)
$appt.Start = $datePicker.Value
#$appt.Duration = 60
$appt.Subject = "$EventSubjectUS; $EventSubjectDescr"
#$appt.Body = "Meet with Scripting Guys to discuss upcoming plans."
$appt.Location = $aptLocation
#$appt.ReminderMinutesBeforeStart = 15
$appt.ReminderSet = $False
$result = $appt.Save()
}
} #End NewOutlookEvent
NewOutlookEvent
```
Текст скрипта выборки событий из общего календаря Outlook:
Get-ATMEvents.ps1
```powershell
<#
Скрипт выборки событий из общего календаря Outlook
03.11.2016 Сатин Павел
#>
#Определяем путь от куда запущен скрипт
$Global:CurrPath = $MyInvocation.MyCommand.Definition | split-path -parent
#Загружаем переменные из конфигурационного файла
Get-Content "$Global:CurrPath\SBS-ATMEvents.conf" | ForEach-Object { $ExecutionContext.InvokeCommand.InvokeScript($_) }
#$Global:ReportStart = [datetime]"11/01/2016"
#$Global:ReportEnd = [datetime]"11/07/2016"
Function FormDateQuery {
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Формирование отчета"
$objForm.Size = New-Object System.Drawing.Size(300,240)
$objForm.StartPosition = "CenterScreen"
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,160)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$OKButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($OKButton)
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(150,160)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)
$objLabelStart = New-Object System.Windows.Forms.Label
$objLabelStart.Location = New-Object System.Drawing.Size(10,20)
$objLabelStart.Size = New-Object System.Drawing.Size(280,20)
$objLabelStart.Text = "Дата события:"
$objForm.Controls.Add($objLabelStart)
$datePicker = New-Object Windows.Forms.DateTimePicker
$datePicker.ShowUpDown = $false
#$datePicker.MinDate = $now
#$datePicker.MaxDate = $now.AddMonths(3); #arbitrary
#$datePicker.MaxSelectionCount = 1
$datePicker.Location = New-Object System.Drawing.Size(10,40)
$datePicker.Size = New-Object System.Drawing.Size(260,20)
#$datePicker.Width = 350
$datePicker.Format = "Custom"
$datePicker.CustomFormat = "dd.MM.yyyy HH:mm"
$datePicker.Enabled = $true
$objForm.Controls.Add($datePicker)
$objLabelEnd = New-Object System.Windows.Forms.Label
$objLabelEnd.Location = New-Object System.Drawing.Size(10,60)
$objLabelEnd.Size = New-Object System.Drawing.Size(280,20)
$objLabelEnd.Text = "Дата события:"
$objForm.Controls.Add($objLabelEnd)
$datePickerEnd = New-Object Windows.Forms.DateTimePicker
$datePickerEnd.ShowUpDown = $false
#$datePickerEnd.MinDate = $now
#$datePickerEnd.MaxDate = $now.AddMonths(3); #arbitrary
#$datePickerEnd.MaxSelectionCount = 1
$datePickerEnd.Location = New-Object System.Drawing.Size(10,80)
$datePickerEnd.Size = New-Object System.Drawing.Size(260,20)
#$datePickerEnd.Width = 350
$datePickerEnd.Format = "Custom"
$datePickerEnd.CustomFormat = "dd.MM.yyyy HH:mm"
$datePickerEnd.Enabled = $true
$objForm.Controls.Add($datePickerEnd)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
$resultForm = $objForm.ShowDialog()
if ($resultForm -eq [System.Windows.Forms.DialogResult]::OK) {
$Global:ReportStart = $datePicker.Value
$Global:ReportEnd = $datePickerEnd.Value
}
} #End FormDateQuery
Function QueryATMEvents {
Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null
#$olFolders = "Microsoft.Office.Interop.Outlook.OlDefaultFolders" -as [type]
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace("MAPI")
$folder = $namespace.getFolderFromID($Global:olFolders)
$result = $folder.items | Select-Object -Property Start, End, Subject, Location |
where-object { $_.start -gt $Global:ReportStart -AND $_.start -lt $Global:ReportEnd } | Sort-object Start
if ($result -ne $null) {
$result | Add-Member -MemberType NoteProperty -Name NumberUS -Value ""
$result | Add-Member -MemberType NoteProperty -Name Description -Value ""
foreach ($reselement in $result) {
$DescStart = $reselement.Subject.IndexOf(";")
$DescLen = ($reselement.Subject.Length - $DescStart)
$NumUS = $reselement.Subject.Substring(0, $DescStart)
$Descr = ($reselement.Subject.Substring($DescStart + 1, $DescLen - 1)).TrimStart(" ")
#$reselement.Start = ($reselement.Start).Date
$reselement.NumberUS = $NumUS
$reselement.Description = $Descr
}
$result | Select-Object -Property Start, End, Location, NumberUS, Description
} else {
Write-Host "За указанный период событий не найдено!"
}
} #End QueryATMEvents
########################### Main #######################################
if ($args[0] -ne $Null) {
$Global:ReportStart = [datetime]$args[0]
if ($args[1] -ne $Null) {
$Global:ReportEnd = [datetime]$args[1]
} else {
$Global:ReportEnd = Get-Date
}
} else {
FormDateQuery
}
$ATMEvents = QueryATMEvents
#Выводим без даты окончания события, так как пока в ней нет необходимости
$ATMEvents | Select-Object -Property Start, Location, NumberUS, Description
```
Файл с глобальными переменными (SBS-ATMEvents.conf):
$Global:aptLocation = "Реж"
$Global:olFolders = "000000000915DBD13ED6B14DAB56DB9764896838010092FB4C91DAB48E43ABA83FB5301ECF250000011E80310000"
$Global:FileListUS = "SBS-ATMList.txt"
Пример файла со значениями выпадающего списка objComboBoxUS (SBS-ATMList.txt):
144300
84150
15309
800090
190097
Идентификатор папки Outlook можно узнать с помощью следующего кода, который открывает форму Oulook с выбором папки.
Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace("MAPI")
$f = $namespace.PickFolder()
Write-Host $f.EntryID