everest
Goto Top

An- und Abmelde Ereignisse mit Powershell auslesen

Hallo PS-Scriptler,

hat jemand von euch ein Script, der bestimmte User (z.B. administrator) in der Domain ausließt, welcher angibt wer sich zuletz auf welchem Server einlogged hat?

Mit Get-ADUser oder mit Get-ADcomputer bekomme ich aber nicht zusammen!

Vielen Dank!
Everest

Content-ID: 328713

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

Ausgedruckt am: 18.11.2024 um 03:11 Uhr

H41mSh1C0R
H41mSh1C0R 07.02.2017 um 20:16:28 Uhr
Goto Top
Everest
Everest 07.02.2017 um 21:31:16 Uhr
Goto Top
Danke für schnelle Anwort. Ich teste es gleich morgen.
colinardo
Lösung colinardo 09.02.2017, aktualisiert am 04.03.2022 um 14:59:35 Uhr
Goto Top
Servus @Everest,
habe ich mal einen PS-Workflow geschrieben der "parallel" alle erreichbaren Server der Domain abgrast und die Daten zusammenfasst. Die lassen sich dann nach Wunsch filtern:

(Achtung PS-Workflows gibt es erst ab PS 3.0, den ThrottleLimit Parameter erst ab v4)
if ($PSVersionTable.PSVersion.Major -lt 4){write-host "ERROR: Minimum Powershell Version 4.0 is required!" -F Yellow; return}   
Import-Module ActiveDirectory

workflow Get-LastLogonEvents {
param(
    [parameter(mandatory=$false)][string]$SamAccountname = '*',  
    [parameter(mandatory=$false)][int]$MaxDays = 14,
    [parameter(mandatory=$false)][int]$timeout = 500,
    [parameter(mandatory=$false)][int]$throttlelimit = 5
)
    
    function Send-Ping {
        param([string]$device,[int]$delay)
        $ping = New-Object System.Net.NetworkInformation.Ping
        if($ping.Send($device,$delay).Status -ne "Success"){  
            return $false
        }else{
            return $true
        }
    }
    
    function Get-Serverlogs([string]$server,$SamAccountname){
        try{
            if ((Send-Ping $server $timeout)){
                Get-WinEvent -FilterXPath "*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (EventID=4624)] and EventData[(Data[@Name='Logontype'] and (Data=2 or Data=10) and (Data[@Name='TargetDomainName'] != 'Window Manager' and Data[@Name='TargetDomainName'] != 'Font Driver Host' ))] or System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (EventID=4647)]]" -LogName Security -ComputerName $server -EA Stop | ?{$_.TimeCreated -ge (get-date).AddDays(-$using:MaxDays)} | %{  
                    $xml = [xml]$_.toXML()
                    $username = $xml.Event.EventData.Data | ?{$_.Name -eq 'TargetUserName'} | %{$_.'#text'}  
                    if ($username -like $SamAccountname){
                        $ip = $xml.Event.EventData.Data | ?{$_.Name -eq 'IPAddress'} | %{$_.'#text'}  
                        $type = $xml.Event.EventData.Data | ?{$_.Name -eq 'LogonType'} | %{$_.'#text'}  
                        $logontype = @{"4647"="Logoff";"4624"=$(if($type -eq "10"){"Logon(Remote)"}else{"Logon"})}[$xml.Event.System.EventId]  
                        [pscustomobject]@{Server=$server;UserName=$username;Time=$_.TimeCreated;LogonType=$logontype;IP=$ip}
                    }
                }
            }
        }catch{}
    }
    # Fetch all computers with server operating system from AD
    $servers = Get-ADComputer -Filter {Operatingsystem -like "*Server*"} | select -Expand DNSHostName  

    # initiate parallel workflow over all servers
    foreach -parallel -throttlelimit $throttlelimit ($s in $servers){
        # call function to fetch filtered security eventlog from server
        Get-Serverlogs -server $s -SamAccountname $SamAccountname
    }
}
Get-LastLogonEvents -MaxDays 90 -SamAccountName 'Administrator' | sort Time -Descending | ft Server,Username,Time,LogonType,IP -GroupBy Server  
Der Aufruf des Workflows geschieht in der letzten Zeile.
Der Workflow kennt ein paar Parameter zur grundlegenden Filterung:
-SamAccountName : Username mit Wildcardunterstützung, wenn weggelassen werden alle Logons gelistet
-MaxDays : Max. Anzahl an Tagen welche die Logon/Logoff Vorgänge in die Vergangenheit reichen sollen / Bei Nichtangabe 14 Tage.
-timeout: Ping-Timeout wenn ein Server als nicht erreichbar gelten soll
-ThrottleLimit : Anzahl an parallelen auszuführenden Threads. / Ohne Angabe 5 parallele Threads

Vorraussetzung ist natürlich das die Remote-Verwaltung bei den Servern in der Firewall aktiviert ist und diese per Ping erreichbar sind.
Und natürlich Auszuführen mit einem Account der auf allen Servern die entsprechenden Rechte besitzt.

Des weiteren müssen die An-/ und Abmelde-Events auch im Security-Eventlog geloggt werden, dazu muss vorher folgende Einstellung gesetzt werden (per GPO oder lokal) damit die EventIDs 4624 und 4647 im Security Eventlog geloggt werden:

screenshot

Viel Spaß
Grüße Uwe

Falls der Beitrag gefällt, seid so nett und unterstützt mich durch eine kleine Spende / If you like my contribution please support me and donate
Everest
Everest 09.02.2017 um 14:33:09 Uhr
Goto Top
Hi Uwe oder Colinardo,

es ist super, dass du dir Zeit genommen hast so ein Script zu schreiben. Danke Dir dafür.

1) Zum Testen, kann ich anstatt:
$servers = Get-ADComputer -Filter {Operatingsystem -like "*Server*"} | select -Expand DNSHostName

$servers = Get-ADComputer -Filter testserver | select -Expand DNSHostName
nehmen?

2) ich habe PS v1 auf Windows Server 2008 Standard R2. Würde es auch gehen?

Danke.
Everest
colinardo
colinardo 09.02.2017 aktualisiert um 22:49:50 Uhr
Goto Top
Zitat von @Everest:
es ist super, dass du dir Zeit genommen hast so ein Script zu schreiben. Danke Dir dafür.
Kein Problem ist schon länger her face-smile
1) Zum Testen, kann ich anstatt:
$servers = Get-ADComputer -Filter testserver | select -Expand DNSHostName
nehmen?
Nein du musst hier im Filter die Filtereigenschaft angeben. Wenn du also auf einen bestimmten Server einschränken willst nimmst du
$servers = Get-ADComputer -Filter {Name -eq "testserver"} | select -Expand DNSHostName   
oder etwas langsamer auch mit
$servers = get-adcomputer -Filter * | ?{$_.Name -eq "testserver"} | select -Expand DNSHostName   
2) ich habe PS v1 auf Windows Server 2008 Standard R2. Würde es auch gehen?
Nicht mit obigem Workflow, dazu muss man es grundlegend umschreiben oder auf min. PS 3.0 aktualisieren.
Du kannst das Skript aber auch von jeder Verwaltungsstation mit aktueller Powershell und installiertem RSAT ausführen so musst du auf den Servern auch nicht zwingend was ändern.

Der Workflow hatte den einfachen Grund um den Vorgang einfach zu beschleunigen.

Die Hauptaufgabe erledigt ja wie du oben sehen kannst Zeile 22, die kannst du auch mit einer ganz einfachen Schleife über alle Server anwenden. Der Rest drum herum ist ja nur der Aufbau für die parallele Verarbeitung.

Alternative dazu wäre auch das zukünftige Einsammeln der Eventlogs auf einer zentralen Maschine dann entfällt das langwierige Abklappern aller Server.
Everest
Everest 10.02.2017 um 10:18:17 Uhr
Goto Top
Hi Uwe,

was ist falsch in der Zeile 44 ($s in $Servers)?
Bei der Ausgabe wird den Lokal PC in Form IP ausgegeben? So dass man genauer lokalisieren kann von welchem PC aus hat dieser bestimmte User gestartet.

Ich bin schon sehr gespannt auf das Ergebnis!
Danke Dir
Everest
ps_scripterror
colinardo
colinardo 10.02.2017, aktualisiert am 04.03.2022 um 14:59:48 Uhr
Goto Top
Zitat von @Everest:

Hi Uwe,

was ist falsch in der Zeile 44 ($s in $Servers)?
Dort ist nichts falsch.
Du verwendest einfach entweder nicht mindestens PS 3.0 oder hast irgendwo eine Klammer zu viel gesetzt.
Bei der Ausgabe wird den Lokal PC in Form IP ausgegeben? So dass man genauer lokalisieren kann von welchem PC aus hat dieser bestimmte User gestartet.
Wenn sich der User per Remote an diesem Server angemeldet hat wird in der Eigenschaft IP die Remote-IP des Clients vermerkt. Hat er sich lokal an der Konsole angemeldet steht dort die Loopback-Adresse oder ist leer.
Skript läuft hier sowohl auf 2008R2 ADs als auch 2012-2022. Wenn es von "Verwaltungsstationen" ausgeführt wird ist ein installiertes RSAT mit AD-Tools natürlich zusätzlich Vorraussetzung.
Des weiteren müssen die An-/ und Abmelde-Events auch im Security-Eventlog geloggt werden, dazu muss vorher folgende Einstellung gesetzt werden (per GPO oder lokal) damit die EventIDs 4624 und 4647 im Security Eventlog geloggt werden:


screenshot
Everest
Everest 10.02.2017 um 11:41:34 Uhr
Goto Top
Hi Uwe,

die Version 3 ist eigentlich installiert und ich habe auch alle Klammern { } ( ) durch gezählt, es sind je 23x.

Was macht genau diese Zeile
foreach-parallel -throttle $throttlelimit ($s in $servers) {
                  1. call function to fetch filtered security eventlog from server
                  Get-Serverlogs -server $s -SamAccountname $SamAccountname
                  }


                  ($s in $Server) unexpected token 'in' in Expression or Statement.

                  Danke Dir
                  Everest
                  psversion
132272
132272 10.02.2017 aktualisiert um 11:52:09 Uhr
Goto Top
Deine Powershell ist putt.
Zitat von @Everest:
Was macht genau diese Zeile
foreach-parallel -throttle $throttlelimit ($s in $servers) {
Lesen: about_Foreach-Parallel

Gruß
Everest
Everest 10.02.2017 um 12:29:39 Uhr
Goto Top
Hi Uwe,

da du so sicher warst, habe ich mir gedacht, dass es nur noch an PS liegen muss, so habe ich PS v4 installiert und es hat super funktioniert.

Du bist echt ein Genie!!
Vielllllllllllllllllle Grüße,
Everest
colinardo
colinardo 10.02.2017 aktualisiert um 12:39:41 Uhr
Goto Top
Ach, ich hatte den Parameter -Throttle nicht ausgeschrieben sondern abgekürzt der sollte komplett -ThrottleLimit heißen. Workflows sind da sehr penibel dort wollen die Parameter vollständig ausgeschrieben werden. Die PS 3.0 war da noch etwas penibler die PS4 verzeiht das. Immer diese leidige Versions-Fragmentierung mit der Zeit, kaum lässt man sich auf den Komfort einer Nachfolgeversion ein tritt man in die Sch.... face-smile

Freut mich das es dir hilft.
Viele Grüße
Uwe
jan.kleinel
jan.kleinel 17.02.2017 um 10:59:37 Uhr
Goto Top
Hey,

das Skript ist sehr hilfreich, nur wie kann ich alle in der Domäne gespeicherten Benutzer anzeigen lassen.
Also Admin und alle anderen Benutzer gleichzeitig.

Vielen Dank.
colinardo
colinardo 17.02.2017 aktualisiert um 11:06:02 Uhr
Goto Top
Servus,
Zitat von @jan.kleinel:
das Skript ist sehr hilfreich, nur wie kann ich alle in der Domäne gespeicherten Benutzer anzeigen lassen.
Also Admin und alle anderen Benutzer gleichzeitig.
Steht oben unter dem Skript:
Zitat:
-SamAccountName : Username mit Wildcardunterstützung, wenn weggelassen werden alle Logons gelistet
Parameter weglassen, freuen face-smile

Grüße Uwe
jan.kleinel
jan.kleinel 17.02.2017 um 11:08:38 Uhr
Goto Top
Danke Uwe für die Antwort, habe das genau dann ausprobiert als du geantwortet hast :D

Trozdem vielen Dank!
colinardo
colinardo 17.02.2017 aktualisiert um 11:30:42 Uhr
Goto Top
Zitat von @jan.kleinel:
Danke Uwe für die Antwort, habe das genau dann ausprobiert als du geantwortet hast :D
Na dann viel Spaß face-smile
Trozdem vielen Dank!
Immer gerne.

Falls es dich vielleicht noch interessiert:
Anmeldestatus von Benutzern im Active Directory speichern
jan.kleinel
jan.kleinel 16.03.2017 um 08:12:22 Uhr
Goto Top
Hey Leute,

könnte man das Ergebnis nicht theoretisch bei jedem starten in einem Textdokument speichern? Wenn ja wie wäre dieses möglich?

L.G.
colinardo
colinardo 16.03.2017 aktualisiert um 11:00:27 Uhr
Goto Top
Servus.
Zitat von @jan.kleinel:
könnte man das Ergebnis nicht theoretisch bei jedem starten in einem Textdokument speichern? Wenn ja wie wäre dieses möglich?
Hättest du den Thread aufmerksam gelesen dann hättest du gesehen das das Skript das per Remote schon aus den Rechnern ausliest, ein separates Ausführen auf jedem Client ist also unnötig. Die auszulesenden Rechner (im obigen Fall waren das ja nur die Server der Organisation) kannst du ja in der Zeile mit Get-AdComputer festlegen. Das Ergebnis kannst du am Ende einfach direkt an Export-CSV leiten und schon hast du deine gewünschte Datei die du nach Bedarf filtern kannst wie du lustig bist.

Für persönliche Anpassungen, gerne per PN (kostenpflichtig).

Grüße Uwe
novregen
novregen 11.04.2017 um 13:37:52 Uhr
Goto Top
Hallo Uwe,

ich würde gerne meine eigenen An- und Abmeldezeiten registrieren. Es handelt sich dabei um Domain Anmeldungen. Es gibt zwei DC.

Ich habe jetzt auf dem Primären DC Powershel von v1 auf v3 geupdatet. Powershel als Administrator geöffnet und dein Script unverändert per kopieren und einfügen eingefügt. Es wird leider nichts ausgegeben. Nach zweimaligen enter drücken, kommt folgende Fehlermeldungen. Wo liegt mein Fehler ? Throttlelimit scheint doch überall korrekt ausgeschrieben vorhanden.
Abspeichern als .ps und dann ausführen funktioniert auch nicht. Ausführung kann man kurz sehen, dann rote schrift und zu.

}
Get-LastLogonEvents -MaxDays 90 -SamAccountName 'Administrator' | sort Time -Descending | ft Server,Us

In Zeile:36 Zeichen:23

back-to-topforeach -parallel -throttlelimit $throttlelimit ($s in $servers){

back-to-top~~~~~~~~~~~~~~

Der Parameter "throttlelimit" ist für die Anweisung "foreach" nicht zulässig.
In Zeile:36 Zeichen:12

back-to-topforeach -parallel -throttlelimit $throttlelimit ($s in $servers){

back-to-top~

Öffnende "(" fehlt nach dem Schlüsselwort "foreach".
In Zeile:36 Zeichen:53

back-to-topforeach -parallel -throttlelimit $throttlelimit ($s in $servers){

back-to-top~

Unerwartetes Token "(" in Ausdruck oder Anweisung.
In Zeile:36 Zeichen:57

back-to-topforeach -parallel -throttlelimit $throttlelimit ($s in $servers){

back-to-top~~

Unerwartetes Token "in" in Ausdruck oder Anweisung.
In Zeile:36 Zeichen:56

back-to-topforeach -parallel -throttlelimit $throttlelimit ($s in $servers){

back-to-top~

Schließende ")" fehlt in einem Ausdruck.
In Zeile:1 Zeichen:30

back-to-topworkflow Get-LastLogonEvents {

back-to-top~

Schließende "}" fehlt im Anweisungsblock.
In Zeile:36 Zeichen:68

back-to-topforeach -parallel -throttlelimit $throttlelimit ($s in $servers){

back-to-top~

Unerwartetes Token ")" in Ausdruck oder Anweisung.
In Zeile:40 Zeichen:1

back-to-top}

back-to-top~

Unerwartetes Token "}" in Ausdruck oder Anweisung.
+ CategoryInfo : ParserError: (face-smile , ParentContainsErrorRecordException
+ FullyQualifiedErrorId : InvalidForeachFlag
132895
132895 11.04.2017 um 13:52:03 Uhr
Goto Top
colinardo
colinardo 11.04.2017 aktualisiert um 13:55:43 Uhr
Goto Top
Zitat von @132895:

-ThrottleLimit benötigt min. PS V4
http://www.happysysadm.com/2013/06/how-to-throttle-workflow-activites-i ...

hauruck
Korrrekt. Hatte ich oben vergessen zu erwähnen, ist nachgeholt.
novregen
novregen 11.04.2017 um 13:57:55 Uhr
Goto Top
Könnte man auf ThrottleLimit verzichten, wenn evtl. nur ein Server (sollte dann ja der Primäre DC) abgefragt wird ?
Wie müßte das Script dann aussehen oder geht das nicht ?
colinardo
colinardo 11.04.2017 um 14:01:32 Uhr
Goto Top
Klar, kannst du weg lassen.
novregen
novregen 11.04.2017 um 15:20:59 Uhr
Goto Top
Hallo,
ich hab versucht das auszukommentieren, jedoch ohne Erfolg. Könnte mir jemand weiterhelfen, wie ich das Script für PS 3.0 anpasse und ggfs. auch einfach nur für einen Server und einen User. Danke.


Windows PowerShell
Copyright (C) 2012 Microsoft Corporation. Alle Rechte vorbehalten.

PS C:\Users\######> if ($PSVersionTable.PSVersion.Major -lt 4){write-host "ERROR: Minimum Powershell Versio 
n 4.0 is required!" -F Yellow; return}  
ERROR: Minimum Powershell Version 4.0 is required!
PS C:\Users\#####> Import-Module ActiveDirectory
PS C:\Users\#####> workflow Get-LastLogonEvents {
>> param(
>>     [parameter(mandatory=$false)][string]$SamAccountname = '*',  
>>     [parameter(mandatory=$false)][int]$MaxDays = 14,
>>     [parameter(mandatory=$false)][int]$timeout = 500,
>>    # [parameter(mandatory=$false)][int]$throttlelimit = 5
>> )
>>
In Zeile:5 Zeichen:54
+     [parameter(mandatory=$false)][int]$timeout = 500,
+                                                      ~
Ausdruck nach "," fehlt.  
In Zeile:1 Zeichen:30
+ workflow Get-LastLogonEvents {
+                              ~
Schließende "}" fehlt im Anweisungsblock.  
    + CategoryInfo          : ParserError: (:) , ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingExpressionAfterToken

PS C:\Users\#####>     function Send-Ping {
>>         param([string]$device,[int]$delay)
>>         $ping = New-Object System.Net.NetworkInformation.Ping
>>         if($ping.Send($device,$delay).Status -ne "Success"){  
>>             return $false
>>         }else{
>>             return $true
>>         }
>>     }
>>
PS C:\Users\#####>     function Get-Serverlogs([string]$server,$SamAccountname){
>>         try{
>>             if ((ping $server,$timeout)){
>>                 Get-WinEvent -FilterXPath "*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (EventI  
D=4624)] and EventData[(Data[@Name='Logontype'] and (Data=2 or Data=10) and Data[@Name='TargetDomainName'] != 'Window Ma  
nager')] or System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (EventID=4647)]]" -LogName Security -Comput  
erName $server -EA Stop | ?{$_.TimeCreated -ge (get-date).AddDays(-$using:MaxDays)} | %{
>>                     $xml = [xml]$_.toXML()
>>                     $username = $xml.Event.EventData.Data | ?{$_.Name -eq 'TargetUserName'} | %{$_.'#text'}  
>>                     if ($username -like $SamAccountname){
>>                         $ip = $xml.Event.EventData.Data | ?{$_.Name -eq 'IPAddress'} | %{$_.'#text'}  
>>                         $type = $xml.Event.EventData.Data | ?{$_.Name -eq 'LogonType'} | %{$_.'#text'}  
>>                         $logontype = @{"4647"="Logoff";"4624"=$(if($type -eq "10"){"Logon(Remote)"}else{"Logon"})}[$x  
ml.Event.System.EventId]
>>                         [pscustomobject]@{Server=$server;UserName=$username;Time=$_.TimeCreated;LogonType=$logontype;
IP=$ip}
>>                     }
>>                 }
>>             }
>>         }catch{}
>>     }
>>     # Fetch all computers with server operating system from AD
>>     $servers = Get-ADComputer -Filter {Operatingsystem -like "*Server*"} | select -Expand DNSHostName  
>>
PS C:\Users\Administrator.#####>     # initiate parallel workflow over all servers
PS C:\Users\Administrator.#####>     # foreach -parallel -throttlelimit $throttlelimit ($s in $servers){
PS C:\Users\Administrator.#####>         # call function to fetch filtered security eventlog from server
PS C:\Users\Administrator.#####>         Get-Serverlogs -server $s -SamAccountname $SamAccountname
PS C:\Users\Administrator.#####>     }
In Zeile:1 Zeichen:5
+     }
+     ~
Unerwartetes Token "}" in Ausdruck oder Anweisung.  
    + CategoryInfo          : ParserError: (:) , ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken

PS C:\Users\Administrator.#####> }
In Zeile:1 Zeichen:1
+ }
+ ~
Unerwartetes Token "}" in Ausdruck oder Anweisung.  
    + CategoryInfo          : ParserError: (:) , ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken

PS C:\Users\Administrator.#####> Get-LastLogonEvents -MaxDays 90 -SamAccountName 'Administrator' | sort Time -Descending 
 | ft Server,Username,Time,LogonType,IP -GroupBy Server
132895
132895 11.04.2017 aktualisiert um 15:40:23 Uhr
Goto Top
Junge du führst das einfach falsch aus, geht hier nämlich testweise absolut fehlerfrei!
Das pastet man nicht in die Konsole so wie du das hier machst. Für einen Server nehm dir doch einfach die Function aus dem Workflow raus face-smile. Man oh man, die Leute können echt nur noch copy n Paste ...
novregen
novregen 11.04.2017 um 16:10:57 Uhr
Goto Top
Ja scheint so. Update auf PS 4.0 ist leider auf dem Server nicht möglich. Von PS Scripten habe ich wirklich keine Ahnung, deshalb hatte ich ja gefragt, wie das ausgeführt werden muss und entsprechend mit den Fehlerangaben gepostet.
132895
132895 11.04.2017 aktualisiert um 16:18:12 Uhr
Goto Top
Von PS Scripten habe ich wirklich keine Ahnung
Dann solltest du das erst mal ändern und dann wieder kommen. Man kann hier ja nicht jedem das "Fahren" beibringen face-wink. Mitdenken musst du schon, nimm nur die Function Get-ServerLogs die enthält ja alles was du brauchst, alles andere drum herum ist ja nur dafür da, viele Server gleichzeitig/parallel zu verarbeiten. Ohne minimal Hirn einschalten und sich grundlegend mit dem Inhalt zu beschäftigen wirst du mit Powershell nie warm!

p.s. So ein schöner Thread durch deine Unwissenheit verunstaltet face-confused
novregen
novregen 12.04.2017 um 08:48:27 Uhr
Goto Top
Ob du es glaubs oder nicht, auch nur die Get Funktion habe ich per Konsole PS 3.0 versucht, ohne Erfolg.

Werde diesen Thread aber auch nicht weiter verunstalten und mich an deinen fachlichen Kommentaren erfreuen.
Cool, dann brauch ich bei euch nicht mehr zur Arbeit wenn ich die Kiste per Remote hoch und runter fahre :-P
Fohnbit
Fohnbit 04.03.2022 um 08:31:11 Uhr
Goto Top
Hallo!

ich würde das Script auch gerne nutzen (Server 2019), aber ich erhalte keine Ausgabe.
Läuft ohne Fehler durch.

Aufruf im Script mit:
Get-LastLogonEvents | sort Time -Descending | ft Server,Username,Time,LogonType,IP -GroupBy Server

Ist das Script für Windows Server 2019 nicht passend?