colinardo
Goto Top

Powershell: Googlemail (GMail) nativ mit Powershell verwalten

back-to-top1. 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

back-to-top2. 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

e20b40683b53f1f81260a77d8f7b119e

a68a8209daf69a630317c6e16af7a9b3

3a3df340d0c164551973b517fb73ec8a

a6f2cf4d1c85f9d7585b79fdddc6144f

28f32f63ca09cef79c51c6ba9445621e

320bfe8b4011cb74769fb52684658d9c

b9b750e7c457325cc7d653a30c66aeff

92f8416d4ae970888c30938ce14f83ce

40b50aaa7e4b0f58d78ef757a41caaef

Hier erfahren wir nun endlich unsere gewünschten Zugangsdaten

69dd38531f6ea6d387065d556c0dfcc4


back-to-top3. 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
# ANPASSUNGEN HIER VORNEHMEN ===========================================================

# Client API Zugangsdaten hier eintragen
$client_id = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com'  
$client_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxx'  
# Array der Bereiche die autorisiert werden sollen (In diesem Beispiel erhält die Anwendung Vollzugriff auf alle GMail Funktionen)
$global:scopes = @('https://mail.google.com/')  
# Pfad in dem das Refresh-Token gespeichert wird mit dem man ein neues Access Token anfordert (Standardmäßig der Ordner in dem das Skript liegt)
$global:token_path = "$(Split-Path $PSCommandPath -Parent)\refresh.token"  
# E-Mail-Adresse des Google-Kontos
$global:gmail_email = 'USER@GMAIL.COM'  

# ENDE EINRICHTUNG =====================================================================

back-to-top4. Haupt-Powershell-Code

<#
    #####################################################
    ###### Google GMAIL-Verwaltung (c) @colinardo #######
    #####################################################
    -> benötigt wird mind. PS Version 3.0
#>

# ANPASSUNGEN HIER VORNEHMEN ===========================================================

# Client API Zugangsdaten hier eintragen
$client_id = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com'  
$client_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxx'  
# Array der Bereiche die autorisiert werden sollen (In diesem Beispiel erhält die Anwendung Vollzugriff auf alle GMail Funktionen)
$global:scopes = @('https://mail.google.com/')  
# Pfad in dem das Refresh-Token gespeichert wird mit dem man ein neues Access Token anfordert (Standardmäßig der Ordner in dem das Skript liegt)
$global:token_path = "$(Split-Path $PSCommandPath -Parent)\refresh.token"  
# E-Mail-Adresse des Google-Kontos
$global:gmail_email = 'USER@GMAIL.COM'  

# ENDE EINRICHTUNG =====================================================================

Add-Type -AssemblyName System.Windows.Forms

# Accept all TLS protocols
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::GetNames([System.Net.SecurityProtocolType])

<# 
    -------------------------------------------------------------------------------------------
    Funktion: Auth-Google - Haupt-Authentifizierungsfunktion (OAuth 2.0) für Zugriffe auf die Google-Dienste
    -------------------------------------------------------------------------------------------
#>
function Auth-Google {
    # Wenn refresh.token Datei vorhanden lese Token aus
    if ((Test-Path $global:token_path)){
        $content = gc $global:token_path -TotalCount 1
        if ($content.length -gt 0){$global:refresh_token = $content}
    }
    # wenn kein Refresh-Token vorhanden ist, initiale Authorization starten ...
    if(!$global:refresh_token){
        $url = "https://accounts.google.com/o/oauth2/auth?scope=$($global:scopes -join " ")&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&client_id=$client_id"  
        # Manuelle Authorization mit Userinteraktion
        write-host "Starting Authorization Request in Browser ... (Please Login into your Google-Account, and accept the authorization request, copy the returned code and close the Browser-Window !" -ForegroundColor Green  
        Start-Process "iexplore.exe" -ArgumentList $url -Wait  
        $authcode = [System.Windows.Forms.Clipboard]::GetText()
        
        $requestbody = @{
        "code"=$authcode  
        "client_id"=$client_id  
        "client_secret"=$client_secret  
        "redirect_uri"='urn:ietf:wg:oauth:2.0:oob'  
        "grant_type"="authorization_code"  
        }
    
        $result = Invoke-RestMethod 'https://www.googleapis.com/oauth2/v3/token' -Method Post -Body $requestbody  
        $global:refresh_token = $result.refresh_token
        set-content $global:token_path -Value $global:refresh_token
        $global:access_token = $result.access_token
        $global:token_expires = $result.expires_in
        $global:token_created = get-date
        return $true
    }else{
        # kein access_token vorhanden => neues access_token via refresh holen
        if (!$global:access_token){
            write-host "Refreshing access_token ..."  
            $requestbody = @{
            "refresh_token"=$global:refresh_token  
            "client_id"=$client_id  
            "client_secret"=$client_secret  
            "grant_type"="refresh_token"  
            }
            Try{
                $tokenrequest = Invoke-RestMethod 'https://www.googleapis.com/oauth2/v3/token' -Method Post -Body $requestbody -EA Stop  
                $global:access_token = $tokenrequest.access_token
                $global:token_created = get-date
                $global:token_expires = $tokenrequest.expires_in
                return $true
            }catch{
                write-host $_.Exception.Message
                return $false
            }
        }else{
            # access_token vorhanden, überprüfe ob es abgelaufen ist
            if((((get-date) - $global:token_created).TotalSeconds) -ge $global:token_expires){
                # access_token ist abgelaufen => fordere ein neues an
                write-host "Access Token has expired ..."  
                $global:access_token = ""  
                Auth-Google
            }else{
                # gültiges access_token vorhanden
                return $true
            }
        }
    }
}

<# 
    ------------------------------------
    Funktion: Get-GoogleMails
    ------------------------------------
#>
function Get-GoogleMails([string[]]$labels = @('INBOX','UNREAD'),[switch]$includespamtrash,[string]$query,[switch]$raw,[int]$maxResults = 100000){  
    if(!(Auth-Google)){
        return $false 
    }
    Try{
        $param_spam = $(if($includespamtrash.IsPresent){'&includeSpamTrash=true'}else{'&includeSpamTrash=false'})  
        $param_format = $(if($raw.IsPresent){'&format=raw'}else{'&format=full'})  
        $param_labels = $(if($labels){'&labelIds=' + $($labels -join '&labelIds=')})  
        $param_query = $(if($query){"&q=$([System.Net.WebUtility]::UrlEncode($query))"})  
        $uri = "https://www.googleapis.com/gmail/v1/users/$([System.Net.WebUtility]::UrlEncode($global:gmail_email))/messages?access_token=$($global:access_token)$param_labels$param_spam$param_query&maxResults=$maxResults"  
        $result = Invoke-RestMethod $uri -Method Get -ErrorAction Stop
        $mails = @()
        $result.messages.id | %{
            $messageId = $_
            $mail = irm -Uri "https://www.googleapis.com/gmail/v1/users/$($global:gmail_email)/messages/$($messageId)?access_token=$($global:access_token)$param_format" -Method Get -EA Stop  
            # UNIX Datum umwandeln
            $mail | add-member -MemberType NoteProperty -Name "Date" -Value ([timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddMilliseconds($mail.internalDate)))  
            # Simplen Body extrahieren
            if ($mail.payload.body.data){
                $b64data = $mail.payload.body.data.replace('-','+').replace('_','/')  
                $mail | add-member -MemberType NoteProperty -Name 'Body' -Value ([System.Text.Encoding]::UTF8.GetString([convert]::FromBase64String($b64data)))  
            }
            # Attachments extrahieren
            if ($mail.payload.parts){
                $mail | add-member -MemberType NoteProperty -Name "Attachments" -Value @()  
                $mail.payload.parts | %{
                    if($_.filename -ne "" -and $_.body.attachmentId -ne $null){  
                     # part ist ein Attachment
                        $attachment = irm -uri "https://www.googleapis.com/gmail/v1/users/$($global:gmail_email)/messages/$($messageId)/attachments/$($_.body.attachmentId)?access_token=$($global:access_token)$param_format" -Method Get -EA Stop  
                        # custom attachment object mit den wichtigsten Daten erstellen und Umwandlung der Base64 Daten in Byte-Array
                        $attachment_object = New-Object PSObject -Property @{'Name'=$_.filename;'Size'=$attachment.Size;'Data'=[convert]::FromBase64String($attachment.data.replace('-','+').replace('_','/'))}  
                        # Methode zum Speichern des Attachments hinzufügen
                        $attachment_object | add-member -MemberType ScriptMethod -Name SaveAs -Value {param([parameter(mandatory=$true)][ValidateNotNullOrEmpty()][string]$filepath)[System.IO.File]::WriteAllBytes($filepath,$this.Data)}
                        $mail.Attachments += $attachment_object
                    }
                }
            }
            # Header leichter zugänglich machen
            if($mail.payload.headers){
                $headers = @{}
                $mail.payload.headers | %{$headers[$_.name] += @($_.value)}
                $mail | add-member -MemberType NoteProperty -Name Headers -Value $headers
            }
            if($mail.raw){
                $b64data = $mail.raw.replace('-','+').replace('_','/') # google benutzt eine andere Base64 Tabelle  
                $mail | add-member -MemberType NoteProperty -Name "Body" -Value ([System.Text.Encoding]::UTF8.GetString([convert]::FromBase64String($b64data)))  
            }
            # mail zum Array hinzufügen
            $mails += $mail
        }
        return $mails
        
    }catch [System.Net.WebException]{
        write-host $_.Exception.Message -F Red
        return $false
    }
}
<# 
    ----------------------------------------
    Funktion: Set-GoogleMailLabels
    ----------------------------------------
#>
function Set-GoogleMailLabels([string]$messageid,[string[]]$addlabels,[string[]]$removeLabels){
        if(!(Auth-Google)){
        return $false 
    }
    Try{
        $body_labels = @{}
        if($removeLabels){$body_labels."removeLabelIds" = $removelabels}  
        if($addlabels){$body_labels."addLabelIds" = $addlabels}  
        $body_labels = $body_labels | ConvertTo-JSON

        $uri = "https://www.googleapis.com/gmail/v1/users/$([System.Net.WebUtility]::UrlEncode($global:gmail_email))/messages/$($messageid)/modify?access_token=$($global:access_token)"  
        $result = Invoke-RestMethod $uri -Method POST -ErrorAction Stop -Body $body_labels -ContentType "application/json"  
        return $result
    }catch [System.Net.WebException]{
        write-host $_.Exception.Message -F Red
        return $false
    }
}

<# 
    ----------------------------------------
    Funktion: Remove-GoogleMailMessage
    ----------------------------------------
#>
function Remove-GoogleMailMessage([string]$messageid){
    if(!(Auth-Google)){
        return $false 
    }
    Try{
        $uri = "https://www.googleapis.com/gmail/v1/users/$([System.Net.WebUtility]::UrlEncode($global:gmail_email))/messages/$($messageid)?access_token=$($global:access_token)"  
        return irm $uri -Method Delete -ErrorAction Stop
    }catch [System.Net.WebException]{
        write-host $_.Exception.Message -F Red
        return $false
    }
}

<# 
    ----------------------------------------
    Funktion: Send-GoogleMailMessage
    ----------------------------------------
#>
function Send-GoogleMailMessage([string]$from = $global:gmail_email,[string[]]$to,[string[]]$cc,[string[]]$bcc,[string]$subject,[string]$body,[switch]$IsHtml,[string[]]$attachments){
        if(!(Auth-Google)){
        return $false 
    }
    Try{
        $mail = new-Object System.Net.Mail.MailMessage
        $mail.From = $from
        $to | %{$mail.to.Add($_)}
        if($cc){$cc | %{$mail.cc.Add($_)}}
        if($bcc){$bcc | %{$mail.Bcc.Add($_)}}
        if($attachments){$attachments | %{$mail.Attachments.Add($_)}}
        $mail.Subject = $subject
        $mail.Body = $body
        $mail.IsBodyHtml = $(if($IsHtml.IsPresent){$true}else{$false})
        $mail.BodyEncoding = [System.Text.Encoding]::UTF8
        $mail.BodyTransferEncoding = [System.Net.Mime.TransferEncoding]::Base64

        $flags = [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic
        $MailWriter = [System.Net.Mail.SmtpClient].Assembly.GetType("System.Net.Mail.MailWriter")  
        $MailWriterConstructor = $MailWriter.GetConstructor($flags,$null,([System.IO.Stream]),$null)
        $sendMethod = [System.Net.Mail.MailMessage].GetMethod("Send",$flags)  
        $closeMethod = [System.Net.Mail.MailMessage].GetMethod("Close",$flags)  
        $result = New-Object System.IO.MemoryStream
        $writer = $MailWriterConstructor.Invoke($result)
        $sendMethod.Invoke($mail,$flags,$null,@($writer,$true,$true),$null)
        $b64String = [System.Convert]::ToBase64String($result.toArray())
        $result.Close(); $result.Dispose()

        $body = @{
            "raw" = $b64String  
        } | ConvertTo-Json
        $uri = "https://www.googleapis.com/gmail/v1/users/$([System.Net.WebUtility]::UrlEncode($global:gmail_email))/messages/send?access_token=$($global:access_token)"  
        $result = Invoke-RestMethod $uri -Method POST -ErrorAction Stop -Body $body -ContentType "application/json"  
        return $result
    }catch [System.Net.WebException]{
        write-host $_.Exception.Message -F Red
        return $false
    }
}

back-to-top5. Erläuterungen zur Anwendung der einzelnen Funktionen

back-to-top5.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.

back-to-top5.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
$mails = Get-GoogleMails -labels @("INBOX")  
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
$mails = Get-GoogleMails -query 'has:attachment' -labels @("INBOX")  
$mails | %{
    write-host "Mail: $($_.Headers.Subject)" -F Green  
    $_.Attachments
}
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.
$mails = Get-GoogleMails -query 'has:attachment' -labels @("INBOX")  
$mails | %{
    write-host "Mail: $($_.Headers.Subject)" -F Green  
    $_.Attachments | %{
        $_.SaveAs("<PFAD für das ATTACHMENT>")  
   }
}

back-to-top5.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
Set-GoogleMailLabels -messageid $mails.id -removelabels "UNREAD"

back-to-top5.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
Remove-GoogleMailMessage -messageid $mails.id

back-to-top5.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
Send-GoogleMailMessage -to "user@domain.de" -subject "Testsubject" -body "Mein Body kann auch <strong>HTML</strong> enthalten." -IsHtml -attachments 'C:\test.txt'  

back-to-top6. 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

back-to-topUpdates

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

Content-Key: 291531

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

Ausgedruckt am: 19.03.2024 um 09:03 Uhr

Mitglied: 114757
114757 22.12.2015 aktualisiert um 19:51:12 Uhr
Goto Top
@colinardo HAMMER kann man dazu nur sagen 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...
Mitglied: bitrider
bitrider 28.12.2015 um 15:02:50 Uhr
Goto Top
Ich bin begeistert face-smile
Danke dir
Mitglied: notSoClever
notSoClever 20.07.2019 aktualisiert um 12:33:33 Uhr
Goto Top
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?
Mitglied: colinardo
colinardo 20.07.2019 aktualisiert um 12:40:40 Uhr
Goto Top
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 Diskussionsrichtlinien - die Regeln zu unseren Inhalten beachten, DANKE.
Mitglied: notSoClever
notSoClever 20.07.2019 um 13:55:21 Uhr
Goto Top
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: (:) [ForEach-Object], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull,Microsoft.PowerShell.Commands.ForEachObjectCommand
Mitglied: colinardo
colinardo 20.07.2019 aktualisiert um 17:57:00 Uhr
Goto Top
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
Mitglied: notSoClever
notSoClever 21.07.2019 um 09:24:22 Uhr
Goto Top
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)
Mitglied: colinardo
colinardo 21.07.2019, aktualisiert am 27.02.2023 um 08:29:57 Uhr
Goto Top
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

Powershell Pfad überprüfen

usw.

Alles andere bitte PN.

Grüße Uwe
Mitglied: ber999
ber999 06.02.2024 um 18:45:10 Uhr
Goto Top
Ganz ausgezeichnet.
Ist aber auch möglich, eine Hotmail Mailbox nativ mit Powershell verwalten?
Mir geht es darum, ein Hotmail Konto einem Outlook 2013 Client hinzuzufügen.
Microsoft hat wieder etwas geändert und es gelingt nicht, funktionierende Einstellungen zu finden.
Vielen Dank.