een betere manier om een ingelogde gebruiker op afstand te vinden met behulp van PowerShell

er zijn een berg van verschillende manieren om ingelogde gebruikers te krijgen, maar ik heb een favoriet! Met qwinsta is het enige probleem dat het een string retourneert en PowerShell houdt van objecten : (maar wees nooit bang! Daar kunnen we wat aan doen.

qwinsta

Prereqs

ik liep in een fout 5 Toegang geweigerd probleem toen ik voor het eerst begon met het gebruik van qwinsta, er is een Register fix voor dat (Dank u StackOverflow:

"AllowRemoteRPC"=dword:00000001

aangezien dit een PowerShell blog is, is hier de PowerShell syntaxis om het toe te voegen aan een externe computer, omdat we waarschijnlijk zullen werken op externe computers.

$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()

syntaxis

de syntaxis van qwinsta is vrij eenvoudig:

qwinsta /server:ServerName

en de output ziet er nogal onbeheersbaar uit:

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

het enige probleem is dat als je op zoek was naar een RDS-server, er geen gemakkelijke manier is om strings in PowerShell te filteren. Dus je kon niet zoiets doen als:

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

maar dat kunnen we oplossen! Laat wrap qwinsta, zodat we kunnen objectiveren die output!

Wrapping qwinsta

we gaan hier een PowerShell-functie maken, reader let op.

de string voor zijn waarden wringen

naast alle parameter dingen, die we zullen krijgen om, het eerste kern ding dat we zullen doen is om de output te sturen naar een variabele:

$result = qwinsta /server:$ComputerName

nu zal $result er net zo uitzien als de uitvoer van daarvoor, maar het zal worden geformatteerd als een string array (string). We kunnen dat natuurlijk verifiëren met Get-Member:

($result | Get-Member).TypeName

dus het volgende ding is om alleen de informatie die we willen. Ik heb besloten om een voor lus, overslaan van de eerste regel omdat we niet nodig de headers:

ForEach($line in $result)

waarmee wordt voor elke regel elke waarde afgebakend? Spaces! Dus we kunnen het gebruiken .Split () methode op strings en splitsen met elke spatie. Het enige voorbehoud is dat we ook moeten testen voor waarde op elke splitsing, omdat je meerdere spaties kunt splitsen en null-waarden kunt krijgen.

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

een ding om op te merken is dat de uitvoer van qwinsta vaste breedte is, wat betekent dat de breedte niet verandert ongeacht hoe lang een van de waarden is. We kunnen daar gebruik van maken en bepaalde indexen in ons voordeel gebruiken.

het eerste wat je moet doen is bepalen welke regels een gebruiker bevatten. We kunnen karakters tellen en vinden dat de gebruikersnaam waarde begint bij het 19e teken (het eerste teken is eigenlijk de spatie, kijk goed). Dus als het 19e teken niet leeg is, hebben we een gebruiker.

If(($line -ne " "))

het volgende wat me opviel bij het testen met qwinsta is dat de eigenschap SessionName alleen waarde heeft als de sessie zich in de ‘actieve’ toestand bevindt. Dus moeten we ook controleren of de staat ‘actief’ is, wat we kunnen doen door de index van die staat te controleren voor een ‘A’

If($line -eq "A")

als het “actief” is, zal de variabele $tmp verschillende waarden hebben.

Actief:

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

Niet Actief:

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

het omzetten van de waarden naar bruikbare objecten

zodra we alle waarden hebben uitgedokterd, kunnen we een nieuw PSObject maken, mijn favoriet! Als je PowerShellv5 hebt, kun je de {} type accelerator (x) gebruiken, maar ik gebruik hier de New-Object cmdlet voor ultieme Compatibiliteit.

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

in dit geval, omdat we weten dat de sessie actief is, is de eerste tekenreeks in $tmp de sessienaam, en dan, in volgorde, heb je de rest van de eigenschappen. Het is mogelijk dat ‘Type’ of ‘SessionName’ leeg terug kan komen.

als de status niet ‘actief’ is, schakelen we dat om naar:

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

het eindproduct

aangezien dit geen post is over het maken van functies, ga ik de andere syntaxis overslaan en de laatste functie die ik schreef laten zien. Dit omvat een aantal best practice dingen zoals het controleren van connectiviteit en admin rechten voordat je in de spannende dingen.

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

u kunt dit vinden in mijn hulpprogramma ‘ s GitHub repo. Dit is mijn eerste gepubliceerde script! Hoera! Dus laten we gaan over hoe het te gebruiken:

eenvoudig gebruik

om de gebruikers op te halen die ingelogd zijn op een externe of lokale computer, gebruiken we gewoon:

Get-ActiveSessions ComputerName

en dit zou iets gelijkaardigs moeten opleveren:

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

en als je het doorgeeft aan een variabele en naar de type naam kijkt, zouden we een PSCustomObject moeten hebben, wat betekent dat we alle andere nuttige cmdlets kunnen gebruiken om te filteren en zo!

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

geavanceerd gebruik

we hebben hier twee dingen voor ons, we kunnen pijplijn invoer accepteren en het maakt een object. Dus we kunnen dingen doen voor en na Get-ActiveSessions.

wat als u alle servers in uw omgeving wilt vinden waarop een bepaalde gebruiker is ingelogd?

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

of wat dacht je van een lijst met computers uit een tekstbestand te trekken en de uitvoer van de lijst van unieke gebruikers aangemeld bij hen allemaal?

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

als u met een nuttig gebruik van Get-ActiveSessions komt, reageer dan!

conclusie

hopelijk heb je een waardering voor waarom ik een functie zou schrijven om dit voor mij te doen. Ik kon eerlijk gezegd niet tellen het aantal keren dat ik dit heb gebruikt om mijn werk gemakkelijker te maken.

hoe dan ook, Ik heb een paar opmerkelijke posts op komst, met name de partner van Get-ActiveSessions: Close-ActiveSessions.

Spoiler:

Get-ActiveSessions Computer | Close-ActiveSessions

en ook: ‘het maken van geplande taken voor PowerShell Scripts’, wat een trip zal zijn omdat ik nog geen afbeeldingen heb gedaan!

Leave a Reply