En bedre måte å finne en logget på bruker eksternt Ved Hjelp Av PowerShell

Det er et fjell av forskjellige måter å få logget på brukere, men jeg har en favoritt! Ved å bruke qwinsta, er det eneste problemet at Det returnerer en streng og PowerShell liker objekter: (men aldri frykt! Vi kan fikse det.

qwinsta

Prereqs

jeg løp inn i en feil 5 tilgang nektet problem da jeg først begynte å bruke qwinsta, det er en registerreparasjon for det (takk stackoverflow:

"AllowRemoteRPC"=dword:00000001

Siden dette er En PowerShell-blogg, her Er PowerShell-syntaksen for å legge den til en ekstern datamaskin, siden vi sannsynligvis vil jobbe på eksterne datamaskiner.

$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

syntaksen til qwinsta er ganske grei:

qwinsta /server:ServerName

og utgangen ser ganske unmenacing ut:

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

Det eneste problemet er at hvis DU så PÅ EN RDS-server, er det ingen enkel måte å filtrere strenger I PowerShell. Så du kunne ikke gjøre noe som:

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

Men vi kan fikse det! Lar vikle qwinsta slik at vi kan objektifisere den utgangen!

Innpakning qwinsta

Vi skal lage En PowerShell-funksjon her, leser pass opp.

Vri ut strengen for verdiene

I tillegg til alle parametergreiene, som vi kommer til, er den første kjerne tingen vi skal gjøre å lede utgangen til en variabel:

$result = qwinsta /server:$ComputerName

$result vil se ut som utdataene fra før, men det vil bli formatert som en streng array (string). Vi kan selvfølgelig bekrefte det med Get-Member:

($result | Get-Member).TypeName

Så det neste er å hente bare den informasjonen vi ønsker. Jeg har bestemt meg for en løkke, hopper over første linje siden vi ikke trenger overskriftene:

ForEach($line in $result)

For hver linje, hva er hver verdi avgrenset med? Mellomrom! Sa vi kan bruke den.Split () metode på strenger og delt med hvert mellomrom. Den eneste advarselen er at vi også må teste for verdi på hver splitt siden du kan dele flere mellomrom og få nullverdier.

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

en ting å merke seg er at utgangen fra qwinsta er fast bredde, noe som betyr at bredden ikke endres uansett hvor lenge noen av verdiene er. Vi kan dra nytte av det og bruke visse indekser til vår fordel.

Det Første du må gjøre er å finne ut hvilke linjer som faktisk inneholder en bruker. Vi kan telle tegn og finne UT AT BRUKERNAVNVERDIEN starter ved det 19. tegn (det første tegnet er faktisk plassen, se nøye). Så hvis det 19. tegnet ikke er tomt, har vi en bruker.

If(($line -ne " "))

det neste jeg la merke til i testing med qwinsta er at SessionName-egenskapen bare har verdi hvis økten er I Aktiv tilstand. Så vi må også sjekke for Å se Om Staten Er ‘Aktiv’, som vi kan gjøre ved å sjekke indeksen for den staten for en ‘A’

If($line -eq "A")

hvis den Er Aktiv, vil $tmp – variabelen ha forskjellige mengder verdier.

Aktiv:

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

Ikke Aktiv:

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

Konvertere verdiene til brukbare objekter

Når vi har alle verdiene funnet ut, kan vi opprette et nytt PSObject, min favoritt! Hvis Du har PowerShellv5, kan du bruke {} type akselerator (x), men jeg bruker cmdleten New-Object her for ultimate kompatibilitet.

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

I dette tilfellet siden vi vet at økten er aktiv, er den første strengen i $tmp øktnavnet, og i rekkefølge har du resten av egenskapene. Det er mulig at ‘Type’ eller ‘SessionName’ kan komme tilbake tomt.

hvis staten ikke Er Aktiv, vil vi bytte det til:

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

det endelige produktet

Siden dette ikke er et innlegg på å lage funksjoner, skal jeg hoppe over den andre syntaksen og vise deg den endelige funksjonen jeg skrev. Dette inkluderer noen beste praksis ting som å sjekke for tilkobling og admin rettigheter før du får inn spennende ting.

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

du finner dette i Min Verktøy GitHub repo. Dette er mitt første publiserte manus! Hurra! Så kan vi gå over hvordan du bruker den:

Enkel bruk

for å hente brukerne logget inn på en ekstern eller lokal datamaskin, ville vi bare bruke:

Get-ActiveSessions ComputerName

Og dette burde returnere noe som ligner på:

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

og hvis du sender den til en variabel og ser på typenavnet, bør vi ha en PSCustomObject, noe som betyr at vi kan bruke alle de andre nyttige cmdlets for filtrering og hva ikke!

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

Avansert bruk

Vi har to ting som går for oss her, vi kan akseptere rørinngang OG det ouputs et objekt. Så vi kan gjøre ting før og etter Get-ActiveSessions.

Hva om du vil finne alle servere i ditt miljø som har en bestemt bruker logget på dem?

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

eller hva med å trekke en liste over datamaskiner fra en tekstfil og skrive ut listen over unike brukere logget på dem alle?

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

hvis du kommer opp med noen nyttige bruksområder av Get-ActiveSessions, kommenter!

Konklusjon

Forhåpentligvis har Du en forståelse for hvorfor jeg ville skrive en funksjon for å gjøre dette for meg. Jeg kunne ærlig talt ikke telle antall ganger jeg har brukt dette for å gjøre arbeidet mitt enklere.

uansett, Jeg har et par bemerkelsesverdige innlegg som kommer opp, spesielt partneren til Get-ActiveSessions: Close-ActiveSessions.

Spoiler:

Get-ActiveSessions Computer | Close-ActiveSessions

Og også: ‘Opprette Planlagte Oppgaver For PowerShell-Skript’, som vil være en tur siden jeg ikke har gjort noen bilder ennå!

Leave a Reply