uma maneira melhor de encontrar um usuário conectado remotamente usando PowerShell

há uma montanha de maneiras diferentes de fazer login nos usuários, mas eu tenho um favorito! Usando qwinsta, o único problema é que ele retorna uma string e PowerShell gosta de objetos: ( mas nunca tenha medo! Podemos resolver isso.

qwinsta

Prereqs

encontrei um erro 5 problema de acesso negado quando comecei a usar qwinsta, há uma correção de registro para isso (obrigado StackOverflow:

"AllowRemoteRPC"=dword:00000001

como este é um blog do PowerShell, aqui está a sintaxe do PowerShell para adicioná-lo a um computador remoto, pois provavelmente estaremos trabalhando em computadores remotos.

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

Sintaxe

A sintaxe do qwinsta é bastante simples:

qwinsta /server:ServerName

E a saída parece bastante unmenacing:

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

O único problema é que se você estivesse olhando para um servidor RDS, não há nenhuma maneira fácil para seqüências de filtro no PowerShell. Então você não poderia fazer algo como:

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

mas podemos consertar isso! Vamos embrulhar qwinsta para que possamos objetivar essa saída!

Wrapping qwinsta

vamos criar uma função PowerShell aqui, cuidado com o leitor.

Espremer a seqüência de caracteres para seus valores

Além de tudo o parâmetro coisas, que nós vamos chegar, o primeiro núcleo coisa que vamos fazer é direcionar a saída para uma variável:

$result = qwinsta /server:$ComputerName

Agora $result irá olhar apenas como a saída de antes, mas ele será formatado como uma matriz de seqüência de caracteres (string). Podemos, é claro, verificar que com Get-Member:

($result | Get-Member).TypeName

então, a próxima coisa é recuperar apenas as informações que queremos. Decidi fazer um loop for, pulando a primeira linha, pois não precisamos dos cabeçalhos:

ForEach($line in $result)

para cada linha, com o que cada valor é delimitado? Espaços! Para que possamos usar o.Método Split() em strings e dividir com cada espaço. A única ressalva é que também precisaremos testar o valor em cada divisão, pois você pode dividir vários espaços e obter valores nulos.

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

Uma coisa a notar é que a saída do qwinsta largura fixa, o que significa que a largura não muda, independentemente do tempo de qualquer dos valores. Podemos aproveitar isso e usar certos índices a nosso favor.

a primeira coisa a fazer é determinar quais linhas realmente contêm um usuário. Podemos contar caracteres e descobrir que o valor do nome de usuário começa no 19º caractere (o primeiro caractere é na verdade o espaço, olhe com cuidado). Portanto, se o 19º caractere não estiver vazio, temos um usuário.

If(($line -ne " "))

a próxima coisa que notei ao testar com qwinsta é que a propriedade SessionName só tem valor se a sessão estiver no estado ‘ativo’. Então, nós precisamos verificar para ver se o Estado é “Ativo”, o que podemos fazer consultando o índice do estado para um ‘Uma’

If($line -eq "A")

Se ele é “Ativo”, o $tmp variável terá diferentes quantidades de valores.

Activo:

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

Não Ativo:

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

convertendo os valores em objetos utilizáveis

depois de descobrir todos os valores, podemos criar um novo PSObject, meu favorito! Se você tiver PowerShellv5, poderá usar o Acelerador de tipo {} (x), mas usarei o cmdlet New-Object aqui para compatibilidade final.

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

nesse caso, como sabemos que a sessão está ativa, a primeira string em $tmp é o nome da sessão e, em seguida, em ordem, você tem o restante das propriedades. É possível que ‘Type ‘ ou’ SessionName ‘ possa voltar vazio.

Se o estado não é “Ativo” nós tínhamos que mudar para:

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

O produto final

uma vez que este não é um post sobre a criação de funções, eu vou pular de passar sobre a sintaxe e mostrar-lhe a função final eu escrevi. Isso inclui algumas coisas de melhores práticas, como verificar a conectividade e os direitos de administrador antes de entrar nas coisas interessantes.

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

você pode encontrar isso em Meus utilitários GitHub repo. Este é o meu primeiro roteiro publicado! Hooray! Então vamos ver como usá-lo:

Simples de uso de

Para recuperar os usuários registrados em um computador remoto ou local, nós simplesmente usar:

Get-ActiveSessions ComputerName

E isso deve retornar algo semelhante a:

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

E se você passá-lo para uma variável e olhar para o nome do tipo, devemos ter uma PSCustomObject, o que significa que pode usar todos os outros útil cmdlets para a filtragem e outras coisas mais!

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

uso avançado

temos duas coisas para nós aqui, podemos aceitar a entrada do pipeline e ele elimina um objeto. Então podemos fazer coisas antes e depois Get-ActiveSessions.

e se você quiser encontrar todos os servidores em seu ambiente que têm um determinado usuário conectado a eles?

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

ou que tal puxar uma lista de computadores de um arquivo de texto e produzir a lista de usuários únicos logados em todos eles?

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

se você tiver algum uso útil de Get-ActiveSessions, comente!

conclusão

espero que você tenha uma apreciação por que eu escreveria uma função para fazer essas coisas para mim. Sinceramente, não consegui contar o número de vezes que usei isso para facilitar meu trabalho.

de qualquer forma, tenho algumas postagens notáveis chegando, particularmente o parceiro para Get-ActiveSessions: Close-ActiveSessions.

Spoiler:

Get-ActiveSessions Computer | Close-ActiveSessions

e também: ‘criando tarefas agendadas para Scripts do PowerShell’, o que será uma viagem, pois ainda não fiz nenhuma imagem!

Leave a Reply