List users logged on to your machines

Password policies are the best 😀 A volte portano a logout di account quando qualcuno dimentica di uscire da una sessione da qualche parte nella rete. Potrebbe essere la sessione TS che usano una volta al trimestre per i rapporti o forse conoscete la sensazione quando fate una RDP su un server solo per scoprire che è bloccato da altri 2 amministratori che hanno dimenticato di fare il logout quando sono usciti. (Spento perché questo non succede mai… usiamo tutti PowerShell…) Comunque, questo mi ha portato a cercare una sessione utente da qualche parte nella rete. La cosa peggiore è quando la mia password scade. Odio quando il mio account finisce per essere bloccato. Perciò mi sono imposta la regola di controllare tutti i server prima di cambiare la password. Ci sono più modi per farlo, ma naturalmente tendo a seguire la strada di PowerShell.

Ricerca

Il metodo originale che ho usato è dalla galleria TechNet

In breve: Get-WmiObject -Class Win32_process

Questo sostanzialmente trova tutti gli utenti unici che eseguono processi sulla macchina. Questo è bello perché trova tutto, anche le cose in esecuzione come servizio, ma non sono convinto che sia il modo più efficiente.

Controllando con google trovo un sacco di modi creativi per controllare chi è connesso alla vostra macchina.

peetersonline.nl/2008/11/oneliner-get-logged-on-users-with-powershell/ mi ha dato l’idea di controllare Win32_LoggedOnUser che sembra ovvio.

2015-08-28 (1)

Questo sembra ottimo e sembra funzionare anche con Get-CimInstance sebbene l’output sia un po’ diverso.

2015-08-28

learn-powershell.net/…/Quick-hit-find-currently-logged-on-users/ ha adottato un approccio un po’ più vecchia scuola che mi piace perché è un po’ grezzo e mi costringe a giocare con il mio parsing basato su template.

2015-08-28 (2)

Non sono davvero sicuro di quale metodo sia più veloce, quindi perché non provare ad implementare tutti e 3 in un modulo e testarlo.

Sketching

È sempre una buona idea iniziare facendo uno schizzo di ciò che si sta cercando di realizzare.

Pseudo code:Get-ActiveUser -ComputerName -Method Wanted output:Username ComputerName-------- ------------TestUser1 Svr3TestUser3 Svr3DonaldDuck Client2

Ora ho tutte le informazioni di cui ho bisogno per impostare il repository GitHub.

github.com/mrhvid/Get-ActiveUser

Code

Prima di tutto i parametri che mi interessano sono ComputerName e Method.

 Param ( # Computer name, IP, Hostname ] $ComputerName, # Choose method, WMI, CIM or Query $Method )

Ho già in mente 3 possibili Methods quindi imposto ValidateSet con le 3 possibilità. Quindi non devo preoccuparmi di quell’input in seguito.

 Process { switch ($Method) { 'WMI' { } 'CIM' { } 'Query' { } } }

Nella parte Process della mia funzione uso semplicemente un interruttore per i 3 metodi diversi che ho permesso nel Parametro.

Ora è un semplice riempimento degli spazi vuoti.

WMI

La mia vecchia soluzione è semplice e funziona bene.

$WMI = Get-WmiObject -Class Win32_Process -ComputerName $ComputerName -ErrorAction Stop$ProcessUsers = $WMI.getowner().user | Select-Object -Unique

2015-08-28 (3)

Ma ora che ho trovato Win32_LoggedOnUser sembra sbagliato farlo così. Guardiamo invece la nuova idea.

2015-08-28 (4)

gwmi-Wmi32_LoggedOnUser_gm

Questi sono tutti i dati giusti ma sembrano essere in un formato stringa quindi dovrò fare una piccola manipolazione. Questo può essere fatto in un milione di modi.

function Get-MyLoggedOnUsers { param($Computer) Get-WmiObject Win32_LoggedOnUser -ComputerName $Computer | Select Antecedent -Unique | %{"{0}{1}" -f $_.Antecedent.ToString().Split('"'), $_.Antecedent.ToString().Split('"')} }

Il suddetto one-liner di Peter non mi sembrava molto leggibile, il che va bene per un one-liner, ma vorrei che fosse un po’ più leggibile se possibile.

$WMI = (Get-WmiObject Win32_LoggedOnUser).Antecedent$ActiveUsers = @()foreach($User in $WMI) { $StartOfUsername = $User.LastIndexOf('=') + 2 $EndOfUsername = $User.Length - $User.LastIndexOf('=') -3 $ActiveUsers += $User.Substring($StartOfUsername,$EndOfUsername)}

2015-08-28 (5)

Questo sembra giusto 🙂 Salverò l’output nella variabile $ActiveUsers e farò lo stesso per CIM e Query.

CIM

Prova con CIM.

2015-08-28 (6)

Questo sembra molto più strutturato.

2015-08-28 (7)

CIM finisce per essere una semplice riga 😀

$ActiveUsers = (Get-CimInstance Win32_LoggedOnUser -ComputerName $ComputerName).antecedent.name | Select-Object -Unique

Query

Usando il buon vecchio Query.exe ho trovato molto utile il parsing basato su template discusso in precedenza.

$Template = @' USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME>{USER*:jonas} console 1 Active 1+00:27 24-08-2015 22:22 {USER*:test} 2 Disc 1+00:27 25-08-2015 08:26'@$Query = query.exe user$ActiveUsers = $Query | ConvertFrom-String -TemplateContent $Template | Select-Object -ExpandProperty User

Output

Ora ho solo bisogno di formattare ed emettere gli utenti in un modo carino. Voglio oggetti puliti con ComputerName e UserName.

# Create nice output format$UsersComputersToOutput = @()foreach($User in $ActiveUsers) { $UsersComputersToOutput += New-Object psobject -Property @{ ComputerName=$ComputerName; UserName=$User } }}# output data$UsersComputersToOutput

Testing

Ora ho un problema. Non posso testare questo perché non ho un mucchio di server di prova a mia disposizione. Tutti i miei test sono stati fatti contro il mio box Windows 10. Sembra che la query sia molto più veloce in esecuzione locale, ma WMI/CIM potrebbe dare una visione più completa di quali servizi sono in esecuzione.

get-activeuser_wmi_highlight

Ho un mucchio di account di servizi standard in esecuzione che potrebbe essere bello rimuovere dall’output. Inoltre, affinché questo sia utile, dovremo eseguirlo su molte macchine.

get-activeuser_query

Combinando Get-ActiveUser con Start-Multithread del post della scorsa settimana sembra funzionare come previsto.

Start-Multithread -Script { param($C) Get-ActiveUser -ComputerName $C -Method Query } -ComputerName ::1,Localhost | Out-GridView

Il piping di quanto sopra in Out-GridView è probabilmente il mio modo preferito di realizzare qualcosa di veramente utile.

get-activeuser_query_out-gridview

Ora abbiamo tutti i dati in un bel modo ricercabile ed è veramente facile controllare se il vostro utente è loggato su qualche macchina a caso. È anche un modo semplice per controllare se ci sono utenti in fuga sulla tua rete.

Pubblicazione e feedback

Il codice è pubblicato su PowerShellGallery.

Per favore aiutatemi testandolo per me. Mi piacerebbe sapere se questo funziona nel mondo reale 🙂

# To install Get-ActiveUserInstall-Module Get-ActiveUser#To install Start-MultithreadInstall-Module Start-Multithread

Questo dovrebbe funzionare quando hai WMF 5 + installato e su Windows 10 fuori dalla scatola.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.