a better way to find a logged on user remote using PowerShell
There are a mountain of different ways to get logged on users, but I have a favorite! Käyttämällä qwinsta
ainoa ongelma on, että se palauttaa merkkijonon ja PowerShell tykkää objekteista : (but never fear! Voimme korjata sen.
qwinsta
esiasetukset
törmäsin virheeseen 5 access denied issue kun aloin käyttää qwinsta
, siihen on olemassa rekisterikorjaus (kiitos StackOverflow:
"AllowRemoteRPC"=dword:00000001
koska tämä on PowerShell-blogi, tässä on PowerShell-syntaksi, jolla voit lisätä sen etätietokoneeseen, koska työskentelemme todennäköisesti etätietokoneilla.
$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()
syntaksi
qwinstan syntaksi on melko suoraviivainen:
qwinsta /server:ServerName
ja lähtö näyttää melko unmenacing:
SESSIONNAME USERNAME ID STATE TYPE DEVICE services 0 Disc console Anthony 1 Active rdp-tcp 65536 Listen
ainoa ongelma on, että jos etsit RDS-palvelinta, ei ole helppoa tapaa suodattaa merkkijonoja Powershellissa. Joten et voinut tehdä jotain … :
qwinsta /server:RDSServer | Where-Object USERNAME -like "Anth*"
mutta voimme korjata sen! Lets wrap qwinsta jotta voimme esineellistää että lähtö!
Wrapping qwinsta
we ‘ re going to create a PowerShell function here, reader beware.
vääntämällä merkkijonoa sen arvoille
kaiken parametrin lisäksi, johon pääsemme, ensimmäinen ydinasia, jonka teemme, on ohjata lähtö muuttujaan:
$result = qwinsta /server:$ComputerName
nyt $result
näyttää aivan samalta kuin aikaisempi ulostulo, mutta se muotoillaan merkkijonorivistöksi (string
). Voimme tietenkin tarkistaa, että Get-Member
:
($result | Get-Member).TypeName
seuraavaksi haemme haluamamme tiedot. Olen päättänyt for loop, ohita ensimmäinen rivi, koska emme tarvitse otsikot:
ForEach($line in $result)
kunkin rivin, mikä on kunkin arvon rajattu kanssa? Välilyöntejä! Joten voimme käyttää sitä .Split () menetelmä merkkijonoja ja jakaa jokaisen välilyönnin. Ainoa varoitus on, että meidän täytyy myös testata arvoa jokaiselle jaetulle, koska voit jakaa useita välilyöntejä ja saada nolla-arvoja.
$tmp = $line.split(" ") | ?{$_.length -gt 0}
on huomattava, että lähtö qwinsta
on tasalevyinen, eli leveys ei muutu riippumatta siitä, kuinka pitkiä arvot ovat. Voimme hyödyntää sitä ja käyttää tiettyjä indeksejä eduksemme.
ensimmäiseksi on selvitettävä, mitkä rivit todella sisältävät käyttäjän. Voimme laskea merkkejä ja todeta, että käyttäjätunnuksen arvo alkaa 19.merkki (ensimmäinen merkki on todella tilaa, Katso huolellisesti). Joten jos 19. merkki ei ole tyhjä, meillä on käyttäjä.
If(($line -ne " "))
seuraava asia, jonka huomasin testauksessa qwinsta
, on, että SessionName-ominaisuudella on arvoa vain, jos istunto on ‘aktiivisessa’ tilassa. Joten meidän on myös tarkistettava, onko valtio “aktiivinen”, minkä voimme tehdä tarkistamalla kyseisen valtion indeksin “A’
If($line -eq "A")
jos se on “aktiivinen”, $tmp
– muuttujalla on erilaisia arvoja.
Aktiivinen:
#raw rdp-tcp#0 anthony 2 Active #$tmp variable (split)rdp-tcp#0anthony2Active
Ei Käytössä:
#raw anthony 2 Disc #$tmp variable (split)anthony2Disc
muunnetaan arvot käyttökelpoisiksi kohteiksi
kun kaikki arvot on selvitetty, voidaan luoda uusi PSObject, suosikkini! Jos sinulla on PowerShellv5, voit käyttää {}
type acceleratoria (x), Mutta minä käytän New-Object
cmdlet tässä lopulliseen yhteensopivuuteen.
New-Object PSObject -Property @{ "ComputerName" = $ComputerName "SessionName" = $tmp "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $tmp}
tässä tapauksessa, koska tiedämme istunnon olevan aktiivinen, ensimmäinen merkkijono $tmp
on istunnon nimi, ja sitten, järjestyksessä, sinulla on loput ominaisuudet. On mahdollista, että “Tyyppi” tai “Sessioname” voi palata tyhjänä.
jos valtio ei ole “aktiivinen”, vaihtaisimme sen:
New-Object PSObject -Property @{ "ComputerName" = $ComputerName "SessionName" = $null "UserName" = $tmp "ID" = $tmp "State" = $tmp "Type" = $null}
lopputuote
koska tämä ei ole viesti funktioiden luomisesta, Aion ohittaa muun syntaksin ja näyttää lopullisen funktion, jonka kirjoitin. Tämä sisältää joitakin parhaita käytäntöjä juttuja, kuten tarkistaa yhteyden ja admin oikeudet ennen päästä jännittävä tavaraa.
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
tämän löydät Apuohjelmistani GitHub reposta. Tämä on ensimmäinen julkaistu käsikirjoitukseni! Hurraa! Joten mennään yli, miten sitä käytetään:
yksinkertainen käyttö
hakeaksemme käyttäjät, jotka ovat kirjautuneet etätietokoneeseen tai paikalliseen tietokoneeseen, käyttäisimme yksinkertaisesti:
Get-ActiveSessions ComputerName
ja tämän pitäisi palauttaa jotain vastaavaa:
ID : 2SessionName :Type :UserName : anthonyComputerName : dc01State : Disc
ja jos siirrät sen muuttujaan ja katsot tyypin nimeä, meillä pitäisi olla PSCustomObject
, eli voimme käyttää kaikkia muita hyödyllisiä cmdletejä suodatukseen ja muuhun!
$sessions = Get-ActiveSessions ComputerName($sessions | Get-Member).TypeNameSystem.Management.Automation.PSCustomObject
Advanced usage
meillä on tässä kaksi asiaa, voimme hyväksyä putkilinjan syötön ja se ouputs objekti. Joten voimme tehdä juttuja ennen ja jälkeen Get-ActiveSessions
.
mitä jos haluat löytää kaikki ympäristöstäsi olevat palvelimet, joihin on kirjautunut tietty käyttäjä?
Get-ADComputer -Filter {OperatingSystem -like '*Server*'} | Get-ActiveSessions | Where-Object UserName -eq 'Anthony'
tai mitä jos vetäisit listan tietokoneista tekstitiedostosta ja tulostaisit listan ainutlaatuisista käyttäjistä, jotka ovat kirjautuneet niihin kaikkiin?
get-content C:\temp\computers.txt | Get-ActiveSessions | Select-Object -Unique UserName -ExpandProperty UserName | Out-File C:\temp\users.txt
jos keksit Get-ActiveSessions
hyödyllisiä käyttötarkoituksia, kommentoi!
loppupäätelmä
toivottavasti osaat arvostaa sitä, miksi kirjoittaisin funktion, jolla tekisin nämä jutut puolestani. En osannut laskea, kuinka monta kertaa olen käyttänyt tätä helpottaakseni työtäni.
Anyways, minulla on pari merkittävää virkaa tulossa, erityisesti kumppani Get-ActiveSessions
: Close-ActiveSessions
.
spoileri:
Get-ActiveSessions Computer | Close-ActiveSessions
ja myös:’ luominen ajoitettu tehtäviä PowerShell skriptejä’, joka on matka, koska en ole tehnyt mitään kuvia vielä!
Leave a Reply