Ein besserer Weg, um einen angemeldeten Benutzer remote mit PowerShell zu finden

Es gibt viele verschiedene Möglichkeiten, angemeldete Benutzer zu erhalten, aber ich habe einen Favoriten! Bei Verwendung von qwinsta besteht das einzige Problem darin, dass eine Zeichenfolge zurückgegeben wird und PowerShell Objekte mag: ( Aber keine Angst! Wir können das beheben.

qwinsta

Voraussetzungen

Beim ersten Start von qwinsta ist ein Fehler 5 aufgetreten. Es gibt einen Registrierungsfix dafür (danke StackOverflow:

"AllowRemoteRPC"=dword:00000001

Da es sich um einen PowerShell-Blog handelt, finden Sie hier die PowerShell-Syntax zum Hinzufügen zu einem Remotecomputer, da wir wahrscheinlich auf Remotecomputern arbeiten werden.

$ComputerName = 'Computer' #replace with the computer name$LMtype = ::LocalMachine$LMkey = "SYSTEM\CurrentControlSet\Control\Terminal Server"$LMRegKey = ::OpenRemoteBaseKey($LMtype,$ComputerName)$regKey = $LMRegKey.OpenSubKey($LMkey,$true)If($regKey.GetValue("AllowRemoteRPC") -ne 1){ $regKey.SetValue("AllowRemoteRPC",1) Start-Sleep -Seconds 1}$regKey.Dispose()$LMRegKey.Dispose()

Syntax

Die Syntax von qwinsta ist ziemlich einfach:

qwinsta /server:ServerName

Und die Ausgabe sieht eher unmenacing:

 SESSIONNAME USERNAME ID STATE TYPE DEVICE services 0 Disc console Anthony 1 Active rdp-tcp 65536 Listen

Das einzige Problem ist, dass es keine einfache Möglichkeit gibt, Zeichenfolgen in PowerShell zu filtern, wenn Sie sich einen RDS-Server angesehen haben. Du könntest also nichts tun wie:

qwinsta /server:RDSServer | Where-Object USERNAME -like "Anth*"

Aber wir können das beheben! Wickeln wir qwinsta ein, damit wir diese Ausgabe objektivieren können!

Wrapping qwinsta

Wir werden hier eine PowerShell-Funktion erstellen, Leser aufgepasst.

Die Zeichenfolge für ihre Werte auswringen

Neben all dem Parametermaterial, zu dem wir kommen werden, ist das erste, was wir tun werden, die Ausgabe an eine Variable zu richten:

$result = qwinsta /server:$ComputerName

Jetzt sieht $result genauso aus wie die vorherige Ausgabe, wird jedoch als String-Array formatiert (string ). Das können wir natürlich verifizieren mit Get-Member:

($result | Get-Member).TypeName

Das nächste ist also, nur die Informationen abzurufen, die wir wollen. Ich habe mich für eine for-Schleife entschieden und die erste Zeile übersprungen, da wir die Header nicht benötigen:

ForEach($line in $result)

Womit wird für jede Zeile jeder Wert begrenzt? Räume! So können wir die verwenden .Split () -Methode für Strings und Split mit jedem Leerzeichen. Die einzige Einschränkung ist, dass wir auch bei jedem Split auf Wert testen müssen, da Sie mehrere Leerzeichen aufteilen und Nullwerte erhalten können.

$tmp = $line.split(" ") | ?{$_.length -gt 0}

Zu beachten ist, dass die Ausgabe von qwinsta eine feste Breite hat, was bedeutet, dass sich die Breite nicht ändert, unabhängig davon, wie lang die Werte sind. Wir können das ausnutzen und bestimmte Indizes zu unserem Vorteil nutzen.

Zuerst müssen Sie feststellen, welche Zeilen tatsächlich einen Benutzer enthalten. Wir können Zeichen zählen und feststellen, dass der Benutzernamenwert beim 19. Zeichen beginnt (das erste Zeichen ist eigentlich das Leerzeichen, schauen Sie genau hin). Wenn also das 19. Zeichen nicht leer ist, haben wir einen Benutzer.

If(($line -ne " "))

Das nächste, was mir beim Testen mit qwinsta aufgefallen ist, ist, dass die Eigenschaft SessionName nur dann einen Wert hat, wenn sich die Sitzung im Status ‘Aktiv’ befindet. Wir müssen also auch überprüfen, ob der Status ‘Aktiv’ ist, was wir tun können, indem wir den Index dieses Status auf ein ‘A’ überprüfen’

If($line -eq "A")

Wenn es ‘Aktiv’ ist, hat die Variable $tmp unterschiedliche Werte.

Aktiv:

#raw rdp-tcp#0 anthony 2 Active #$tmp variable (split)rdp-tcp#0anthony2Active

Nicht aktiv:

#raw anthony 2 Disc #$tmp variable (split)anthony2Disc

Konvertieren der Werte in verwendbare Objekte

Sobald wir alle Werte herausgefunden haben, können wir ein neues PSObject erstellen, mein Favorit! Wenn Sie PowerShellv5 haben, können Sie den {} Typ accelerator (x) , aber ich werde das New-Object Cmdlet hier für ultimative Kompatibilität verwenden.

New-Object PSObject -Property @{ "ComputerName" = $ComputerName "SessionName" = $tmp "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $tmp}

In diesem Fall, da wir wissen, dass die Sitzung aktiv ist, ist die erste Zeichenfolge in $tmp der Sitzungsname, und dann haben Sie der Reihe nach den Rest der Eigenschaften. Es ist möglich, dass ‘Type’ oder ‘SessionName’ leer zurückgegeben werden.

Wenn der Status nicht ‘Aktiv’ ist, würden wir das auf:

New-Object PSObject -Property @{ "ComputerName" = $ComputerName "SessionName" = $null "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $null}

Das Endprodukt

Da dies kein Beitrag zum Erstellen von Funktionen ist, werde ich die andere Syntax überspringen und Ihnen die endgültige Funktion zeigen, die ich geschrieben habe. Dies beinhaltet einige Best-Practice-Dinge wie die Überprüfung auf Konnektivität und Administratorrechte, bevor Sie sich mit den aufregenden Dingen befassen.

Function Get-ActiveSessions{ Param( $Name , $Quiet ) Begin{ $return = @() } Process{ If(!(Test-Connection $Name -Quiet -Count 1)){ Write-Error -Message "Unable to contact $Name. Please verify its network connectivity and try again." -Category ObjectNotFound -TargetObject $Name Return } If(((::GetCurrent()).groups -match "S-1-5-32-544")){ #check if user is admin, otherwise no registry work can be done #the following registry key is necessary to avoid the error 5 access is denied error $LMtype = ::LocalMachine $LMkey = "SYSTEM\CurrentControlSet\Control\Terminal Server" $LMRegKey = ::OpenRemoteBaseKey($LMtype,$Name) $regKey = $LMRegKey.OpenSubKey($LMkey,$true) If($regKey.GetValue("AllowRemoteRPC") -ne 1){ $regKey.SetValue("AllowRemoteRPC",1) Start-Sleep -Seconds 1 } $regKey.Dispose() $LMRegKey.Dispose() } $result = qwinsta /server:$Name If($result){ ForEach($line in $result){ #avoiding the line 0, don't want the headers $tmp = $line.split(" ") | ?{$_.length -gt 0} If(($line -ne " ")){ #username starts at char 19 If($line -eq "A"){ #means the session is active ("A" for active) $return += New-Object PSObject -Property @{ "ComputerName" = $Name "SessionName" = $tmp "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $tmp } }Else{ $return += New-Object PSObject -Property @{ "ComputerName" = $Name "SessionName" = $null "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $null } } } } }Else{ Write-Error "Unknown error, cannot retrieve logged on users" } } End{ If($return){ If($Quiet){ Return $true } Else{ Return $return } }Else{ If(!($Quiet)){ Write-Host "No active sessions." } Return $false } }}

Get-ActiveSessions

Sie finden dies in meinem Utilities GitHub Repo. Dies ist mein erstes veröffentlichtes Skript! Hurra! Also lass uns darüber gehen, wie man es benutzt:

Einfache Verwendung

Um die an einem Remote- oder lokalen Computer angemeldeten Benutzer abzurufen, verwenden wir einfach:

Get-ActiveSessions ComputerName

Und das sollte etwas Ähnliches zurückgeben:

ID : 2SessionName :Type :UserName : anthonyComputerName : dc01State : Disc

Und wenn Sie es an eine Variable übergeben und sich den Typnamen ansehen, sollten wir ein PSCustomObject haben, was bedeutet, dass wir alle anderen nützlichen Cmdlets zum Filtern und so weiter verwenden können!

$sessions = Get-ActiveSessions ComputerName($sessions | Get-Member).TypeNameSystem.Management.Automation.PSCustomObject

Erweiterte Verwendung

Wir haben hier zwei Dinge für uns, wir können Pipeline-Eingaben akzeptieren UND es wird ein Objekt ausgegeben. So können wir Sachen vor und nach Get-ActiveSessions machen.

Was ist, wenn Sie alle Server in Ihrer Umgebung finden möchten, auf denen ein bestimmter Benutzer angemeldet ist?

Get-ADComputer -Filter {OperatingSystem -like '*Server*'} | Get-ActiveSessions | Where-Object UserName -eq 'Anthony'

Oder wie wäre es, eine Liste von Computern aus einer Textdatei zu ziehen und die Liste der eindeutigen Benutzer auszugeben, die bei allen angemeldet sind?

get-content C:\temp\computers.txt | Get-ActiveSessions | Select-Object -Unique UserName -ExpandProperty UserName | Out-File C:\temp\users.txt

Wenn Sie nützliche Verwendungen von Get-ActiveSessions finden, kommentieren Sie!

Fazit

Hoffentlich haben Sie eine Wertschätzung dafür, warum ich eine Funktion schreiben würde, um dieses Zeug für mich zu tun. Ich konnte ehrlich gesagt nicht zählen, wie oft ich dies verwendet habe, um meine Arbeit zu erleichtern.

Wie auch immer, ich habe ein paar bemerkenswerte Beiträge, besonders der Partner zu Get-ActiveSessions: Close-ActiveSessions .

Spoiler:

Get-ActiveSessions Computer | Close-ActiveSessions

Und auch: ‘Geplante Aufgaben für PowerShell-Skripte erstellen’, was eine Reise sein wird, da ich noch keine Bilder gemacht habe!

Leave a Reply