marcok2019
Goto Top

Public Folder - Kalender - Info bei Neuanlage und Änderung

Hallo zusammen,
ich habe einen Kalender im Public Folder.

Wenn ich hier einen neuen Termin eintrage oder verändere möchte ich an 3 bestimmte Personen eine Info zukommen lassen (per Mail).

Irgendwie finde keine so richtige Lösung.

Content-Key: 489792

Url: https://administrator.de/contentid/489792

Printed on: April 25, 2024 at 11:04 o'clock

Mitglied: 140913
140913 Aug 29, 2019 updated at 20:30:30 (UTC)
Goto Top
Member: colinardo
colinardo Aug 30, 2019, updated at May 05, 2021 at 12:10:53 (UTC)
Goto Top
Servus @MarcoK2019 , willkommen auf Administrator.de!

Etwas Powershell mit EWS und Streaming-Notification und ab geht die "Post".
Die benötigte DLL Microsoft.Exchange.WebServices.dll welche man sich aus dem Paket von hier herunterladen kann, mit ins Skriptverzeichnis legen, Variablen im Kopf anpassen und ausführen.
Das Skript überwacht die Create und Modify Events des Ordners per EWS-Streaming-Subscription und reagiert darauf mit einer Mail mit Details des Events an die definierten E-Mailadressen.
<#
    EWS Kalender mit Event-Subscription auf Änderungen (Created, Modified) überwachen und per Mail benachrichtigen
#>

# ===== START VARS =====
# EXCHANGE SERVER FQDN
$global:EXSERVER = 'exchange.domain.tld'  
# PFAD ZUM KALENDER
$global:PUBLICFOLDERCALENDARPATH = 'Testordner\Testkalender'  
# EMAIL ADRESSEN DIE BENACHRICHTIGUNGEN ERHALTEN
$global:NOTIFICATIONMAILADDRESSES = @('user1@domain.tld','user2@domain.tld','user3@domain.tld')  
# ===== END VARS =====

$global:CONNECTIONTIMEOUT = 30

if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return}    

# EWS DLL laden
Add-Type -Path "$PSScriptRoot\Microsoft.Exchange.WebServices.dll"  

Get-EventSubscriber | Unregister-Event -Force

# Allen Zertifikaten vertrauen
Add-Type @"  
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@  
# Trust all certs policy dem ServicePointManager zuweisen
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

function global:Generate-HTMLDataTable([object]$data,[string[]]$properties){
@"  
<div>
$(
foreach($itm in $data){
    "<table class=`"modern`" style=`"float:left`">`n"  
    $properties | %{
        "<tr><th>$($_)</th><td>$($itm.$_ -replace '\r\n','<br/>')</td></tr>`n"  
    }
    "</table>`n"  
}
)
<div style="clear:both;"></div>  
</div>
"@  
}

function Get-EWSFolder{
    param(
        [parameter(mandatory=$true)][Microsoft.Exchange.WebServices.Data.WellKnownFolderName]$storeroot,
        [parameter(mandatory=$false)][string]$path = "",  
        [parameter(mandatory=$true)][Microsoft.Exchange.WebServices.Data.ExchangeService]$service
    )
    # rekusiver Skriptblock zum Suchen eines Ordnerpfades
    $findfolder = {
        param(
            $id,
            [string]$subpath
        )
        if ($subpath -ne ""){  
            $parts = $subpath.Split("\")  
            $view = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1)
            $view.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Shallow
            $view.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
 
            $f = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$parts)
            $result = $service.FindFolders($id,$f,$view)
            
            if ($result.TotalCount -gt 0){
                if ($parts.Count -gt 1 ){
                    & $findfolder -id $result.Folders.Id -subpath $subpath.Split("\",2)[-1]  
                }else{
                    return $result.Folders
                }        
            }else{
                throw "Search returned no results for path subpart '$($parts)'."  
            }
        }else{
            return ([Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$id))
        }

    }
    return (& $findfolder -id $storeroot -subpath $path)
}


# EWS Objekt erstellen
$global:ews = new-object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2)
$global:ews.Url = "https://$global:EXSERVER/ews/exchange.asmx"  
# Benutze die Credentials mit dem das Skript ausgeführt wird
$global:ews.UseDefaultCredentials = $true

# Kalender Objekt ermitteln
$global:calendar = Get-EWSFolder -storeroot PublicFoldersRoot -path $global:PUBLICFOLDERCALENDARPATH -service $global:ews
# Wenn Kalender nicht gefunden wurde, beende Skript
if(!$global:calendar){
    throw "Pfad zum Kalender nicht gefunden!"  
    exit
}
# Streaming Subscription erstellen
$global:subscription = $global:ews.SubscribeToStreamingNotifications([Microsoft.Exchange.WebServices.Data.FolderId[]]($global:calendar.Id),[Microsoft.Exchange.WebServices.Data.EventType[]]('Created','Modified'))  
# connection object erstellen
$global:connection = New-Object Microsoft.Exchange.WebServices.Data.StreamingSubscriptionConnection($global:ews,$global:CONNECTIONTIMEOUT)

# Event das beim Erstellen/Ändern einer/mehrerer neuer Appointments/Meetings ausgeführt wird
Register-ObjectEvent $global:connection -EventName OnNotificationEvent -SourceIdentifier NewCalendarEvent -Action {
    # Alle Events verarbeiten
    $Event.SourceEventArgs.Events | ?{$_.ItemId -ne $null} | %{
        # Item-Details abrufen
        $item = $null
        try{
            $item = [Microsoft.Exchange.WebServices.Data.Item]::Bind($global:ews, $_.ItemId)
        }catch{}
        # wenn item existiert
        if($item -ne $null){
            # Log auf die Konsole
            write-host "Event-Typ: $($_.EventType)" -F Green  
            write-host ($item | fl Subject,DateTimeCreated,Start,End,Location,IsAllDayEvent,Duration | out-string)
            # Erstelle Benachrichtigungs-Mail
            $mail = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage $global:ews
            $mail.Subject = "Im Kalender '$($global:calendar.DisplayName)' wurde eine Änderung festgestellt."  
            $mail.Body =@"  
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
</head>
<body>
<style>
h1,h2,h3,h4,h5,h6 {
    clear:both;
}
body {
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size:0.9em;
}
table.modern {
	font-family: Verdana, Arial, Helvetica, sans-serif;
	border-collapse: collapse;
	border-left: 1px solid #ccc;
	border-top: 1px solid #ccc;
	color: #333;
    margin:5px;
}
table.modern tr th {
    font-weight: bold;
	text-align:left;
}
table.modern tfoot tr th, table.modern tfoot tr td {
	text-transform: uppercase;
	color: #000;
	font-weight: bold;
}
table.modern td, table.modern th {
	border-right: 1px solid #ccc;
	border-bottom: 1px solid #ccc;
	padding: 5px;
	line-height: 1.8em;
	font-size: 0.8em;
	vertical-align: top;
}
table.modern tr:nth-child(even) td,table.modern tr:nth-child(even) th { background: #efefef; }
</style>
<h3>Änderungstyp: $($_.EventType)</h3>
$(Generate-HTMLDataTable $item Subject,DateTimeCreated,Start,End,Location,IsAllDayEvent,Duration)
</body>
</html>
"@  
            # füge Empfänger hinzu
            $global:NOTIFICATIONMAILADDRESSES | %{
                $mail.ToRecipients.Add($_)
            }
            # Sende Mail
            $mail.Send()

        }
    }
} | out-null

# Event das beim Disconnect der Verbindung ausgeführt wird (Verbindung wird dann erneut hier wiederhergestellt)
Register-ObjectEvent $global:connection -EventName OnDisconnect -SourceIdentifier OnDisconnectNotification -Action {
    write-host "Subscription-Connection disconnected, restarting connection ... " -F Yellow -NoNewline  
    while(!$global:connection.IsOpen){
        $global:connection.Open()
    }
    write-host "Connected." -F Green  
}

# Subscription anlegen
$global:connection.AddSubscription($global:subscription)
# Subscription öffnen
$global:connection.Open()


write-host "Warte auf neue oder geänderte Items im Kalender ..." -F Green  
while($true){
    sleep 1
}
Grüße Uwe

Support gerne gegen Aufwandsentschädigung via PN.