saschard
Goto Top

Anleitung: E-Mail versenden mit Powershell

Hallo Administratoren und Freunde der Shell,

back-to-top1. Allgemeines
hier ist eine Anleitung zur Versendung von E-Mails via Powershell.

Voraussetzung ist ein SMTP-Server.
back-to-top2. Erläuterung des Cmdlet
Ausschlaggebend zum Versenden von E-Mails ist das Send-MailMessage Cmdlet, welches seit Version 2.0 zur Verfügung steht.

In der Shell mit dem Befehl Send-MailMessage -?, erhaltet Ihr wie gewohnt eine Hilfsübersicht. Hier ist der Auszug der Syntax:
Send-MailMessage [-To] <string> [-Subject] <string> -From <string> [[-Body] <string>] [[-SmtpServer] <string>] [-Attachments <string[]>] [-Bcc <string[]>] [-BodyAsHtml] [-Cc <string[]>] [-Credential <PSCredential>] [-DeliveryNotificationOption {None | OnSuccess | OnFailure | Delay | Never}] [-Encoding <Encoding>] [-Priority {Normal | Low | High}] [-UseSsl] [<CommonParameters>]
back-to-top3 Die Basis
Eine einfache E-Mail kann mit dem folgenden Befehl über die Shell versandt werden:
Send-MailMessage –To "Empfänger@Adresse.de" –Subject "Test E-Mail" –Body "Dies ist meine erste E-Mail mit Powershell." –SmtpServer "ServerAdresse" –From "Absender@Powershell.de"  
Wichtig ist hier, dass im String für –To und –From ein @ vorkommt.
back-to-top3.1 Erste Modifizierung
Darauf aufbauend können weitere Werte hinzugefügt werden, wie z.B. -Cc, -Bcc oder -Priority
Send-MailMessage –To "Empfänger@Adresse.de" –CC „Empfänger@Adresse.de“ –Subject "Test E-Mail" –Body "Dies ist meine erste E-Mail mit Powershell." –SmtpServer "ServerAdresse" –From "Absender@Powershell.de"  
+++++ 3.2 Inhalt aus Logdatei
Im nächsten Schritt wird der Body, also der Inhalt der E-Mail so verändert, dass dieser als Inhalt den Inhalt einer Logdatei enthält.
$Logfile = “C:\meine_kleine.log”

Send-MailMessage –To "Empfänger@Adresse.de" –Subject "Test E-Mail" –Body (gc $Logfile | Out-String) –SmtpServer "ServerAdresse" –From "Absender@Powershell.de"  
+++++ 3.3 Absender automatisch generieren
Die nächste Modifizierung ist es, dass der Absender automatisch an Hand des Computernamens festgelegt wird. Dazu wird eine Variable zum Auslesen des Computernamens erstellt.
$PC = gc env:computername
$Logfile = “C:\meine_kleine.log”
Send-MailMessage –To "Empfänger@Adresse.de" –Subject "Test E-Mail" –Body (gc $logfile | Out-String) –SmtpServer "ServerAdresse" –From "Absender@$PC"  
+++++ 3.4 Batch
Und was ist mit Batch? Auch aus Batch heraus, kann eine E-Mail versandt werden.
powershell -ExecutionPolicy Unrestricted -c "Send-MailMessage -To 'Empfänger@Adresse.de' -Subject 'Test E-Mail aus Batch' -Body ‘Meine erste E-Mail aus Batch mit Powershell.’ -SmtpServer 'ServerAdresse' -From 'Absender@Powershell.de'"  
Warum wird die ExecutionPolicy mit angegeben? Die Standardeinstellung von Powershell erlaubt keine Ausführung von Skripten. Es muss also erst bestätigt bzw. erlaubt werden, ansonsten werdet Ihr eine Fehlermeldung erhalten. Falls die ExecutionPolicy bereits gesetzt wurden, kann dieser Befehl ignoriert werden.
back-to-top3.4.1 Batch mit Variablen
Natürlich können auch Variablen an den Powershell Befehl übergeben werden. Mit dem folgenden Beispiel seht Ihr wie es gemacht wird:
powershell -ExecutionPolicy Unrestricted -c "Send-MailMessage -To '%TO%' -Subject '%SUBJECT%' -Body ‘%BODY%’ -SmtpServer '%SMTP%' -From '%FROM%'"  
Wichtig hier bei sind die Anführungszeichen. Ihr müsst die Variablen in die Anführungszeichen schreiben, ansonsten führt es zu einer Fehlermeldung.
back-to-top3.4.1 Batch: Inhalt aus Logdatei
Auch in Batch ist es möglich den Wert einer Logdatei an den Powershell Befehl zu übergeben.
powershell -ExecutionPolicy Unrestricted -c "Send-MailMessage -To '%TO%' -Subject '%SUBJECT%' -Body (gc ‘%LOGFILE%’ | Out-String) -SmtpServer '%SMTP%' -From '%FROM%'"  
Und schon wird der Inhalt eurer Logdatei versendet.
back-to-top4 Als HTML
Ab hier wird der E-Mail Typ als HTML-Objekt versendet, somit ändert sich der gesamte Aufbau (dies ist für die weitere Verarbeitung notwendig).
function GenerateMail {
$SmtpClient = New-Object System.Net.Mail.SmtpClient
$SmtpClient.host = 'ServerAdresse'  
$PC = gc env:computername
$Mail = New-Object System.Net.Mail.MailMessage
$Mail.From = 'Absender@'+$PC  
$Mail.To.Add('Empfänger@Adresse.de')  
$Mail.IsBodyHtml = 1
$Mail.Subject = ‘Meine Erste HTML Mail’
$Mail.Body = GenerateHTMLBody
$SmtpClient.Send($Mail)
}
Wie zu sehen ist, werden die Befehle nun in Variablen unterteilt und sie befinden sich in einer Funktion.
Einige werden sich jetzt fragen, wieso?
Wird das Skript durchlaufen und es trifft aus diesen Code, wird automatisch eine E-Mail verschickt. Dies wird durch die Funktion aufgehoben, denn eine Funktion in Powershell muss explizit aufgerufen werden, damit der Code der sich innerhalb der Funktion befindet ausgeführt wird.

Variablen- und Funktionsnamen können für jeweiligen Zwecke angepasst werden.

In der Zeile
$Mail.Body = GenerateHTMLBody
ist zu sehen, dass der Variable des Textkörpers eine Funktion zugewiesen ist.
Der Code für die Generierung des HTML Textkörpers sieht wie folgt aus:
function GenerateHTMLBody {
$MailLog = gc $Logfile
Write-Output "  
 <html><head><title></title><style type=""text/css"">  
 table{margin-bottom:0px; margin-left:15px;}
 .Borderless{border:none; font-family:Arial, Helvetica, sans-serif; font-size:12px; color:#666666; border-collapse:collapse;}
 </style>
 </head><body>
"  
Foreach ($Log in $MailLog){
Write-Output "  
 <table>
 <tr>
 <td class="Borderless">$($Log)</td>  
 </tr>
 </table>
 </body></html>
"  
}
In diesem sind HTML-Stylesheet Informationen verbaut. Des Weiteren wird der Inhalt der Logdatei in einer tabellarischen Form im Textkörper ausgegeben. Dieses Konzept kann man nun beliebig erweitern, um z.B. Reports, Farbmarkierungen etc.
back-to-top4.1 HTML Erweiterung I: Farbmarkierungen
Wie oben als Beispiel bereits erwähnt ist eine Erweiterung dieses Grundkonstrukts nun beliebig erweiterbar. Die erste Erweiterung wird es sein, dass gewissen Ereignissen Farbinformationen zu gewiesen werden.
function LogColor {
 Param([Parameter(Position=0)]
 [String]$LogEntry)
 process {
  IF ($LogEntry.Contains("Debug")) {Return '<p class="Debug">'}  
  ELSEIF ($LogEntry.Contains("Warning")) {Return '<p class="Warning">'}  
  ELSEIF ($LogEntry.Contains("Exception")) {Return '<p class="Exception">'}  
  ELSE {Return ''}  
 }
}
Die Funktion aus dem Punkt 4. Als HTML muss anschließend um die folgenden Zeilen erweitert bzw. geändert werden. Dabei entfällt die Hilfsvariable $MailLog.
gc $Logfile | ForEach {Write-Output "<table><tr><td class="Borderless">"(LogColor $_</p>)$_"</tr></table>"}  
Alle Einträge die mit ein Ereignis Debug, Warning oder Exception gekennzeichnet bzw. beinhalten, werden in der jeweiligen Farbe markiert. Die Farbinformation wird einfach als Stylesheet hinzugefügt.
P{font-family:Arial, Helvetica, sans-serif; font-size:12px; color:#666666; margin-top:0px; margin-bottom:0px;}
P.Exception{color:#DB0000; font-weight:bold;}
P.Warning{color:#ff9900; font-weight:bold;}
P.Debug{color:#000000; font-weight:bold;}
Die Stichwörter für die Ereignisse können auf Eure Wünsche angepasst werden.
back-to-top5. Code Optimierung
Zuallererst sollte versucht werden, den Code so lesbar, schlank und übersichtlich wie nur möglich zu halten. Was ist das gewünschte Ziel? Für Ereignisse mit unterschiedlichen Zuständen, wird die jeweilige Information per E-Mail versandt, um dies zu realisieren sind hier einige Beispiele.

Das bereits vorhandene Grundkonstrukt aus dem Punkt 4 Als HTML wird erweitert:
function GenerateMail ($MailSubject){
$SmtpClient = New-Object System.Net.Mail.SmtpClient
$SmtpClient.host = 'ServerAdresse'  
$PC = gc env:computername
$Mail = New-Object System.Net.Mail.MailMessage
$Mail.From = 'Absender@'+$PC  
$Mail.To.Add('Empfänger@Adresse.de')  
$Mail.IsBodyHtml = 1
$Mail.Subject = $MailSubject
$Mail.Body = GenerateHTMLBody
$SmtpClient.Send($Mail)
}
Somit übergeben wir der Funktion die Variable $MailSubject, welche gleichzeitig unser Titel für den jeweiligen Zustand sein wird.
Function SendGeneratedWarningMail {
GenerateMail –MailSubject "Prozess XY hat eine Warnung auf $PC"  
}
Der Aufruf der Funktion GenerateMail wird durch die neue Funktion SendGeneratedWarningMail für den Zustand „Warnung“ ersetzt. Dies können wir jetzt beliebig wiederholen.
Function SendGeneratedSuccessMail {
GenerateMail –MailSubject "Prozess XY war Erfolgreich auf $PC"  
}
Mit dieser Struktur werden viele Zeilen Code, als auch jede Menge doppelte Zeilen Code abgelöst.

Die Anleitung wird in den nächsten Tagen noch um die folgenden Punkte erweitert.
  1. Ereignis Logging
  2. Weitere Methoden
  3. mit/ohne Authentifizierung
  4. SSL / TLS
  5. Dateianhänge


Gruß, Sascha

Content-Key: 275508

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

Printed on: June 23, 2024 at 15:06 o'clock

Mitglied: 114757
114757 Jun 24, 2015 updated at 14:31:09 (UTC)
Goto Top
Moin Sascha,
erstmal schöne Sache. Warum du aber das Konstrukt wegen HTML vollkommen änderst verstehe ich nicht, denn Send-MailMessage kennt ja den Parameter -BodyAsHTML face-wink

Die Funktionen würde ich dann etwas mehr generalisieren und mit Funktionsparametern versehen so das sie universeller weiterverwendbar sind. So wie hier z.B.
PowerShell 2.0 sendMail Skript

Auch wären ein paar Hinweise zur Authentifizierung und die Verwendung des Credential-Parameters noch eine sinnvolle Ergänzung. (New-Object PSCredential)

Gruß jodel32
Member: SaschaRD
SaschaRD Jun 24, 2015, updated at Jul 01, 2015 at 07:36:43 (UTC)
Goto Top
Hallo Jodel,

danke für dein Feedback.
Hatte es mit -BodyAsHTML mehrmals versucht. Dies führte leider nur zu Problemen mit dem Stylesheet etc., daher hatte ich das Grundgerüst umgemodelt.

Update:
Egal wie ich es dreh oder wende, mit dem folgenden Code ist es nicht möglich die Funktion (den Teil der den Textkörper generiert) zu senden.
Send-MailMessage –To "Empfänger@Adresse.de" –Subject $MailSubject -BodyAsHtml GenerateHTMLBody –SmtpServer "ServerAdresse" –From "HTML_Test@$PC"   
Als Body wird dann nur das Wort übermittelt anstatt die Funktion.

Gruß, Sascha
Member: Dani
Dani Jun 26, 2015 updated at 21:47:35 (UTC)
Goto Top
Guten Abend Sascha,
ich kann mich den Worten von @114757 nur anschließen. Sogar die Formatierungen wurden genutzt. Normalerweise muss der Author dazu überredet werden. face-smile
Was ich vermisse, ist der Versand über Authentifizierung und via TLS. Sollte beides heute Standard sein, bei neuen Implementierungen.


Gruß,
Dani
Member: DrAlcome
DrAlcome Jun 30, 2015 at 14:03:34 (UTC)
Goto Top
Hey cool, das kann ich für ein Paar Scripte anwenden um mir die Ergebnisse per Mail schicken zu lassen.
Dann muss ich nicht immer irgendwelche Log-Files per Hand raussuchen... wie ein Neandertaler! face-wink

Danke für den Tipp! face-smile
Member: SaschaRD
SaschaRD Jul 01, 2015 updated at 07:34:09 (UTC)
Goto Top
@Dani,

danke für dein Feedback. Habe es notiert und werde die Anleitung um die Punkte Authentifizierung und TLS erweitern.

@DrAlcome

das war mein Ziel =) Habe mir damit diverse Mail-Typen gebastelt für Reporting von den ESX-Server über PowerCLI, als auch für Feedback bei automatisierten Installationsprozessen.
So muss man nicht ständig auf das jeweilige Gerät und schauen ob die Prozedur fertig abgeschlossen wurde.

Gruß, Sascha
Member: FireEmerald
FireEmerald Nov 26, 2021 at 07:52:23 (UTC)
Goto Top
Achtung an die Copy/Paste Fraktion! In den ersten PS Zeilen sind keine normalen Bindestriche vorhanden, ihr bekommt nur eine kryptische Fehlermeldung - ersetzt diese händisch!
Falsch: –, Korrekt: -