Passwortrichtlinien sind das Beste 😀 Manchmal führen sie jedoch zu Kontoabmeldungen, wenn jemand vergisst, sich von einer Sitzung irgendwo im Netzwerk abzumelden. Es könnte die TS-Sitzung sein, die einmal im Quartal für die Berichterstattung verwendet wird, oder vielleicht kennen Sie das Gefühl, wenn Sie per RDP auf einen Server zugreifen und feststellen, dass er von zwei anderen Administratoren gesperrt ist, die vergessen haben, sich abzumelden, als sie gingen. (Aus, weil so etwas nie passiert… wir verwenden alle PowerShell…) Jedenfalls musste ich in diesem Fall irgendwo im Netzwerk nach einer Benutzersitzung suchen. Am schlimmsten ist es, wenn mein eigenes Kennwort abläuft. Ich hasse es, wenn mein Konto am Ende gesperrt wird. Deshalb habe ich es mir zur Regel gemacht, alle Server zu überprüfen, bevor ich mein Passwort ändere. Es gibt mehrere Möglichkeiten, dies zu tun, aber ich neige natürlich dazu, die PowerShell-Route zu wählen.
Recherche
Die ursprüngliche Methode, die ich verwendet habe, stammt aus der TechNet-Galerie
Kurz gesagt: Get-WmiObject -Class Win32_process
Dies findet im Grunde alle einzelnen Benutzer, die Prozesse auf dem Computer ausführen. Das ist cool, weil es alles findet, sogar Dinge, die als Dienst laufen, aber ich bin nicht davon überzeugt, dass es der effizienteste Weg ist.
Bei der Suche mit Google finde ich eine Menge kreativer Wege, um zu überprüfen, wer an deinem Rechner angemeldet ist.
peetersonline.nl/2008/11/oneliner-get-logged-on-users-with-powershell/ brachte mich auf die Idee, Win32_LoggedOnUser zu überprüfen, was naheliegend scheint.
Das sieht gut aus und scheint auch mit Get-CimInstance zu funktionieren, obwohl die Ausgabe ein wenig anders ist.
learn-powershell.net/…/Quick-hit-find-currently-logged-on-users/ hat einen etwas altmodischeren Ansatz gewählt, den ich irgendwie mag, weil er ein wenig grob ist und mich zwingt, mit meinem templatebasierten Parsing zu spielen.
Ich bin mir nicht wirklich sicher, welche Methode schneller ist, also warum nicht versuchen, alle 3 in einem Modul zu implementieren und es auszuprobieren.
Skizzieren
Es ist immer eine gute Idee, damit zu beginnen, eine Skizze von dem zu machen, was man zu erreichen versucht.
Pseudo code:Get-ActiveUser -ComputerName -Method Wanted output:Username ComputerName-------- ------------TestUser1 Svr3TestUser3 Svr3DonaldDuck Client2
Jetzt habe ich alle Informationen, die ich brauche, um das GitHub-Repository einzurichten.
github.com/mrhvid/Get-ActiveUser
Code
Zuerst sind die Parameter, die mich interessieren, Computername und Methode.
Param ( # Computer name, IP, Hostname ] $ComputerName, # Choose method, WMI, CIM or Query $Method )
Ich habe bereits 3 mögliche Methoden im Kopf, also setze ich ValidateSet mit den 3 Möglichkeiten. Dann muss ich mich später nicht um diese Eingabe kümmern.
Process { switch ($Method) { 'WMI' { } 'CIM' { } 'Query' { } } }
Im Process-Teil meiner Funktion verwende ich einfach einen Schalter für die 3 verschiedenen Methoden, die ich im Parameter zugelassen habe.
Jetzt ist es ein einfaches Fill-in-the-Blanks.
WMI
Meine alte Lösung ist einfach und funktioniert gut.
$WMI = Get-WmiObject -Class Win32_Process -ComputerName $ComputerName -ErrorAction Stop$ProcessUsers = $WMI.getowner().user | Select-Object -Unique
Aber jetzt, wo ich Win32_LoggedOnUser gefunden habe, scheint es falsch zu sein, es so zu machen. Schauen wir uns stattdessen die neue Idee an.
Das sind alles die richtigen Daten, aber sie scheinen in einem String-Format zu sein, also muss ich sie ein wenig manipulieren. Dies kann auf eine Million Arten geschehen.
function Get-MyLoggedOnUsers { param($Computer) Get-WmiObject Win32_LoggedOnUser -ComputerName $Computer | Select Antecedent -Unique | %{"{0}{1}" -f $_.Antecedent.ToString().Split('"'), $_.Antecedent.ToString().Split('"')} }
Peters oben erwähnter Einzeiler schien mir nicht sehr leserfreundlich zu sein, was für einen Einzeiler in Ordnung ist, aber ich hätte ihn gerne etwas lesbarer, wenn möglich.
$WMI = (Get-WmiObject Win32_LoggedOnUser).Antecedent$ActiveUsers = @()foreach($User in $WMI) { $StartOfUsername = $User.LastIndexOf('=') + 2 $EndOfUsername = $User.Length - $User.LastIndexOf('=') -3 $ActiveUsers += $User.Substring($StartOfUsername,$EndOfUsername)}
Das scheint richtig zu sein 🙂 Ich werde die Ausgabe in der Variable $ActiveUsers speichern und das Gleiche für CIM und Query tun.
CIM
Lassen Sie es uns mit CIM versuchen.
Das sieht viel strukturierter aus.
CIM ist am Ende ein einfach zu verstehender Einzeiler 😀
$ActiveUsers = (Get-CimInstance Win32_LoggedOnUser -ComputerName $ComputerName).antecedent.name | Select-Object -Unique
Query
Mit der guten alten Query.exe fand ich das zuvor besprochene vorlagenbasierte Parsing sehr nützlich.
$Template = @' USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME>{USER*:jonas} console 1 Active 1+00:27 24-08-2015 22:22 {USER*:test} 2 Disc 1+00:27 25-08-2015 08:26'@$Query = query.exe user$ActiveUsers = $Query | ConvertFrom-String -TemplateContent $Template | Select-Object -ExpandProperty User
Output
Jetzt muss ich nur noch die Benutzer formatieren und auf eine schöne Art und Weise ausgeben. Ich möchte saubere Objekte mit ComputerName und UserName.
# Create nice output format$UsersComputersToOutput = @()foreach($User in $ActiveUsers) { $UsersComputersToOutput += New-Object psobject -Property @{ ComputerName=$ComputerName; UserName=$User } }}# output data$UsersComputersToOutput
Testen
Nun habe ich ein Problem. Ich kann das nicht testen, da ich nicht über eine Reihe von Testservern verfüge. Alle meine Tests habe ich mit meinem eigenen Windows 10 Rechner durchgeführt. Es scheint, dass die Abfrage viel schneller ist, wenn sie lokal ausgeführt wird, aber WMI/CIM könnte einen vollständigeren Überblick darüber geben, welche Dienste ausgeführt werden.
Ich habe eine Reihe von Standarddienstkonten laufen, die aus der Ausgabe entfernt werden könnten. Damit dies nützlich ist, müssen wir es auf vielen Rechnern ausführen.
Die Kombination von Get-ActiveUser mit Start-Multithread aus dem Beitrag von letzter Woche scheint wie vorgesehen zu funktionieren.
Start-Multithread -Script { param($C) Get-ActiveUser -ComputerName $C -Method Query } -ComputerName ::1,Localhost | Out-GridView
Das obige zu Out-GridView zu leiten ist wahrscheinlich mein persönlicher Favorit, um etwas wirklich Nützliches zu erreichen.
Jetzt haben wir alle Daten in einer schönen durchsuchbaren Weise und es ist wirklich einfach zu überprüfen, ob der Benutzer auf einem beliebigen Rechner angemeldet ist. Es ist auch ein einfacher Weg, um zu überprüfen, ob ein Benutzer im Netzwerk abtrünnig ist.
Veröffentlichung und Feedback
Der Code ist auf PowerShellGallery veröffentlicht.
Bitte helfen Sie mir, indem Sie ihn für mich testen. Ich würde gerne wissen, ob dies in der realen Welt funktioniert 🙂
# To install Get-ActiveUserInstall-Module Get-ActiveUser#To install Start-MultithreadInstall-Module Start-Multithread
Dies sollte funktionieren, wenn Sie WMF 5 + installiert haben und auf Windows 10 out of the box.