lepší způsob, jak najít přihlášeného uživatele vzdáleně pomocí PowerShell

existuje Hora různých způsobů, jak se přihlásit uživatelé,ale mám oblíbenou! Při použití qwinsta je jediným problémem, že vrací řetězec a PowerShell má rád objekty 🙁 ale nikdy se nebojte! Můžeme to napravit.

qwinsta

Prereqs

narazil jsem na chybu 5 Přístup odepřen problém, když jsem poprvé začal používat qwinsta, existuje oprava registru pro to (děkuji StackOverflow:

"AllowRemoteRPC"=dword:00000001

protože se jedná o blog PowerShell, zde je syntaxe PowerShell pro přidání do vzdáleného počítače, protože pravděpodobně budeme pracovat na vzdálených počítačích.

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

syntaxe

syntaxe qwinsta je poměrně přímočará:

qwinsta /server:ServerName

a výstup vypadá poněkud nevýrazně:

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

jediným problémem je, že pokud jste se dívali na server RDS, neexistuje snadný způsob filtrování řetězců v PowerShell. Takže jste nemohli udělat něco jako:

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

ale můžeme to napravit! Umožňuje zabalit qwinsta, takže můžeme objektivizovat tento výstup!

obal qwinsta

zde vytvoříme funkci PowerShell, pozor na čtenáře.

vyždímání řetězce pro jeho hodnoty

kromě všech parametrů, ke kterým se dostaneme, první základní věc, kterou uděláme, je nasměrovat výstup na proměnnou:

$result = qwinsta /server:$ComputerName

nyní $result bude vypadat stejně jako výstup z předchozího, ale bude formátován jako řetězcové pole (string). Můžeme to samozřejmě ověřit pomocí Get-Member:

($result | Get-Member).TypeName

takže další věc je získat jen informace, které chceme. Rozhodl jsem se pro smyčku, přeskočení prvního řádku, protože nepotřebujeme záhlaví:

ForEach($line in $result)

pro každý řádek, jaká je každá hodnota vymezena? Prostory! Takže můžeme použít .Split () metoda na řetězcích a rozdělit s každým mezerou. Jedinou námitkou je, že budeme také muset otestovat hodnotu na každém rozdělení, protože můžete rozdělit více mezer a získat hodnoty null.

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

jedna věc, kterou je třeba poznamenat, je, že výstup z qwinsta je Pevná šířka, což znamená, že šířka se nemění bez ohledu na to, jak dlouho jsou některé z hodnot. Můžeme toho využít a využít určité indexy v náš prospěch.

první věc, kterou musíte udělat, je určit, které řádky skutečně obsahují uživatele. Můžeme počítat znaky a zjistit, že hodnota uživatelského jména začíná na 19. znaku (první znak je vlastně mezera, podívejte se pozorně). Takže pokud 19. znak není prázdný, máme uživatele.

If(($line -ne " "))

další věc, kterou jsem si všiml při testování s qwinsta, je, že vlastnost SessionName má hodnotu pouze v případě, že relace je ve stavu “aktivní”. Musíme také zkontrolovat, zda je stav “aktivní”, což můžeme udělat kontrolou indexu tohoto stavu pro “A’

If($line -eq "A")

pokud je “aktivní”, proměnná $tmp bude mít různé hodnoty.

Aktivní:

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

Není Aktivní:

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

převod hodnot na použitelné objekty

jakmile budeme mít všechny hodnoty vyřešeny, můžeme vytvořit nový PSObject, můj oblíbený! Pokud máte PowerShellv5, můžete použít {} Typ accelerator (x), ale budu používat New-Object rutinu zde pro maximální kompatibilitu.

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

v tomto případě, protože víme, že relace je aktivní, první řetězec v $tmp je název relace a pak v pořadí máte zbytek vlastností. Je možné, že ” typ “nebo” SessionName ” se může vrátit prázdný.

pokud stav není “aktivní”, přepneme to na:

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

konečný produkt

protože se nejedná o příspěvek na vytváření funkcí, přeskočím druhou syntaxi a ukážu vám konečnou funkci, kterou jsem napsal. To zahrnuje některé osvědčené postupy, jako je kontrola připojení a administrátorských práv, než se dostanete do vzrušujících věcí.

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

najdete to v mém Utilities GitHub repo. Toto je můj první publikovaný scénář! Hurá! Takže pojďme přes to, jak ji používat:

Jednoduché použití

k načtení uživatelů přihlášených do vzdáleného nebo lokálního počítače bychom jednoduše použili:

Get-ActiveSessions ComputerName

a to by mělo vrátit něco podobného:

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

a pokud ji předáte proměnné a podíváte se na název typu, měli bychom mít PSCustomObject, což znamená, že můžeme použít všechny další užitečné rutiny pro filtrování a kdoví co ještě!

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

Pokročilé použití

máme pro nás dvě věci, můžeme přijmout vstup potrubí a to ouputs objekt. Takže můžeme dělat věci před a po Get-ActiveSessions.

co když chcete najít všechny servery ve vašem prostředí, do kterých je přihlášen konkrétní uživatel?

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

nebo co vytáhnout seznam počítačů z textového souboru a výstup seznamu unikátních uživatelů přihlášených do nich všechny?

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

pokud přijdete s jakýmkoli užitečným použitím Get-ActiveSessions, komentář!

závěr

doufejme, že máte ocenění za to, proč bych napsal funkci, která by pro mě dělala tyto věci. Upřímně jsem nemohl spočítat, kolikrát jsem to použil, abych usnadnil práci.

každopádně mám několik pozoruhodných příspěvků, zejména partnera Get-ActiveSessions: Close-ActiveSessions.

Spoiler:

Get-ActiveSessions Computer | Close-ActiveSessions

a také: “vytváření naplánovaných úkolů pro skripty PowerShell”, což bude výlet, protože jsem ještě neudělal žádné obrázky!

Leave a Reply