From 6fd1167cd85d416effe9a045a2e0cfcf61a966af Mon Sep 17 00:00:00 2001 From: scriptos Date: Sun, 26 Apr 2026 13:02:04 +0200 Subject: [PATCH] Update 4.0 - Zusammenfuehrung AD/Local, Config-Datei, Ntfy-Support Co-authored-by: Copilot --- LICENSE | 27 ++- README.md | 49 ++-- .../rdp-access-mail-notification.v1.ps1 | 92 ------- .../rdp-access-mail-notification.v2.ps1 | 52 ---- ...htigung bei RDP Anmeldung (AD Version).xml | Bin 4382 -> 0 bytes .../rdp-access-mail-notification.v3.ad.ps1 | 92 ------- config.conf | 26 ++ docs/configuration.md | 92 +++++++ docs/prerequisites.md | 51 ++++ docs/task-scheduler.md | 67 ++++++ ...gung bei RDP Anmeldung (Local Version).xml | Bin 4226 -> 0 bytes .../rdp-access-mail-notification.v3.local.ps1 | 74 ------ rdp-access-notification.ps1 | 225 ++++++++++++++++++ rdp-access-notification.xml | 47 ++++ screenshots/notification.png | Bin 32346 -> 0 bytes 15 files changed, 563 insertions(+), 331 deletions(-) delete mode 100644 ad-version/.archiv/rdp-access-mail-notification.v1.ps1 delete mode 100644 ad-version/.archiv/rdp-access-mail-notification.v2.ps1 delete mode 100644 ad-version/Mailbenachrichtigung bei RDP Anmeldung (AD Version).xml delete mode 100644 ad-version/rdp-access-mail-notification.v3.ad.ps1 create mode 100644 config.conf create mode 100644 docs/configuration.md create mode 100644 docs/prerequisites.md create mode 100644 docs/task-scheduler.md delete mode 100644 local-version/Mailbenachrichtigung bei RDP Anmeldung (Local Version).xml delete mode 100644 local-version/rdp-access-mail-notification.v3.local.ps1 create mode 100644 rdp-access-notification.ps1 create mode 100644 rdp-access-notification.xml delete mode 100644 screenshots/notification.png diff --git a/LICENSE b/LICENSE index b03ff96..45ebd56 100644 --- a/LICENSE +++ b/LICENSE @@ -1,11 +1,28 @@ MIT License -Copyright (c) 2023 scriptos +Copyright © -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Name: Patrick Asmus (scriptos) +Email: support@techniverse.net +Website: https://www.patrick-asmus.de +Blog: https://www.cleveradmin.de -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +--- -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -Patrick Asmus | www.media-techport.de \ No newline at end of file +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 2b4b7b3..ee818cd 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,40 @@ -# Benachrichtigungsmail bei Anmeldung per Remote Desktop Protokoll +

+ + Techniverse Community + +

+

RDP Login Notifier

-**1. Skript: rdp-access-mail-notification.v3.ad.ps1** +

+ Versendet Benachrichtigungen (E-Mail und/oder Ntfy Push) wenn sich jemand per RDP auf einem Windows-System anmeldet. +

-- **Beschreibung:** Dieses Skript sendet eine E-Mail-Benachrichtigung an alle Mitglieder einer Sicherheitsgruppe, wenn sich jemand per Remote Desktop Protocol (RDP) auf einem Windows-System anmeldet. Es extrahiert Informationen aus dem Ereignisprotokoll und informiert die Benutzer über die Anmeldung, einschließlich Datum, Uhrzeit, Domäne, Benutzer und IP-Adresse des Clients. +
+ 🏰 Website + · + 📰 Community + · + 🐘 Mastodon + · + 💬 Support +
+

-**Voraussetzung:** -Folgendes Modul muss auf allen Systemen, auf denen das Script läuft, installiert sein: +## Schnellstart -Dies kann man einfach per Powershell machen: +1. [Voraussetzungen](docs/prerequisites.md) pruefen (RSAT-Modul bei AD-Modus installieren) +2. `rdp-access-notification.ps1`, `config.conf` und `rdp-access-notification.xml` nach `C:\scripts\rdp-login-notifier` kopieren +3. `config.conf` anpassen — siehe [Konfiguration](docs/configuration.md) +4. Task-Scheduler-Aufgabe einrichten — siehe [Task-Scheduler](docs/task-scheduler.md) - Install-WindowsFeature RSAT-AD-PowerShell +

+

+ +

- -**2. Skript: rdp-access-mail-notification.v3.local.ps1** - -- **Beschreibung:** Dieses Skript sendet eine E-Mail-Benachrichtigung, wenn sich jemand per Remote Desktop Protocol (RDP) auf einem Windows-System anmeldet. Es verwendet Informationen aus dem Ereignisprotokoll, um die Benutzer über die Anmeldung zu informieren, einschließlich Datum, Uhrzeit, Domäne, Benutzer und IP-Adresse des Clients. Die Benachrichtigung geht an eine vordefinierte Empfängeradresse. - - -Das ganze könnte dann so aussehen: - -![notification](/screenshots/notification.png) \ No newline at end of file +

+ + © Patrick Asmus · Techniverse Network · Lizenz + +

\ No newline at end of file diff --git a/ad-version/.archiv/rdp-access-mail-notification.v1.ps1 b/ad-version/.archiv/rdp-access-mail-notification.v1.ps1 deleted file mode 100644 index 1637b78..0000000 --- a/ad-version/.archiv/rdp-access-mail-notification.v1.ps1 +++ /dev/null @@ -1,92 +0,0 @@ -# Konfigurationsparameter -$SMTPServer = "smtp.media-techport.int" -$FromName = "Media-Techport.DE | Notification Service" -$FromEmail = "noreply@media-techport.de" -$SecurityGroupDN = "CN=GG-MailAT_RDP-Access,OU=Benachrichtigungsgruppen,OU=Benutzergruppen,DC=media-techport,DC=int" - -# Überwachung der Ereignisprotokolle -$EventLogName = "Security" -$EventID = 1149 # Event ID für Anmeldungen - -# Filter für Ereignisse -$FilterXML = @" - - - - - -"@ - -# Funktion zum Senden von E-Mails -function Send-Email { - param( - [string]$To, - [string]$Subject, - [string]$Message, - [string]$GivenName, - [string]$Surname - ) - $EmailBody = @" - - - - - - - -

Logo-Schwarz

-

Hallo $GivenName $Surname,

-

$Message

- - -"@ - - Send-MailMessage -SmtpServer $SMTPServer -From "$FromName <$FromEmail>" -To $To -Subject $Subject -Body $EmailBody -BodyAsHtml -Encoding "UTF8" -} - -# Hauptüberwachungsschleife -$events = Get-WinEvent -LogName $EventLogName -FilterXPath $FilterXML -foreach ($event in $events) { - $eventTime = $event.TimeCreated - $clientIP = $event.Properties[18].Value # IP-Adresse des Clients - $serverIP = $env:COMPUTERNAME # IP-Adresse des Servers - $user = $event.Properties[5].Value - $domain = $event.Properties[6].Value - - $userEmails = Get-ADGroupMember -Identity $SecurityGroupDN | Where-Object { $_.objectClass -eq "user" } | ForEach-Object { - $userDetails = Get-ADUser $_.DistinguishedName -Properties GivenName, Surname, EmailAddress - $GivenName = $userDetails.GivenName - $Surname = $userDetails.Surname - $EmailAddress = $userDetails.EmailAddress - [PSCustomObject]@{ - EmailAddress = $EmailAddress - GivenName = $GivenName - Surname = $Surname - } - } - - $emailMessage = @" -Es wurde eine Anmeldung per RDP auf dem Windows Server $serverIP registriert.

-Datum: $($eventTime.ToString('dd.MM.yyyy'))
-Uhrzeit: $($eventTime.ToString('HH:mm:ss'))
-Domäne: $domain
-Benutzer: $user
-IP-Adresse des Clients: $clientIP -"@ - foreach ($userDetail in $userEmails) { - Send-Email -To $userDetail.EmailAddress -Subject "RDP-Anmeldung auf $serverIP registriert" -Message $emailMessage -GivenName $userDetail.GivenName -Surname $userDetail.Surname - } -} diff --git a/ad-version/.archiv/rdp-access-mail-notification.v2.ps1 b/ad-version/.archiv/rdp-access-mail-notification.v2.ps1 deleted file mode 100644 index 4fea0bc..0000000 --- a/ad-version/.archiv/rdp-access-mail-notification.v2.ps1 +++ /dev/null @@ -1,52 +0,0 @@ -# Konfigurationsparameter -$SMTPServer = "smtp.media-techport.int" -$FromName = "Media-Techport.DE | Notification Service" -$FromEmail = "noreply@media-techport.de" -$SecurityGroupDN = "CN=GG-MailAT_RDP-Access,OU=Benachrichtigungsgruppen,OU=Benutzergruppen,DC=media-techport,DC=int" - -# Funktion zum Senden von E-Mails -function Send-Email { - param( - [string]$To, - [string]$Subject, - [string]$Message - ) - - Send-MailMessage -SmtpServer $SMTPServer -From "$FromName <$FromEmail>" -To $To -Subject $Subject -Body $Message -BodyAsHtml -Encoding "UTF8" -} - -# Parameter aus dem Ereignisprotokoll auslesen -$eventID = 1149 # Event ID für RDP-Anmeldungen -$eventLogName = "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational" - -$latestEvent = Get-WinEvent -LogName $eventLogName -FilterXPath "" | Select-Object -First 1 - -if ($latestEvent) { - $xml = [xml]$latestEvent.ToXml() - - if ($xml.Event.UserData) { - $user = $xml.Event.UserData.EventXML.Param1 - $domain = $xml.Event.UserData.EventXML.Param2 - $clientIP = $xml.Event.UserData.EventXML.Param3 - - $eventTime = $latestEvent.TimeCreated - $computerName = $latestEvent.MachineName - - $userEmails = Get-ADGroupMember -Identity $SecurityGroupDN | Where-Object { $_.objectClass -eq "user" } | ForEach-Object { - Get-ADUser $_.DistinguishedName -Properties EmailAddress | Select-Object -ExpandProperty EmailAddress - } - - $emailMessage = @" -Es wurde eine Anmeldung per RDP auf dem Windows Server $computerName registriert.

-Datum: $($eventTime.ToString('dd.MM.yyyy'))
-Uhrzeit: $($eventTime.ToString('HH:mm:ss'))
-Domäne: $domain
-Benutzer: $user
-IP-Adresse des Clients: $clientIP -"@ - - foreach ($email in $userEmails) { - Send-Email -To $email -Subject "RDP-Anmeldung auf $computerName registriert" -Message $emailMessage - } - } -} diff --git a/ad-version/Mailbenachrichtigung bei RDP Anmeldung (AD Version).xml b/ad-version/Mailbenachrichtigung bei RDP Anmeldung (AD Version).xml deleted file mode 100644 index 3301d036011d57ac05219af26d7b9a99b38e16db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4382 zcmd6rT~8ZF6o$`rrTzzti=?gO4?YT|HC9PL!4fo-m~sKRaIgaiV=S)&p}()ctL^ii zVc4Cup$?U*YQ@fa=FEG(&z#|}KbzLEu4Q&<6}z#%jrqQ?Ya7~zE!d*fY=yC6pY6&9 z%w|4+ZWEr7{b+Tb%uel`y;qJ@W4vHy3`)k|M<{FjzGl8|x2z4V$FEyf>$YSKo)x|t zeAj*NgmH2&)q=I`Yx@cbD%P|ExSWBIu|9@kaxZHe%#UE^w1IxhY5L5I&yp=$6`dNq zml!*|m(byRTjSlZA6#3F>qxW=MH5MKj3`II-n38fKZolW{4INHd-jL@V%v6NuaI-- z>%Y5Ag_F{!SchoV2IT~dE;X3KEDJ~cf;Jwed$@~?&23R-J ze8cP(YrnY^(X-#WUXf>%L^95AU&W2&I^zjZQ?~uK$I}q0Q_7Ss*m4`$yJ$23tA`!r z-A{Z=rt(^pS3AS*chG+DD3nAax052cWiLRS*iZJWqmAv(cA-%8yg+WPOjA_wM9-tV z;gP@ZF?8-Td+bglyJ|J{h?6WRqzW-1`v0@s-`O$NxpRN0dK@FOs)lUUbB&MfXELhm zalK(L$&UZt{x9u4)|5wjjCoYI$*c`(#3Hp~9h&zKu~c`TM^BU^tzL-6r`F1ms$6(H z(u-LUvPRYXsq7O~nwc3H6LFgE3&rp$HXot?06*pHA@k&~l&0do)7eq1cf~56=j|bg z$`$2X3*A(kt5oAqovYY&iOL)-yke_V=yj)AWYnpl>aA+M%IpeXYrI!kTj#y%SWAq{ zJkmAg7WK@f*(LJMJR3X2q%yAMIg}ygE%Rff6wWNVX|w~c!MmWy4+F6Dt&?_gZ&^jT zVnkUk-02-fR8dS@JNL)z^`gg`9+f(`<*~CF-rPfG)l2zXlC`0eyo&u(erHH<&5CmH z4vpHN4Baw)vb2wtB*mAaq*`u)o_VwlK)yw0@gMVUbHcxc-z$Dg3q{U_OVwf}#AmSN z^Dt65#P=FIi0d1^g3TV|Up%kAY-h@K6YB=OcUFGG%j+9Go(vIrN8B|*o%Q_n$kNwz31fNUdxKG_j zxg&`lo<&#W9#GX&W$+GBT-;N(@l%vVTxD65?`gf7*f>U1?m@}0g;eU-r?s1JM=DRb zM=Rz-c`eS1POP$+7)Ooe$Skv=ypYrPQ zd{QpuJ$gnj7SjF1{SETco0{WTCWG+J - - - - - - $HTMLBody - - -"@ - - Send-MailMessage -SmtpServer $SMTPServer -From "$FromName <$FromEmail>" -To $To -Subject $Subject -Body $emailMessage -BodyAsHtml -Encoding "UTF8" -} - -# Parameter aus dem Ereignisprotokoll auslesen -$eventID = 1149 # Event ID für RDP-Anmeldungen -$eventLogName = "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational" - -$latestEvent = Get-WinEvent -LogName $eventLogName -FilterXPath "" | Select-Object -First 1 - -if ($latestEvent) { - $xml = [xml]$latestEvent.ToXml() - - if ($xml.Event.UserData) { - $user = $xml.Event.UserData.EventXML.Param1 - $domain = $xml.Event.UserData.EventXML.Param2 - $clientIP = $xml.Event.UserData.EventXML.Param3 - - $eventTime = $latestEvent.TimeCreated - $computerName = $latestEvent.MachineName - - $userEmails = Get-ADGroupMember -Identity $SecurityGroupDN | Where-Object { $_.objectClass -eq "user" } | ForEach-Object { - $userDetails = Get-ADUser $_.DistinguishedName -Properties GivenName, Surname, EmailAddress - $GivenName = $userDetails.GivenName - $Surname = $userDetails.Surname - $EmailAddress = $userDetails.EmailAddress - [PSCustomObject]@{ - EmailAddress = $EmailAddress - GivenName = $GivenName - Surname = $Surname - } - } - - foreach ($userDetails in $userEmails) { - $GivenName = $userDetails.GivenName - $Surname = $userDetails.Surname - $EmailAddress = $userDetails.EmailAddress - - $HTMLBody = @" - - - - - -

-

Hallo $GivenName $Surname,

-

Es wurde eine Anmeldung per RDP auf der Windows Maschine $computerName registriert.

Datum: $($eventTime.ToString('dd.MM.yyyy'))
Uhrzeit: $($eventTime.ToString('HH:mm:ss'))
Domäne: $domain
Benutzer: $user
IP-Adresse des Clients: $clientIP

- - -"@ - - Send-Email -To $EmailAddress -Subject "RDP-Anmeldung auf $computerName registriert" -HTMLBody $HTMLBody - } - } -} diff --git a/config.conf b/config.conf new file mode 100644 index 0000000..be68f5c --- /dev/null +++ b/config.conf @@ -0,0 +1,26 @@ +# RDP Access Notification - Konfiguration +# Dokumentation: docs/configuration.md + +# Modus: ad | local +MODE=ad + +# Benachrichtigungsmethoden: email, ntfy oder email,ntfy +NOTIFICATION_METHODS=email + +# E-Mail +SMTP_SERVER= +SMTP_FROM_NAME= +SMTP_FROM_EMAIL= + +# AD-Modus (nur bei MODE=ad) +AD_SECURITY_GROUP_DN= + +# Local-Modus (nur bei MODE=local, Format: Name,Email;Name,Email) +LOCAL_RECIPIENTS= + +# Ntfy (nur wenn ntfy in NOTIFICATION_METHODS) +NTFY_SERVER=https://ntfy.sh +NTFY_TOPIC= +NTFY_PRIORITY=3 +NTFY_TAGS=warning,computer +NTFY_AUTH_TOKEN= diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000..401e467 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,92 @@ +# Konfiguration + +Alle Einstellungen werden in der `config.conf` vorgenommen, die im selben Verzeichnis wie das Script liegen muss. + +## Modus + +| Wert | Beschreibung | +|---|---| +| `MODE=ad` | Empfaenger werden aus einer AD-Sicherheitsgruppe gelesen | +| `MODE=local` | Empfaenger werden manuell in der Konfiguration definiert | + +**RSAT-Modul installieren (nur fuer AD-Modus):** + +```powershell +Install-WindowsFeature RSAT-AD-PowerShell +``` + +## Benachrichtigungsmethoden + +Kommasepariert — einzeln oder kombiniert: + +``` +NOTIFICATION_METHODS=email +NOTIFICATION_METHODS=ntfy +NOTIFICATION_METHODS=email,ntfy +``` + +## E-Mail + +| Key | Beschreibung | +|---|---| +| `SMTP_SERVER` | SMTP-Server Adresse | +| `SMTP_FROM_NAME` | Anzeigename des Absenders | +| `SMTP_FROM_EMAIL` | E-Mail-Adresse des Absenders | + +Beispiel: + +``` +SMTP_SERVER=smtp.example.com +SMTP_FROM_NAME=Notification Service +SMTP_FROM_EMAIL=noreply@example.com +``` + +## AD-Modus + +Nur relevant wenn `MODE=ad`. + +| Key | Beschreibung | +|---|---| +| `AD_SECURITY_GROUP_DN` | Distinguished Name der AD-Sicherheitsgruppe, deren Mitglieder benachrichtigt werden | + +Beispiel: + +``` +AD_SECURITY_GROUP_DN=CN=Gruppe,OU=Gruppen,DC=domain,DC=local +``` + +## Local-Modus + +Nur relevant wenn `MODE=local`. Mehrere Empfaenger mit Semikolon trennen. + +| Key | Beschreibung | +|---|---| +| `LOCAL_RECIPIENTS` | Empfaengerliste im Format `Name,Email;Name,Email` | + +Beispiel: + +``` +LOCAL_RECIPIENTS=Max Mustermann,max@example.com;Lisa Mueller,lisa@example.com +``` + +## Ntfy Push-Benachrichtigung + +Nur relevant wenn `ntfy` in `NOTIFICATION_METHODS` enthalten ist. + +| Key | Beschreibung | +|---|---| +| `NTFY_SERVER` | URL des Ntfy-Servers | +| `NTFY_TOPIC` | Ntfy-Topic | +| `NTFY_PRIORITY` | Prioritaet 1-5 (1=min, 3=default, 5=max) | +| `NTFY_TAGS` | Kommaseparierte Emoji-Tags | +| `NTFY_AUTH_TOKEN` | Bearer-Token (leer lassen wenn nicht benoetigt) | + +Beispiel: + +``` +NTFY_SERVER=https://ntfy.sh +NTFY_TOPIC=rdp-access +NTFY_PRIORITY=3 +NTFY_TAGS=warning,computer +NTFY_AUTH_TOKEN=tk_geheim123 +``` diff --git a/docs/prerequisites.md b/docs/prerequisites.md new file mode 100644 index 0000000..39272ed --- /dev/null +++ b/docs/prerequisites.md @@ -0,0 +1,51 @@ +# Voraussetzungen + +## PowerShell ExecutionPolicy + +Windows blockiert standardmaessig die Ausfuehrung von PowerShell-Scripts. Es gibt zwei Moeglichkeiten, das Script ausfuehrbar zu machen: + +**Variante 1 — Nur fuer die Task-Scheduler-Aufgabe (empfohlen):** + +In der Aufgabe wird `-ExecutionPolicy Bypass` als Argument uebergeben. Das betrifft nur diese eine Ausfuehrung und aendert keine systemweite Einstellung. Details dazu in der [Task-Scheduler-Dokumentation](task-scheduler.md). + +**Variante 2 — Systemweit erlauben:** + +```powershell +Set-ExecutionPolicy RemoteSigned -Scope LocalMachine +``` + +## RSAT ActiveDirectory PowerShell-Modul + +Das AD-Modul wird nur benoetigt, wenn `MODE=ad` in der `config.conf` gesetzt ist. Im Local-Modus (`MODE=local`) kann dieser Abschnitt uebersprungen werden. + +### Windows Server + +```powershell +Install-WindowsFeature RSAT-AD-PowerShell +``` + +Ein Neustart ist in der Regel nicht erforderlich. + +### Windows Client (Windows 10 / 11 Pro oder Enterprise) + +```powershell +Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 +``` + +Alternativ ueber DISM: + +```cmd +DISM /Online /Add-Capability /CapabilityName:Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 +``` + +Nach der Installation pruefen, ob das Modul verfuegbar ist: + +```powershell +Get-Module -ListAvailable -Name ActiveDirectory +``` + +### Wichtige Hinweise zum AD-Modus + +- Das Zielsystem muss Mitglied der Domaene sein. +- Das Script laeuft als `SYSTEM` (S-1-5-18) und nutzt das Computerkonto fuer AD-Abfragen. Dafuer sind keine separaten Credentials noetig. +- Die Windows Home-Edition unterstuetzt weder RDP-Host noch RSAT und ist daher nicht kompatibel. diff --git a/docs/task-scheduler.md b/docs/task-scheduler.md new file mode 100644 index 0000000..94c63c5 --- /dev/null +++ b/docs/task-scheduler.md @@ -0,0 +1,67 @@ +# Task-Scheduler einrichten + +Die Aufgabe wird durch das Windows-Event **1149** im Log `Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational` ausgeloest. Dieses Event wird bei jeder erfolgreichen RDP-Anmeldung geschrieben. + +## Variante 1 — XML importieren (empfohlen) + +Die mitgelieferte Datei `rdp-access-notification.xml` kann direkt importiert werden: + +**Per PowerShell:** + +```powershell +Register-ScheduledTask -Xml (Get-Content "C:\scripts\rdp-access-notification.xml" -Raw) -TaskName "RDP Access Notification" +``` + +**Per Aufgabenplanung (GUI):** + +1. Aufgabenplanung oeffnen (`taskschd.msc`) +2. Aktion > Aufgabe importieren +3. Die Datei `rdp-access-notification.xml` auswaehlen +4. Bei Bedarf den Pfad zum Script unter *Aktionen* anpassen + +## Variante 2 — Manuell anlegen + +### Allgemein + +| Einstellung | Wert | +|---|---| +| Name | `RDP Access Notification` | +| Ausfuehren als | `SYSTEM` | +| Unabhaengig von der Benutzeranmeldung ausfuehren | Ja | +| Mit hoechsten Privilegien ausfuehren | Nein | + +### Trigger + +| Einstellung | Wert | +|---|---| +| Trigger-Typ | Bei einem Ereignis | +| Protokoll | `Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational` | +| Quelle | `Microsoft-Windows-TerminalServices-RemoteConnectionManager` | +| Ereignis-ID | `1149` | + +### Aktion + +| Einstellung | Wert | +|---|---| +| Programm/Script | `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` | +| Argumente | `-ExecutionPolicy Bypass -File "C:\scripts\rdp-access-notification.ps1"` | + +Der Parameter `-ExecutionPolicy Bypass` sorgt dafuer, dass das Script auch ohne systemweite Aenderung der ExecutionPolicy ausgefuehrt wird. Er gilt nur fuer diesen einen Prozess. + +### Einstellungen + +| Einstellung | Wert | +|---|---| +| Aufgabe bei Bedarf starten | Ja | +| Aufgabe beenden, falls laenger als | 72 Stunden | +| Nicht starten, falls im Akkubetrieb | Nein | + +## Aufgabe testen + +Nach dem Anlegen kann die Aufgabe manuell ausgeloest werden: + +```powershell +Start-ScheduledTask -TaskName "RDP Access Notification" +``` + +Oder im Aufgabenplaner per Rechtsklick > *Ausfuehren*. diff --git a/local-version/Mailbenachrichtigung bei RDP Anmeldung (Local Version).xml b/local-version/Mailbenachrichtigung bei RDP Anmeldung (Local Version).xml deleted file mode 100644 index 671034c4dc1b8cdf7d35cf148016cf759b710616..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4226 zcmd6rT~8ZF6o$`rrTzzti=?gOk3cGt)>w4{DwaY*36u-S1;GR?Y-8;@5c=cWKJOWZ z-C5hzp;A??@a)cw_SZ-@Itg=?$vC5YCbXoIBS5pe|GUHgpu3#4Z7e+9C!&-~$5)XtP5-F<*A zJ@y^j4j2d6_M>w+aa(50$fnZo9Ij)2Yfdp>+ym1tW0(06yN1{^(tKxcKy(VvAr!wm zmgv#%U7sj9;t|s2?W%YYx^tcoEmfOuc^r+wo>HcC!G>FCaDrY#c=fS{y!x4UVXCf0 zyxJLdzlZjtN1qT)+**ppK>s_z;f*)R4MJrvy=_LLm? z@9qE8K449Gq|aDHb&u@Zpf)_CM!baP!+k6@-RIF0RWCJ5(fH6>HByxeizB_96(MU> z#UIK(QKgxglQEG`+kK%JKE>t}^dI7wf%C3!-*B#mcxl(~vxR;NPi`Rir7 zwB7eQ6=j$6IX2q?v#OG;Dr7zAgjW%E%6ATeD^?Wgw`kOZ%b1yrwYU7;xE^22CDn2h z?z#JP2Z5-+l( zqGXC!6*HGhNPP^46oWEYv8)qlaqP#_I`~|O<3647)pI|3cphC@df=+gB}aCM;_{xV zjUS>c^Hr`#d=Kl@#>O$C3J(gyCaBa6&uX{ajucO|6DsFJbuHbwP1N;ybRtykk*=lt zW+Nk7q{`(X%9Q8gx*?0nJFz$FQW+*5Q#rm3w~?ycf6Fb!7EYuCa16*J)xAFQ!>vZW zwW_kJx~#4Hhx)d(Qap}BisF!nxrFmR8650d)p{O9%43V0nmR$`CQ>(^8d29Cco;JFnUKxKDYtIG>bDMJJroafJ?9HTeq?{;9KQ z - - - - - - $HTMLBody - - -"@ - - Send-MailMessage -SmtpServer $SMTPServer -From "$FromName <$FromEmail>" -To $To -Subject $Subject -Body $emailMessage -BodyAsHtml -Encoding "UTF8" -} - -# Parameter aus dem Ereignisprotokoll auslesen -$eventID = 1149 # Event ID für RDP-Anmeldungen -$eventLogName = "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational" - -$latestEvent = Get-WinEvent -LogName $eventLogName -FilterXPath "" | Select-Object -First 1 - -if ($latestEvent) { - $xml = [xml]$latestEvent.ToXml() - - if ($xml.Event.UserData) { - $user = $xml.Event.UserData.EventXML.Param1 - $domain = $xml.Event.UserData.EventXML.Param2 - $clientIP = $xml.Event.UserData.EventXML.Param3 - - $eventTime = $latestEvent.TimeCreated - $computerName = $latestEvent.MachineName - - $HTMLBody = @" - - - - - -

-

Hallo Patrick Asmus,

-

Es wurde eine Anmeldung per RDP auf der Windows Maschine $computerName registriert.

Datum: $($eventTime.ToString('dd.MM.yyyy'))
Uhrzeit: $($eventTime.ToString('HH:mm:ss'))
Domäne: $domain
Benutzer: $user
IP-Adresse des Clients: $clientIP

- - -"@ - - Send-Email -To $ManualRecipient -Subject "RDP-Anmeldung auf $computerName registriert" -HTMLBody $HTMLBody - } -} diff --git a/rdp-access-notification.ps1 b/rdp-access-notification.ps1 new file mode 100644 index 0000000..f287256 --- /dev/null +++ b/rdp-access-notification.ps1 @@ -0,0 +1,225 @@ +# Script Name: rdp-access-notification.ps1 +# Beschreibung: Versendet Benachrichtigungen (E-Mail / Ntfy) bei RDP-Anmeldung +# Autor: Patrick Asmus +# Web: https://www.patrick-asmus.de +# Git-Reposit.: https://git.techniverse.net/scriptos/rdp-access-mailbenachrichtigung.git +# Version: 4.0 +# Datum: 26.04.2026 +# Modifikation: Zusammenfuehrung AD/Local, Config-Datei, Ntfy-Support +##################################################### + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$configPath = Join-Path $scriptDir "config.conf" + +if (-not (Test-Path $configPath)) { + Write-Error "Konfigurationsdatei nicht gefunden: $configPath" + exit 1 +} + +# --- Config parsen --- + +$conf = @{} +foreach ($line in Get-Content -Path $configPath) { + $line = $line.Trim() + if ($line -eq "" -or $line.StartsWith("#")) { continue } + $parts = $line -split "=", 2 + if ($parts.Count -eq 2) { + $conf[$parts[0].Trim()] = $parts[1].Trim() + } +} + +# --- Funktionen --- + +function Send-Email { + param( + [string]$To, + [string]$RecipientName, + [string]$Subject, + [string]$ComputerName, + [string]$EventDate, + [string]$EventTime, + [string]$Domain, + [string]$User, + [string]$ClientIP + ) + + $htmlBody = @" + + + + + + + +
+
RDP-Zugriff erkannt
+
+

Hallo $RecipientName,

+

auf der Windows-Maschine $ComputerName wurde eine RDP-Anmeldung registriert.

+ + + + + + +
Datum$EventDate
Uhrzeit$EventTime
Domäne$Domain
Benutzer$User
IP-Adresse des Clients$ClientIP
+
+ +
+ + +"@ + + if (-not $To) { + Write-Warning "Kein Empfaenger fuer E-Mail (Name: $RecipientName) - uebersprungen" + return + } + + try { + Send-MailMessage ` + -SmtpServer $conf["SMTP_SERVER"] ` + -From "$($conf["SMTP_FROM_NAME"]) <$($conf["SMTP_FROM_EMAIL"])>" ` + -To $To ` + -Subject $Subject ` + -Body $htmlBody ` + -BodyAsHtml ` + -Encoding ([System.Text.Encoding]::UTF8) ` + -ErrorAction Stop + } + catch { + Write-Error "E-Mail an $To fehlgeschlagen: $_" + } +} + +function Send-Ntfy { + param( + [string]$Title, + [string]$Message + ) + + $ntfyUrl = "$($conf["NTFY_SERVER"])/$($conf["NTFY_TOPIC"])" + + $headers = @{ + "Title" = $Title + "Priority" = $conf["NTFY_PRIORITY"] + "Tags" = $conf["NTFY_TAGS"] + } + + if ($conf["NTFY_AUTH_TOKEN"]) { + $headers["Authorization"] = "Bearer $($conf["NTFY_AUTH_TOKEN"])" + } + + try { + Invoke-RestMethod ` + -Uri $ntfyUrl ` + -Method Post ` + -Headers $headers ` + -Body ([System.Text.Encoding]::UTF8.GetBytes($Message)) ` + -ContentType "text/plain; charset=utf-8" + } + catch { + Write-Error "Ntfy-Benachrichtigung fehlgeschlagen: $_" + } +} + +# --- RDP-Event auslesen --- + +$eventID = 1149 +$eventLogName = "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational" + +$latestEvent = Get-WinEvent -LogName $eventLogName -FilterXPath "" | Select-Object -First 1 + +if (-not $latestEvent) { + exit 0 +} + +$xml = [xml]$latestEvent.ToXml() + +if (-not $xml.Event.UserData) { + exit 0 +} + +$user = $xml.Event.UserData.EventXML.Param1 +$domain = $xml.Event.UserData.EventXML.Param2 +$clientIP = $xml.Event.UserData.EventXML.Param3 +$eventTime = $latestEvent.TimeCreated +$computerName = $latestEvent.MachineName + +$eventDate = $eventTime.ToString('dd.MM.yyyy') +$eventTimeStr = $eventTime.ToString('HH:mm:ss') +$subject = "RDP-Anmeldung auf $computerName registriert" + +# --- Empfaenger ermitteln --- + +$recipients = @() + +switch ($conf["MODE"]) { + "ad" { + $adMembers = Get-ADGroupMember -Identity $conf["AD_SECURITY_GROUP_DN"] | Where-Object { $_.objectClass -eq "user" } + foreach ($member in $adMembers) { + $adUser = Get-ADUser $member.DistinguishedName -Properties GivenName, Surname, EmailAddress + $recipients += [PSCustomObject]@{ + Name = "$($adUser.GivenName) $($adUser.Surname)" + Email = $adUser.EmailAddress + } + } + } + "local" { + foreach ($entry in $conf["LOCAL_RECIPIENTS"] -split ";") { + $entry = $entry.Trim() + if ($entry -eq "") { continue } + $parts = $entry -split ",", 2 + if ($parts.Count -eq 2) { + $recipients += [PSCustomObject]@{ + Name = $parts[0].Trim() + Email = $parts[1].Trim() + } + } + } + } + default { + Write-Error "Unbekannter Modus: $($conf["MODE"]). Erlaubt: 'ad', 'local'" + exit 1 + } +} + +# --- Benachrichtigungen versenden --- + +$methods = $conf["NOTIFICATION_METHODS"] -split "," + +if ($methods.Trim() -contains "email") { + foreach ($recipient in $recipients) { + Send-Email ` + -To $recipient.Email ` + -RecipientName $recipient.Name ` + -Subject $subject ` + -ComputerName $computerName ` + -EventDate $eventDate ` + -EventTime $eventTimeStr ` + -Domain $domain ` + -User $user ` + -ClientIP $clientIP + } +} + +if ($methods.Trim() -contains "ntfy") { + $ntfyMessage = @" +Maschine: $computerName +Datum: $eventDate +Uhrzeit: $eventTimeStr +Domaene: $domain +Benutzer: $user +Client-IP: $clientIP +"@ + + Send-Ntfy -Title $subject -Message $ntfyMessage +} diff --git a/rdp-access-notification.xml b/rdp-access-notification.xml new file mode 100644 index 0000000..6300e29 --- /dev/null +++ b/rdp-access-notification.xml @@ -0,0 +1,47 @@ + + + + 2026-04-26T00:00:00 + Administrator + \Benachrichtigung bei RDP Anmeldung + + + + true + <QueryList><Query Id="0" Path="Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational"><Select Path="Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational">*[System[Provider[@Name='Microsoft-Windows-TerminalServices-RemoteConnectionManager'] and EventID=1149]]</Select></Query></QueryList> + + + + + S-1-5-18 + LeastPrivilege + + + + IgnoreNew + false + true + true + false + false + + true + false + + true + true + false + false + false + true + false + PT72H + 7 + + + + C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe + -ExecutionPolicy Bypass -File "C:\scripts\rdp-login-notifier\rdp-access-notification.ps1" + + + diff --git a/screenshots/notification.png b/screenshots/notification.png deleted file mode 100644 index 6ebac9038a8ed1d9b53de81883cec371524d1e1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32346 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

-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