Wir suchten nach einer Möglichkeit bestimmte Kalendereinträge von unterschiedlichen Personen mit einem SharePoint Kalender zu synchronisieren. Wie wir das ganze gelöst haben und auf was man achten muss und welche Probleme es dabei gegeben hat, erfahrt ihr in diesem Blogbeitrag.

Anforderung

  • Synchronisieren von bestimmten Kalendereinträgen unterschiedlicher Personen mit einem SharePoint Kalender.
  • Synchronisieren der Termine von den letzten X-Wochen und den kommenden Y-Wochen.

Umsetzung

Da die Einträge alle 2 Stunden synchronisiert werden sollen, haben wir uns dazu entschieden es mit einem PowerShell Skript umzusetzen. Um herauszufinden welche Termine synchronisiert werden sollen, gibt es 2 Möglichkeiten:

  • Termine mit Kategorien versehen (Jeder User muss sich die Kategorien selbst anlegen)
  • Termine mit einem bestimmten Präfix synchronisieren

Wir haben uns für Möglichkeit 1. Entschieden, da man so nur einmal die Kategorien anlegen muss. Dadurch fallen mögliche Fehler durch falsche Präfixe und Tippfehler weg. Die Farbe der Kategorie spielt dabei keine Rolle. Ein Nachteil hierbei ist, dass es keine Möglichkeit gibt, den User davon abzuhalten Kategorien zu bearbeiten bzw. zu löschen.

Die Kalendereinträge inklusive Kategorien, werden mittels EWS ausgelesen.

Zuerst müssen deren Kalender synchronisiert werden soll aus der AD-Gruppe ausgelesen werden.

$identities = Get-ADGroupMember Outlooktermine_Mitarbeiter -Recursive | Get-ADUser -Properties * | Select-Object Mail

Nun müssen alle SPItems aus dem Kalender gelöscht werden, bei denen das Startdatum zwischen dem angegebenen Start und Enddatum liegt.

#*************************************
# Get calendar and items
#*************************************
$cal = $web.lists.getbytitle('Name of your Sharepoint calendar here')
$ctx.load($cal)
$ctx.ExecuteQuery()
$query = "<Query>
  <Where>
    <And>
      <Geq>
        <FieldRef Name='EventDate' />
          <Value IncludeTimeValue='TRUE' Type='DateTime'>" + $startDate + "</Value>
      </Geq>
      <Leq>
        <FieldRef Name='EndDate' />
        <Value IncludeTimeValue='TRUE' Type='DateTime'>" + $endDate + "</Value>
      </Leq>
    </And>
  </Where>
</Query>"

$items = [Microsoft.SharePoint.Client.ListItemCollection]$cal.GetItems($query)
$ctx.load($items)
$ctx.ExecuteQuery()

Als nächstes geht man jeden Benutzer der AD-Gruppe durch und liest dessen Kalendereinträge aus.

Hat einer dieser Einträge die gesuchte Kategorie, wird dieser Eintrag in den SharePoint Kalender übernommen.

$categories = @{"Urlaub", "Sonderurlaub"}
foreach ($identity in $identities) {
    # Termine auslesen
    $appointments = Get-CalendarInformation -Identity $identity.Mail -weeksBefore $weeksBefore -weeksAfter $weeksAfter
    
    foreach ($appointment in $appointments) {
        # Überprüfen, ob der Termin der richtigen Kategorie zugeordnet ist
        $hasCategory = $false
        foreach ($appCategory in $appointment.Categories) {
            if ($null -ne $categories[$appCategory]) {
                $hasCategory = $true
            }

            break
        }

        if ($hasCategory) {
            # Termine in SharePoint anlegen
            Add-AppointmentIntoSPCalendar -Appointment $appointment
        }
    }
}

Kalenderinformationen auslesen

function Get-CalendarInformation {
    <#
    .SYNOPSIS
        A PowerShell function to list calendar information
    .DESCRIPTION
        Long description
    .EXAMPLE
        PS C:\> Get-CalendarInformation -Identity "xxx" -weeksBefore 5 -weeksAfter 2
        Lists CalenderInformation from the Last 5 and the next 2 Weeks
    .NOTES
    #>
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        $Identity,
  
        [Parameter(Mandatory)]
        [int]
        $weeksBefore,
        
        [Parameter()]
        [int]
        $weeksAfter,
  
        [Parameter()]
        [System.Management.Automation.CredentialAttribute()]
        [pscredential]
        $Credential
    )
     
    begin {
        $libPath = $PSScriptRoot + "\libs\Microsoft.Exchange.WebServices.dll"
        Add-Type -Path $libPath
    }
     
    process {
        $Service = [Microsoft.Exchange.WebServices.Data.ExchangeService]::new()
        if ($PSBoundParameters.ContainsKey('Credential')) {
            $Service.Credentials = [System.Net.NetworkCredential]::new($Credential.UserName, $Credential.Password)
        }
        else {
            $Service.UseDefaultCredentials = $true
        }
        $Service.Url = "https://xx.xxx.at/EWS/Exchange.asmx"
  
        $FolderId = New-Object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar, $Identity)
        
        try {
            $Folder = [Microsoft.Exchange.WebServices.Data.CalendarFolder]::Bind($Service, $FolderId)
        }
        catch {
            Write-Host $_.Exception.Message "Name:" $FolderId.Mailbox.Address -ForegroundColor Red
            return $null
        }

        $startDate = [datetime]::Now.AddDays(-7 * $weeksBefore)
        if ($null -eq $startDate) {
            $startDate = [datetime]::Now
        }

        $endDate = [datetime]::Now.AddDays(7 * $weeksAfter)
        if ($null -eq $endDate) {
            $endDate = [datetime]::Now
        }

        $View = [Microsoft.Exchange.WebServices.Data.CalendarView]::new($startDate, $endDate)
  
        $View.PropertySet = [Microsoft.Exchange.WebServices.Data.PropertySet]::new([Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Subject,
            [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Start,
            [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::End,
            [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Organizer,
            [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::DateTimeCreated)
        
        $BodyPropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
        $BodyPropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text

        $FolderItems = $Service.FindItems($Folder.Id, $View)
        [Void]$Service.LoadPropertiesForItems($FolderItems, $BodyPropertySet)
        return $FolderItems
    }
     
    end {
    }
}

Nun müssen nur noch alle gefundenen Termine mit der entsprechenden Kategorie in den SP Kalender hinzufügen werden.

Mithilfe dieses kleinen PS-Skripts ist es möglich die Kalendereinträge aus Outlook mittels EWS im SharePoint zu synchronisieren.

Was man sonst noch alles mit PowerShell anstellen kann, kannst du bei diesen Blogbeiträgen nachlesen.

Habt ihr Fragen oder Interesse an dem kompletten Script – einfach bei uns melden, indem du auf den Button klickst!
Kontakt aufnehmen