Outlook und PowerShell
Jahrelang habe ich mit Outlook mit VBScript (Siehe Outlook VBScript) angesteuert, bis Microsoft den Zugriff aufgrund des Missbrauchspotential durch Viren eingeschränkt hat. Dann habe ich per VBScript mit MAPI/CDO hantiert. Seit Exchange 2007 und neuer ist natürlich EWS die bevorzugte Schnittstellen, auch wenn die Exchange REST-API eine neue Möglichkeit aufzeigt.
Dennoch ist Outlook immer noch ein sehr nützliches Werkzeug, um mal schnell an die Elemente eines Postfachs zu kommen und zu verarbeiten.
Einsatzbereich
PowerShell spielt eine immer größere Rolle in meiner täglichen Tätigkeit und da ist es nur logisch, wenn ich immer weniger VBScript einsetze. Nur für Outlook war VBScript neben Outlook VBA lange Zeit meine primäre Skriptsprache. Die Programmierung von Outlook unterliegt aber einigen Einschränkungen:
- Outlook muss installiert und idealerweise gestartet werden
- Ein Outlook Profil muss bereits
konfiguriert sein
Ich habe kaum Wege gefunden, per PowerShell die Profileinstellungen zu ändern. - Keine Impersonation
Man arbeitet immer mit dem aktiv angemeldeten Benutzer - Kein wahlfreier Postfachzugriff
Ich konnte bislang nur auf die Ordner zugreifen, die Outlook auch eingebunden hatte
Dafür ist die Programmierung im Vergleich zu EWS eher "einfach" und Sie können parallel per Outlook sehen, was das Skript sieht. Zudem ist auf einem PC, auf dem Outlook vorhanden ist, CDO sowieso nicht mehr möglich.
Collaboration Data Objects (CDO) 1.2.1
is not supported with Outlook 2010 and later versions
https://support.microsoft.com/en-us/help/2028411/collaboration-data-objects-cdo-1.2.1-is-not-supported-with-outlook-2010-and-later-versions
CDO 1.2.1 is not supported for use with Outlook 2010 or
later versions, and we do not recommend its use with Outlook
2010 and later versions.
CDO könnte man zwar noch auf einem Exchange Server installieren aber es ist eh kein 64bit Code mehr. Letztlich sollte man richtige Projekte auf EWS aufsetzen. Aber um mal eben schnell etwas zu fixen, was der Anwender (oder ein Anmeldeskript) auch ohne weitere Installationen einer EWS Managed API o.ä. starten kann, ist das Outlook Modell immer noch passend.
Outlook per COM-Objekt
Outlook hat immer noch COM-Objekte, und die kann natürlich auch die PowerShell instanzieren. Allerdings kommt hier wieder verschiedene Warnungen, z.B. wenn sie automatisch auf den Kontaktordner lesend zugreifen wollen. Dieser kurze Abschnitt instanziert Outlook als COM-Objekt und listet den Betreff aller Mails im Posteingang auf.
# Outlook per PowerShell Sample # write-host "get-pfcontent: Loading Outlook Object Model" Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null write-host "Erstellen der Auflistung fuer Default Folder" $olFolders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type] Write-host "Instanziere Outlook" $outlook = new-object -comobject outlook.application $namespace = $outlook.GetNameSpace("MAPI") Write-host "Binde Posteingang" $inbox = $namespace.getDefaultFolder($olFolders::olFolderInBox) $inbox.Items | foreach { $_.subject } Writel-host "Binde Public Folder" $pffolderroot = $namespace.getDefaultFolder($olFolders::olPublicFoldersAllPublicFolders)
Ein Zugriff auf die gleichen Funktionen per CDO ist übrigens nicht möglich, da hier das Multithreading von PowerShell mit CDO nicht kompatibel ist.
PowerShell User Guide page 33,
"Not all COM objects are supported. Objects that are based on Exchange
Collaboration Data Objects (CDO) are not supported in this release."
813349 Support policy für Microsoft Exchange APIs with the .NET
Framework applications
Vorsicht bei Loops
Es ist eigentlich naheliegend, die Inhalte eines Ordners einfach mit einer Schleife oder gar Pipeline abzuarbeiten. Das ist aber keine gute Idee, da .NET den Speicher nicht zuverlässig wieder freigeben kann, wen die Laufvariable so benutzt wird.
- OOM.NET: Part 2 – Outlook Item Leaks
https://blogs.msdn.microsoft.com/mstehle/2007/12/07/oom-net-part-2-outlook-item-leaks/
Besser ist es daher mit einer "Zählervariable" zu arbeiten
foreach ($count in 1..($folder.items.count)) { $item = $folder.items.item($count) write-host " Item: ($count) = $($item.Subject)" write-host $item.ReceivedTime write-host $item.SenderName write-host $item.Size }
Über den Counter ist natürlich auch einfach ein Fortschrittsanzeige möglich.
Große Ordner
Speziell bei Ordnern mit sehr vielen Inhalten ist aber auch das sequentielle Durchlaufen mühsam und hat immer das Problem, das speziell Änderungen auch die Reihenfolge ändern. Hier ist es dann sinnvoller sich von Element zu Element zu hangeln.
- Items Object (Outlook)
https://msdn.microsoft.com/en-us/library/ff863652.aspx - Items.FindNext Method (Outlook)
https://msdn.microsoft.com/en-us/library/ff862482.aspx - Items.Find Method (Outlook)
https://msdn.microsoft.com/en-us/library/ff869662.aspx - How To: Use Find and FindNext methods to
retrieve Outlook mail items from a folder
(C#, VB.NET)
https://www.add-in-express.com/creating-addins-blog/2011/09/20/outlook-find-findnext-retrieve-mail/
Ordner gezielt anspringen
Mit ist es noch nicht gelungen, einen Ordner anhand des Pfad direkt und gezielt anzuspringen. Man muss sich schon selbst durch die Ordnerstruktur hangeln und schauen, ob der Name des aktuellen Ordners oder der Pfad mit dem gesuchten Ordner übereinstimmt.
function process-folder($folder) { write-host "get-pfcontent: Folder: $($folder.folderpath)" -nonewline [string]$folderpath = $folder.folderpath if (( $recursive -and ($folder.FullFolderPath.startswith($startfolder))) -or (($folder.FullFolderPath -eq $startfolder))){ write-host "get-pfcontent: Start Items" if ($folder.items.count -ge 1) { foreach ($count in 1..($folder.items.count)) { $item = $folder.items.item($count) write-host " Item: ($count) = $($item.Subject)" } } else { write-host " Skip Folder" } write-host " Subfolders" if ($folder.folders.count -ge 1){ foreach ($count in 1..($folder.folders.count)) { Write-host " Next Subfolder $($subfolder.folderpath)" process-folder $folder.folders.item($count) } } } # start recursive write-host "Start Folder Processing" process-folder $pffolderroot
Weitere Links
- Outlook VBScript
- MAPI/CDO
- Outlook VBA
- EWS
- Exchange REST-API
- REST-API
- How to get reference to Public Folder
Store using Outlook Object Model for Outlook
2010?
https://blogs.msdn.microsoft.com/brijs/2010/07/30/how-to-get-reference-to-public-folder-store-using-outlook-object-model-for-outlook-2010/ - OlDefaultFolders-Aufzählung (Outlook)
https://msdn.microsoft.com/de-de/library/office/ff861868.aspx - Use PowerShell to Data Mine Your Outlook
Inbox
https://blogs.technet.microsoft.com/heyscriptingguy/2011/05/26/use-powershell-to-data-mine-your-outlook-inbox/ - PowerShell - Managing an Outlook Mailbox
with PowerShell
https://msdn.microsoft.com/en-us/magazine/dn189202.aspx - How To Build Recursive Functions In
PowerShell
http://www.tomsitpro.com/articles/build-recursive-functions-in-powershell,2-865.html - Gewusst wie: Abrufen eines Ordners über
den Ordnerpfad
https://msdn.microsoft.com/de-de/library/office/ff184612.aspx - OOM.NET: Part 2 – Outlook Item Leaks
https://blogs.msdn.microsoft.com/mstehle/2007/12/07/oom-net-part-2-outlook-item-leaks/ - Microsoft.Office.Interop.Outlook Namespace
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook(v=office.12).aspx - Why use the Outlook PIA
http://msdn.microsoft.com/en-us/library/bb645534(v=office.12).aspx