Powershell: Googlemail (GMail) nativ mit Powershell verwalten

Mitglied: colinardo

colinardo (Level 5) - Jetzt verbinden

22.12.2015, aktualisiert 20.07.2019, 10250 Aufrufe, 8 Kommentare, 8 Danke

1. Vorwort

Google bietet über die GMail-API die Voraussetzungen um sein Google-Mail-Konto über diverse Programmierschnittstellen (PHP/Javascript/etc. pp) zu verwalten. Die Authentifizierung der Anwendung welche auf das GMail Konto zugreift, kann dabei über die sichere OAuth-Methode geschehen. Für alle die dies nativ ohne zusätzliche DLLs mit der Powershell benötigen, habe ich mal eine Funktion zur Authentifizierung per OAuth und ein paar der wichtigsten Funktionen zur Verwaltung der Mails geschrieben.
Hauptsächlich sind dies folgende.

Funktionsname Verwendung
Auth-Google Authentifizierung der App per OAuth Methode
Get-GoogleMails Ruft eine Liste von Mails ab welche man mit mehreren Parametern filtern kann
Set-GoogleMailLabels Hiermit verändert man die Labels/Flags einer Nachricht um sie z.B. als gelesen zu markieren oder einer Kategorie zuzuordnen
Remove-GoogleMailMessageLöschen einer Nachricht
Send-GoogleMailMessageSenden einer Nachricht inkl. Attachments

Die Einrichtung der Zugangsdaten in der Google-Developer-Konsole und die Nutzung der Funktionen wird in den folgenden Arbeitsschritten erläutert

2. Erstellen der OAuth Zugangsdaten für das GMail-API

Für den Zugriff via Google API benötigen wir entsprechende Zugangsdaten für unser Skript. Namentlich sind das folgende:
  • Client-ID
  • Clientschlüssel
Meist generiert man hier separate Zugangsdaten für jede Applikation um in der Developerkonsole eine Statistik für jede seiner App abrufen zu können.

Anhand der folgenden Bilderreihe schildere ich die Vorgehensweise wie man diese Zugangsdaten erzeugt.

Zuerst melden wird uns an unserem Google-Konto an und rufen dann folgende Webseite auf:
https://console.developers.google.com

Nun folgt der Bilderreihe welche selbsterklärend sein sollten.

cc7bb40f257dbe7c3e97a55ed1c1e888 - Klicke auf das Bild, um es zu vergrößern

e20b40683b53f1f81260a77d8f7b119e - Klicke auf das Bild, um es zu vergrößern

a68a8209daf69a630317c6e16af7a9b3 - Klicke auf das Bild, um es zu vergrößern

3a3df340d0c164551973b517fb73ec8a - Klicke auf das Bild, um es zu vergrößern

a6f2cf4d1c85f9d7585b79fdddc6144f - Klicke auf das Bild, um es zu vergrößern

28f32f63ca09cef79c51c6ba9445621e - Klicke auf das Bild, um es zu vergrößern

320bfe8b4011cb74769fb52684658d9c - Klicke auf das Bild, um es zu vergrößern

b9b750e7c457325cc7d653a30c66aeff - Klicke auf das Bild, um es zu vergrößern

92f8416d4ae970888c30938ce14f83ce - Klicke auf das Bild, um es zu vergrößern

40b50aaa7e4b0f58d78ef757a41caaef - Klicke auf das Bild, um es zu vergrößern

Hier erfahren wir nun endlich unsere gewünschten Zugangsdaten

69dd38531f6ea6d387065d556c0dfcc4 - Klicke auf das Bild, um es zu vergrößern


3. Anpassung der Variablen im Header

Nachdem wir die Zugangsdaten erhalten haben fügen wir diese im Header des Skripts ein.
Zusätzlich geben wir hier die E-Mail-Adresse des Google-Kontos an.
Wenn man will kann man hier auch den Pfad anpassen in welcher das Refresh-Token als Datei abgelegt wird. Standardmäßig im selben Verzeichnis wie das Skript. Zur Funktion des Refresh-Tokens später mehr.
$global:scopes legt die Zugriffsberechtigung des Skripts auf das Google-Konto fest. Google arbeitet hier mit URLs die je nachdem bestimmte Zugriffsrechte auf das Google Konto gewähren. Die hier benutzte URL gibt dem Skript Vollzugriff auf alle GMail-Funktionen. Man kann hier z.B. auch nur Leserechte gewähren wenn man das möchte. Natürlich sind dann Funktionen welche Mails löschen oder verändern nicht möglich. Mehr zu den Scopes findet man in der API-Referenz zu den Scopes

4. Haupt-Powershell-Code

5. Erläuterungen zur Anwendung der einzelnen Funktionen

5.1 Auth-Google

Diese Funktion stellt sicher das sich die Anwendung bei Google per OAuth 2.0 anmeldet und das benötigte Access-Token für die Anfragen an das API abruft. Existiert noch kein Access-Token z.B. weil die Anwendung das erste mal ausgeführt wird muss die sich die Anwendung erst die Berechtigung des Anwenders holen. Dazu öffnet das Skript beim ersten mal ein Internet-Explorer-Fenster welches auf eine spezielle Autorisierungs-URL leitet. Man loggt sich mit seinem Google-Konto ein und bestätigt dann die Abfrage mit Klick auf den Button Zulassen. Dann erscheint ein Code in einem Textfeld. Diesen kopiert man nun in die Zwischenablage(WICHTIG), und schließt dann das Internet-Explorer Fenster. Das Powershell-Skript bekommt nun mit das der IE geschlossen wurde und schließt die Anforderung des Tokens mit dem Code aus der Zwischenablage ab.
Ein sogenanntes Refresh-Token wird dann in einer Datei namens refresh.token im selben Verzeichnis wie das PS-Skript gespeichert.
Da die angeforderten Access-Tokens immer nur eine bestimmte Gültigkeit haben (meist 30-60 Minuten), muss das Skript also auch regelmäßig ein aktuelles Token anfordern. Dies kann es mit dem Refresh-Token welches als refresh.token gesichert wurd, tun. Dieses File ist also sehr wichtig, denn nur damit kann sich das Skript ohne Userinteraktion bei Google anmelden. Wird das File gelöscht und die PS-Session geschlossen, durchläuft die Funktion zwingend erneut die Anforderung eines Autorisationscodes wie zu Beginn.

Die einzelnen folgenden Funktionen rufen diese Funktion zu Beginn immer auf um sicherzustellen das unser Skript ein gültiges Token für die folgenden Abfragen hat.

5.2 Get-GoogleMails

Diese Funktion ruft eine Liste der Mails ab welche wir über folgende Parameter filtern können

ParameterBeschreibung
[string[]]$labels = @('INBOX','UNREAD') Die Mails müssen alle hier in einem Array angegebenen Labels haben damit sie abgerufen werden, ohne Angabe sind das per Default hier nur ungelesene Mails aus dem Posteingang. Sollen alle Mails berücksichtigt werden einfach ein leeres Array @() übergeben.
[switch]$includespamtrash Switch wenn man möchte das Mails aus dem Mülleimer mit beachtet werden
[string]$query Hier kann ein Querystring zum Abfragen einzelner Mail-Felder angegeben werden. Die Syntax folgt der welche man auch im Suchfeld von GMail verwendet, Beispiel from:user@domain.de
[switch]$raw Switch wenn man den RAW-Inhalt einer Mail erhalten will (siehe dazu https://developers.google.com/gmail/api/v1/reference/users/messages/get)
Für einen leichteren Umgang mit dem Inhalt der Mails (Body/Header/etc.) habe ich ein paar Felder zu den standardmäßig von Google per JSON bereitgestellten hinzugefügt um sie leichter abrufen zu können. Das sind z.B. der Body (Text und HTML wenn vorhanden) die Header und das Empfangsdatum.
Alle verfügbaren Eigenschaften könnt Ihr euch ja einfach per get-member anzeigen lassen.
[int]$maxResults=100000Maximale Anzahl an Mails die abgerufen werden sollen

Ein exemplarischer Aufruf der alle Mails aus dem Posteingang abruft und in der Variablen $mails speichert, sieht dann so aus
Die Funktion enthält nun auch die Attachments in einer einfach abzurufender Weise. Beispiel zum auflisten der Attachments von Mails mit Attachment in der Inbox
Die Attachment-Objekte enthalten die Daten als Byte-Array[]. Eine benutzerdefinierte Skriptmethode zum Speichern der Attachments im Dateisystem wurde ebenfalls implementiert. Sie lautet SaveAs(<Pfad>). So kann man jedes Attachment abspeichern.

5.3 Set-GoogleMailLabels

Diese Funktion verändert die Tags/Labels einer Nachricht. Damit lässt sich eine Mail unter anderem als gelesen markieren indem man das UNREAD Flag entfernt.

Parameter

ParameterBeschreibung
[string]$messageid Die ID der Nachricht. Die ID erhalten wir als Eigenschaft für jede Mail welche wir oben mit Get-GoogleMails abgerufen haben
[string[]]$addlabels Ein String-Array aus Label-Namen welche der Mail hinzugefügt werden sollen
[string[]]$removelabels Ein String-Array aus Label-Namen welche von der Mail entfernt werden sollen
WICHTIG: Die Labels müssen schon in Google existieren, könnt Ihr wenn Ihr wollt mit dem API auch automatisiert hinzufügen, habe das in der Funktion aus Zeitgründen noch nicht hinzugefügt.

Exemplarischer Aufruf um die erste Mail welche wir oben mit Get-GoogleMails abgerufen haben als gelesen zu markieren

5.4 Remove-GoogleMailMessage

Die Funktion macht was ? Natürlich leicht zu erraten, sie löscht Mails.

Parameter

ParameterBeschreibung
[string]$messageid Die ID der Nachricht. Die ID erhalten wir als Eigenschaft für jede Mail welche wir oben mit Get-GoogleMails abgerufen haben

Exemplarischer Aufruf um die erste Mail welche wir oben vorher mit Get-GoogleMails abgerufen haben, zu löschen

5.5 Send-GoogleMailMessage

Die Funktion sendet eine Mail über das GMail-System.

Parameter

ParameterBeschreibung
[string]$from = $global:gmail_email Absender-Email-Adresse festlegen, ohne Angabe wird hier die im Header des Skripts angegebene Adresse verwendet
[string[]]$to String-Array aus Empfängeradressen
[string[]]$cc String-Array aus CC-Adressen
[string[]]$bcc String-Array aus BCC-Adressen
[string]$subject Betreff der Nachricht
[string]$body Body der Nachricht. Wenn der Switch $isHtml gesetzt ist kann dieser auch HTML-Anweisungen enthalten
[switch]$IsHtml Switch gibt an ob der Body HTML-Anweisungen enthält, welche angewendet werden sollen
[string[]]$attachments Ein String-Array aus Dateisystem-Pfaden welche als Attachments an die Mail angehängt werden sollen

Exemplarischer Aufruf zum Versenden einer Mail

6. Abschließende Kommentare

Ich weiß das die Anleitung noch nicht sämtliche mögliche Funktionen de GMail-Apis bereitstellt, das war auch nicht meine Intention. Anhand der einzelnen Funktionen kann man sich aber nun sehr einfach ab schauen, wie man Requests an das API schickt und verarbeitet. Es sollte also mit Hilfe der API-Dokumentation zu GMail nun nicht mehr viel Arbeit sein, seine eigenen Funktionen zum implementieren.

Die Authentifizierungs-Funktion kann ebenfalls auch für die anderen APIs wie z.B. das Kalender-API benutzt werden. Ich habe hier auch schon einige Funktionen für den Google-Kalender geschrieben, die ich bei Zeiten auch mal veröffentlichen werde so es die Zeit zulässt.

Ich hoffe ihr habt nun viel Spaß mit dem Skript.

Wie immer geschieht die Verwendung jeglichen Codes auf eigene Gefahr ... Bei Verwendung des Codes in anderen Projekten bitte einen Vermerk der Quelle auf diese Seite einfügen.

Gruß @colinardo

Gefällt euch der Beitrag und Ihr wollt weiterhin solche Beiträge hier sehen, freue ich mich wie immer auf eine kleine Spende.
If you like my contribution please support me and donate

Updates

Datum Änderung
20.07.2019 Anpassung der Funktion Get-Googlemails.
08.06.2016 Fehlerbehebung in der Auth-Google Funktion.
04.01.2016 Update und Fehlerbehebung der Funktion Get-GoogleMails. Diese wurde um eine einfachere Verarbeitung von Attachments erweitert

Mitglied: 114757
114757 (Level 4)
22.12.2015, aktualisiert um 19:51 Uhr
@colinardo HAMMER kann man dazu nur sagen :-D face-big-smile

Vielen Dank....
THUMBS UP! Weiter so!

Gruß jodel

p.s. Die Google-Kalender-Funktionen die du anscheinend auf Lager hast würden mich auch sehr interessieren ;-) face-wink Ich klingel dazu aber mal bei dir an wenn ich darf...
Bitte warten ..
Mitglied: bitrider
28.12.2015 um 15:02 Uhr
Ich bin begeistert :-) face-smile
Danke dir
Bitte warten ..
Mitglied: notSoClever
20.07.2019, aktualisiert um 12:33 Uhr
Google benötigt offenbar Zeit zur Prüfung, um die Authorisierung wirklich per Powershell zuzulassen.

Vorher kann man jedoch im sich öffnenden Browser das eigene Projekt (als unsicher) zulassen und kriegt einen (in meinem Fall 57-Zeichen) Code, den man in der App eingeben soll.
Allerdings erfrägt der Powershell Code keinen solchen Autorisierungs-Code (der sich bei jedem Versuch ändert!).

Das Script meldet einen Fehler:

Invoke-RestMethod : Der Remoteserver hat einen Fehler zurückgegeben: (401) Nicht autorisiert.
In D:\Dokumente\G-Mail Attachments\Get-GMailAttachments.ps1:53 Zeichen:19

... $result = Invoke-RestMethod 'https://www.googleapis.com/oauth2/v3/t" ...

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Was kann ich tun, damit die Authorisierung funktioniert?
Bitte warten ..
Mitglied: colinardo
20.07.2019, aktualisiert um 12:40 Uhr
Allerdings erfrägt der Powershell Code keinen solchen Autorisierungs-Code (der sich bei jedem Versuch ändert!).
Doch, Hinweise zum Beitrag bitte genau lesen !

P.s. Und bitte https://administrator.de/aboutus/rules.php#toc-1 beachten, DANKE.
Bitte warten ..
Mitglied: notSoClever
20.07.2019 um 13:55 Uhr
Hallo Colinardo,
besten Dank für deinen Code - er behandelt genau was ich suche: alle Mail Attachments von Gmail herunterladen.
Gerne versuche ich mich an die Nettiquette zu halten - danke für den Hinweis!

Nach Befolgung deines Hinweises erscheint zumindest kein Authentisierungs-Fehler mehr.
Allerdings kommt eine andere Fehlermeldung (siehe unten).
Kann das daran liegen, dass ich den Scope auf READONLY gesetzt habe?

$global:scopes = @('https://www.googleapis.com/auth/gmail.readonly')"

Fehlermeldung:

% : Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat.
In D:\Dokumente\G-Mail Attachments\Get-GMailAttachments.ps1:133 Zeichen:36

$_.parts | %{

~~

+ CategoryInfo : InvalidOperation: (:) face-smile [ForEach-Object], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull,Microsoft.PowerShell.Commands.ForEachObjectCommand
Bitte warten ..
Mitglied: colinardo
20.07.2019, aktualisiert um 17:57 Uhr
Kann das daran liegen, dass ich den Scope auf READONLY gesetzt habe?
Nein das hat es nicht sofern du keine Schreibfunktionen auf dem Konto ausführst.

Habe es gerade nochmal überprüft. Da hat Google im zurückgegebenen Objekt minimale Typ-Anpassungen vorgenommen. Habe die entsprechende Funktion zum Parsen der Mails (Get-GoogleMails) oben angepasst, jetzt sollte der Fehler nicht mehr auftreten.

Hope that helps.

Danke für dein Feedback, und schönes Wochenende.
Grüße Uwe
Bitte warten ..
Mitglied: notSoClever
21.07.2019 um 09:24 Uhr
Funktioniert wunderbar.
Herzlichen Dank!

Ein Hinweis:
da der Dateinamen zum Abspeichern von Attachments unter anderem aus dem Mail Subject gebildet wird, kann der Dateiname schon mal zu lang werden, und einen Fehler ausgeben - man sollte den Output in der PS Konsole auf rote Einträge prüfen:

... "Ein Teil des Pfades "..." konnte nicht gefunden werden."
(bricht über mehrere Zeile um)
Bitte warten ..
Mitglied: colinardo
21.07.2019, aktualisiert um 10:27 Uhr
Zitat von @notSoClever:
Ein Hinweis:
da der Dateinamen zum Abspeichern von Attachments unter anderem aus dem Mail Subject gebildet wird,
Hinweis: Dem Attachmentsobject wird immer der original Dateiname mit in einer Eigenschaft mit übergeben, zusammen mit dem und einem eindeutigen Wert z.B. der MessageID oder einem Zufallswert gebildet lässt sich so ein eindeutiger Bezeichner bilden.
kann der Dateiname schon mal zu lang werden, und einen Fehler ausgeben - man sollte den Output in der PS Konsole auf rote Einträge prüfen:
Selbst gebildete Dateinamen aus Strings sie dem Subject die man selbst nicht unter Kontrolle hat muss man immer auf Validität Sonderzeichen, Länge etc. prüfen, das hat mit diesen Funktionen hier nichts zu tun.
Eine entsprechende Powershell Funktion zum Bereinigen von Dateinamen habe ich hier im Forum übrigens schon mal gepostet. =>Suchfunktion
https://administrator.de/forum/powershell-pfad-%C3%BCberpr%C3%BCfen-2904 ...
usw.

Alles andere bitte PN.

Grüße Uwe
Bitte warten ..
Heiß diskutierte Inhalte
Festplatten, SSD, Raid
Festplatte aus defekten Notebook ausgebaut - wird nicht erkannt - Wie gelange ich an meine Daten?
gelöst 1nCoreVor 1 TagFrageFestplatten, SSD, Raid15 Kommentare

Hallo liebe Community, nach 7 Jahren hat mein XMG Notebook seinen Geist aufgegeben In dem Notebook waren zwei Festplatten verbaut (eine für System und ...

Erkennung und -Abwehr
Wie geschickt sich Malware verstecken kann - Ein Beispiel aus der Praxis eines Security Experts
colinardoVor 1 TagTippErkennung und -Abwehr5 Kommentare

Servus Kollegen und Mitstreiter, da ja in letzter Zeit die Exchange-Lücken die Admin-Landschaft ziemlich aufgewirbelt haben und dabei auch immer mal wieder "sogenannte" Admins ...

Exchange Server
Exchange Update CU19 auf CU20 Fehler - Eine weitere Version dieses Produkts ist bereits installiert
gelöst StefanKittelVor 1 TagFrageExchange Server6 Kommentare

Hallo, ich habe hier einen Exchange 2016 mit CU19 (15.1.2176.2). Darauf wollte ich nun CU20 installiert. Download Es erscheint Eine weitere Version dieses Produkts ...

Windows Server
Hat Microsoft die WindowsServerSicherung oder diskpart zerpatcht?
anteNopeVor 20 StundenFrageWindows Server3 Kommentare

Hallo, kann es eventuell sein, dass Microsoft mit seinen letzten Updates die WindowsServerSicherung bzw. diskpart zerschossen hat? Es häufen sich bei mir seit gestern ...

Windows 10
Windows 10 Updates im Abgesicherten Modus nicht möglich!
gelöst Yuuto.LucasVor 1 TagFrageWindows 1016 Kommentare

Hallo, ich habe aktuell ein Problem bei einem Kunden Rechner. Bei diesem gibt es Probleme mit dem Soundkarten Treiber hdaudio.inf wegen dem der PC ...

Windows 10
Lokales Profil wird beim Herunterfahren gelöscht!
Yuuto.LucasVor 1 TagFrageWindows 1012 Kommentare

Hallo, ich habe aktuell folgendes Problem. An einem Kundenrechner ist aktuell ein Lokales Profil eingerichtet (vorher ein Server Profil bei dem das gleiche Problem ...

Ubuntu
Cups-Server mit SMB lehnt Verbindungen ab (smb.conf)?
ErikHeinemannVor 10 StundenFrageUbuntu17 Kommentare

Guten Morgen, ich habe einen Ubuntu 20.04 Server mit Cups als Printspooler. Nun Soll noch Samba hinzugefügt werden für eine einfache Verwendung unter Windows. ...

Exchange Server
Kaspersky for Exchange Meldungen
gelöst wieoderwasVor 9 StundenFrageExchange Server11 Kommentare

Guten Morgen, wir haben bei uns einen Exchange 2013 mit Kaspersky for Exchange und Sophos auf Dateiebene. Heute Morgen habe ich einige von diesen ...