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