o modalitate mai bună de a găsi un utilizator conectat de la distanță folosind PowerShell

există un munte de moduri diferite de a vă conecta la utilizatori, dar am un favorit! Folosind qwinsta, singura problemă este că returnează un șir și PowerShell îi plac obiectele: (dar nu vă temeți niciodată! Putem repara asta.

qwinsta

Prereqs

am fugit într-o eroare de acces 5 refuzat problemă atunci când am început să folosesc qwinsta , există un registru fix pentru că (vă mulțumesc StackOverflow:

"AllowRemoteRPC"=dword:00000001

deoarece acesta este un blog PowerShell, iată sintaxa PowerShell pentru a-l adăuga la un computer la distanță, deoarece probabil vom lucra la computere la distanță.

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

sintaxa

sintaxa qwinsta este destul de simplă:

qwinsta /server:ServerName

iar rezultatul pare destul de neimplicant:

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

singura problemă este că, dacă vă uitați la un server RDS, nu există o modalitate ușoară de a filtra șirurile în PowerShell. Deci nu ai putea face ceva de genul:

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

dar putem repara asta! Vă permite să înfășurați qwinsta, astfel încât să putem obiectifica această ieșire!

ambalaj qwinsta

vom crea o funcție PowerShell aici, cititor feriți-vă.

stoarcerea șirul pentru valorile sale

în afară de toate lucrurile parametru, care vom ajunge la, primul lucru de bază vom face este de a direcționa ieșire la o variabilă:

$result = qwinsta /server:$ComputerName

acum $resultva arăta la fel ca ieșirea de dinainte, dar va fi formatată ca o matrice de șiruri (string). Putem, desigur, să verificăm acest lucru cu Get-Member:

($result | Get-Member).TypeName

deci, următorul lucru este să recuperăm doar informațiile pe care le dorim. M-am decis pe o buclă pentru, sărind peste prima linie, deoarece nu avem nevoie de anteturile:

ForEach($line in $result)

pentru fiecare linie, cu ce este delimitată fiecare valoare? Spații! Deci, putem folosi .Split () metoda pe siruri de caractere și împărțit cu fiecare spațiu. Singura avertizare este că va trebui, de asemenea, să testăm valoarea pentru fiecare împărțire, deoarece puteți împărți mai multe spații și puteți obține valori nule.

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

un lucru de remarcat este că ieșirea de la qwinsta este lățime fixă, ceea ce înseamnă că lățimea nu se schimbă indiferent de cât de lungă este oricare dintre valori. Putem profita de asta și putem folosi anumiți indici în avantajul nostru.

primul lucru de făcut este să determinați ce linii conțin de fapt un utilizator. Putem număra caractere și putem constata că valoarea numelui de utilizator începe de la al 19-lea caracter (primul caracter este de fapt spațiul, priviți cu atenție). Deci, dacă al 19-lea personaj nu este gol, avem un utilizator.

If(($line -ne " "))

următorul lucru pe care l-am observat în testarea cu qwinsta este că proprietatea SessionName are valoare numai dacă sesiunea este în starea ‘activă’. Deci, de asemenea, avem nevoie pentru a verifica pentru a vedea dacă statul este ‘activ’ , pe care le putem face prin verificarea indicele de acea stare pentru un ‘A’

If($line -eq "A")

dacă este’ activ’, variabila $tmp va avea valori diferite.

Activ:

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

Nu Este Activ:

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

conversia valorilor la obiecte utilizabile

odată ce avem toate valorile dat seama, putem crea un nou PSObject, preferatul meu! Dacă aveți PowerShellv5 puteți utiliza acceleratorul de tip {} (x), dar voi folosi cmdletul New-Object aici pentru compatibilitate finală.

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

în acest caz, deoarece știm că sesiunea este activă, primul șir din $tmp este numele sesiunii și apoi, în ordine, aveți restul proprietăților. Este posibil ca ‘tip’ sau ‘SessionName’ poate veni înapoi gol.

dacă statul nu este ‘activ’ am trece la:

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

produsul final

deoarece aceasta nu este o postare despre crearea funcțiilor, voi sări peste cealaltă sintaxă și vă voi arăta funcția finală pe care am scris-o. Aceasta include unele lucruri de bune practici, cum ar fi verificarea conectivității și a drepturilor de administrator înainte de a intra în lucrurile interesante.

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

puteți găsi acest lucru în utilitățile mele GitHub repo. Acesta este primul meu scenariu publicat! Ura! Deci, să mergem peste cum să-l folosească:

utilizare simplă

pentru a prelua utilizatorii conectați la un computer la distanță sau local, ne-ar folosi pur și simplu:

Get-ActiveSessions ComputerName

și acest lucru ar trebui să se întoarcă ceva similar cu:

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

și dacă îl transmiteți unei variabile și vă uitați la numele tipului, ar trebui să avem un PSCustomObject, ceea ce înseamnă că putem folosi toate celelalte cmdleturi utile pentru filtrare și fleacuri!

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

utilizare avansată

avem două lucruri care merg pentru noi aici, putem accepta intrarea conductei și ouputs un obiect. Deci, putem face lucruri înainte și după Get-ActiveSessions.

ce se întâmplă dacă doriți să găsiți toate serverele din mediul dvs. care au un anumit utilizator conectat la ele?

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

sau Ce zici de a trage o listă de computere dintr-un fișier text și de a scoate lista de utilizatori unici conectați la toate?

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

dacă veniți cu utilizări utile ale Get-ActiveSessions, comentați!

concluzie

sperăm că aveți o apreciere pentru motivul pentru care aș scrie o funcție pentru a face aceste lucruri pentru mine. Sincer, nu am putut număra de câte ori am folosit acest lucru pentru a-mi ușura munca.

Oricum, Am câteva postări notabile care vin, în special partenerul la Get-ActiveSessions: Close-ActiveSessions.

Spoiler:

Get-ActiveSessions Computer | Close-ActiveSessions

și, de asemenea: ‘crearea sarcinilor programate pentru scripturile PowerShell’, care va fi o călătorie, deoarece nu am făcut încă nicio imagine!

Leave a Reply