en bedre måde at finde en logget på bruger eksternt ved hjælp af Strømshell
der er et bjerg af forskellige måder at blive logget på brugere, men jeg har en favorit! Ved hjælp af qwinsta
er det eneste problem, at det returnerer en streng, og Magtskal kan lide objekter 🙁 men frygt aldrig! Det kan vi ordne.
vynsta
Prerek
jeg løb ind i en fejl 5 Adgang nægtet problem, da jeg først begyndte at bruge qwinsta
, der er en registreringsrettelse til det (tak Stackoverløb:
"AllowRemoteRPC"=dword:00000001
da dette er en Strømshell-blog, her er Strømshell-syntaksen for at føje den til en fjerncomputer, da vi sandsynligvis vil arbejde på eksterne computere.
$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()
syntaks
syntaksen er ret ligetil:
qwinsta /server:ServerName
og udgangen ser ret unmenacing ud:
SESSIONNAME USERNAME ID STATE TYPE DEVICE services 0 Disc console Anthony 1 Active rdp-tcp 65536 Listen
det eneste problem er, at hvis du kigger på en RDS-server, er der ingen nem måde at filtrere strenge på. Så du kunne ikke gøre noget som:
qwinsta /server:RDSServer | Where-Object USERNAME -like "Anth*"
men vi kan ordne det! Så vi kan objektivere det output!
indpakning af kvinsta
vi skal oprette en Kraftshellfunktion her, læser pas på.
vrider strengen ud for dens værdier
udover alle de parameterstoffer, som vi kommer til, er den første kerne ting, vi gør, at lede output til en variabel:
$result = qwinsta /server:$ComputerName
nu $result
vil se ligesom output fra før, men det vil blive formateret som en streng array (string
). Vi kan selvfølgelig bekræfte det med Get-Member
:
($result | Get-Member).TypeName
så den næste ting er at hente bare de oplysninger, vi ønsker. Jeg har besluttet mig for en løkke, springer over den første linje, da vi ikke har brug for overskrifterne:
ForEach($line in $result)
for hver linje, Hvad er hver værdi afgrænset med? Rum! Så vi kan bruge .Split () metode på strenge og split med hvert mellemrum. Den eneste advarsel er, at vi også skal teste for værdi på hver split, da du kan opdele flere mellemrum og få null-værdier.
$tmp = $line.split(" ") | ?{$_.length -gt 0}
en ting at bemærke er, at output fra qwinsta
er fast bredde, hvilket betyder, at bredden ikke ændres uanset hvor længe nogen af værdierne er. Vi kan drage fordel af det og bruge visse indekser til vores fordel.
første ting at gøre er at bestemme, hvilke linjer der faktisk indeholder en bruger. Vi kan tælle tegn og finde ud af, at BRUGERNAVNVÆRDIEN starter ved det 19.tegn (det første tegn er faktisk rummet, se nøje). Så hvis det 19.tegn ikke er tomt, har vi en bruger.
If(($line -ne " "))
den næste ting, jeg bemærkede i test med qwinsta
, er, at SessionName-egenskaben kun har værdi, hvis sessionen er i ‘aktiv’ tilstand. Så vi er også nødt til at kontrollere, om staten er ‘aktiv’, hvilket vi kan gøre ved at kontrollere indekset for denne stat for en ‘A’
If($line -eq "A")
hvis den er’ aktiv’, vil variablen $tmp
have forskellige værdier.
Aktiv:
#raw rdp-tcp#0 anthony 2 Active #$tmp variable (split)rdp-tcp#0anthony2Active
Ikke Aktiv:
#raw anthony 2 Disc #$tmp variable (split)anthony2Disc
konvertering af værdierne til brugbare objekter
når vi har fundet ud af alle værdierne, kan vi oprette et nyt PSObject, min favorit! Hvis du har Strømshellv5, kan du bruge {}
type accelerator (h), men jeg bruger New-Object
cmdlet her for ultimativ Kompatibilitet.
New-Object PSObject -Property @{ "ComputerName" = $ComputerName "SessionName" = $tmp "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $tmp}
i dette tilfælde, da vi ved, at sessionen er aktiv, er den første streng i $tmp
sessionsnavnet, og derefter har du resten af egenskaberne i rækkefølge. Det er muligt, at ‘Type’ eller ‘SessionName’ kan komme tilbage tom.
hvis staten ikke er ‘aktiv’, skifter vi det til:
New-Object PSObject -Property @{ "ComputerName" = $ComputerName "SessionName" = $null "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $null}
det endelige produkt
da dette ikke er et indlæg om oprettelse af funktioner, vil jeg springe over den anden syntaks og vise dig den endelige funktion, jeg skrev. Dette inkluderer nogle bedste praksis ting som at kontrollere for forbindelse og administratorrettigheder, inden du går ind i de spændende 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 kan finde dette i mine hjælpeprogrammer GitHub repo. Dette er mit første udgivne script! Hurra! Så lad os gå over, hvordan man bruger det:
enkel brug
for at hente brugerne logget ind på en ekstern eller lokal computer, ville vi blot bruge:
Get-ActiveSessions ComputerName
og dette skulle returnere noget, der ligner:
ID : 2SessionName :Type :UserName : anthonyComputerName : dc01State : Disc
og hvis du sender den til en variabel og ser på typenavnet, skal vi have en PSCustomObject
, hvilket betyder, at vi kan bruge alle de andre nyttige cmdlets til filtrering og hvad ikke!
$sessions = Get-ActiveSessions ComputerName($sessions | Get-Member).TypeNameSystem.Management.Automation.PSCustomObject
avanceret brug
vi har to ting, der går for os her, vi kan acceptere pipeline input og det ouputs et objekt. Så vi kan gøre ting før og efter Get-ActiveSessions
.
hvad hvis du vil finde alle servere i dit miljø, der har en bestemt bruger logget ind på dem?
Get-ADComputer -Filter {OperatingSystem -like '*Server*'} | Get-ActiveSessions | Where-Object UserName -eq 'Anthony'
eller hvad med at trække en liste over computere fra en tekstfil og udsende listen over unikke brugere, der er logget ind 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 op med nogen nyttige anvendelser af Get-ActiveSessions
, kommentar!
konklusion
forhåbentlig har du en forståelse for, hvorfor jeg ville skrive en funktion til at gøre disse ting for mig. Jeg kunne ærligt talt ikke tælle antallet af gange, jeg har brugt dette til at gøre mit arbejde lettere.
alligevel har jeg et par bemærkelsesværdige indlæg, der kommer op, især partneren til Get-ActiveSessions
: Close-ActiveSessions
.
Spoiler:
Get-ActiveSessions Computer | Close-ActiveSessions
og også: ‘oprettelse af planlagte opgaver til Strømshell-Scripts’, hvilket vil være en tur, da jeg ikke har lavet nogen billeder endnu!
Leave a Reply