Lijst van gebruikers die zijn ingelogd op uw machines

Paswoordbeleid is het beste 😀 Soms leiden ze tot account logouts wanneer iemand vergeet uit te loggen van een sessie ergens op het netwerk though. Het kan de TS sessie zijn die ze eens per kwartaal gebruiken voor rapportage of misschien ken je het gevoel wanneer je RDP naar een server om te ontdekken dat deze vergrendeld is door 2 andere admins die vergeten zijn uit te loggen toen ze vertrokken. (Omdat dit nooit gebeurt… we gebruiken allemaal PowerShell…) Hoe dan ook, dit liet me zoeken naar een gebruikerssessie ergens op het netwerk. Het ergste is wanneer mijn eigen wachtwoord verloopt. Ik haat het als mijn account vergrendeld wordt. Daarom heb ik er een regel van gemaakt om alle servers te controleren voordat ik van wachtwoord verander. Er zijn meerdere manieren om dit te doen, maar ik neig natuurlijk naar de PowerShell route.

Research

De methode die ik oorspronkelijk gebruikte komt uit de TechNet galerij

In het kort: Get-WmiObject -Class Win32_process

Dit vindt in principe alle unieke gebruikers die processen draaien op de machine. Dit is cool omdat het alles vindt, zelfs dingen die draaien als een service, maar ik ben er niet van overtuigd dat dit de meest efficiënte manier is.

Teruggrijpend op google vind ik een heleboel creatieve manieren om te controleren wie er is ingelogd op je box.

peetersonline.nl/2008/11/oneliner-get-logged-on-users-with-powershell/ bracht me op het idee om Win32_LoggedOnUser te controleren, wat voor de hand lijkt te liggen.

2015-08-28 (1)

Dit ziet er goed uit en lijkt ook te werken met Get-CimInstance hoewel de uitvoer een beetje anders is.

2015-08-28

learn-powershell.net/…/Quick-hit-find-currently-logged-on-users/ heeft een wat ouderwetse aanpak, die ik wel leuk vind omdat het een beetje ruw is en me dwingt om te spelen met mijn op sjablonen gebaseerde parsing.

2015-08-28 (2)

Ik weet niet zeker welke methode sneller is, dus waarom zou je niet proberen om ze alle drie in een module te implementeren en het uit te testen.

Sketching

Het is altijd een goed idee om te beginnen met het maken van een schets van wat je probeert te bereiken.

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

Nu heb ik alle informatie die ik nodig heb om de GitHub repository op te zetten.

github.com/mrhvid/Get-ActiveUser

Code

De parameters waar ik in geïnteresseerd ben zijn ComputerName en Method.

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

Ik heb al 3 mogelijke Methods in gedachten dus ik stel ValidateSet in met de 3 mogelijkheden. Dan hoef ik me later geen zorgen meer te maken over die invoer.

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

In het Proces-gedeelte van mijn functie gebruik ik gewoon een schakelaar voor de 3 verschillende methoden die ik in de Parameter heb toegestaan.

Nu is het gewoon invullen van de blanco’s.

WMI

Mijn oude oplossing is simpel en werkt prima.

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

2015-08-28 (3)

Maar nu ik Win32_LoggedOnUser heb gevonden lijkt het fout om het op deze manier te doen. Laten we eens kijken naar het nieuwe idee.

2015-08-28 (4)

gwmi-Wmi32_LoggedOnUser_gm

Dit is allemaal de juiste data maar het lijkt in een string formaat te zijn dus ik zal een beetje manipulatie moeten doen. Dit kan op een miljoen manieren.

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

Peter’s eerder genoemde one-liner leek me niet erg leesvriendelijk, wat niet erg is voor een one-liner, maar ik zou het graag wat leesbaarder zien als dat mogelijk is.

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

Dit lijkt me goed 🙂 Ik zal de output opslaan in $ActiveUsers variabele en hetzelfde doen voor CIM en Query.

CIM

Laten we het eens proberen met CIM.

2015-08-28 (6)

Dit ziet er veel gestructureerder uit.

2015-08-28 (7)

CIM eindigt als een makkelijk te begrijpen one-liner 😀

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

Query

Met behulp van de goede oude Query.exe vond ik de eerder besproken sjabloongebaseerde parsing erg nuttig.

$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

Nu hoef ik alleen nog maar de gebruikers op te maken en op een mooie manier uit te voeren. Ik wil schone objecten met ComputerName en UserName.

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

Testing

Nu heb ik een probleem. Ik kan dit niet testen omdat ik niet een heleboel testservers tot mijn beschikking heb. Al mijn testen zijn gedaan tegen mijn eigen Windows 10 box. Het lijkt erop dat lokaal query’s uitvoeren een stuk sneller gaat, maar WMI/CIM geeft misschien een completer beeld van welke services worden uitgevoerd.

get-activeuser_wmi_highlight

Ik heb een heleboel standaard serviceaccounts draaien die misschien beter uit de uitvoer kunnen worden verwijderd. Om dit nuttig te laten zijn, moeten we het op veel machines uitvoeren.

get-activeuser_query

De combinatie van Get-ActiveUser en Start-Multithread uit het bericht van vorige week lijkt te werken zoals de bedoeling was.

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

Het pipen van het bovenstaande naar Out-GridView is waarschijnlijk mijn persoonlijke favoriete manier om echt iets nuttigs te bereiken.

get-activeuser_query_out-gridview

Nu hebben we alle gegevens op een mooie doorzoekbare manier en is het heel eenvoudig om te controleren of je gebruiker is ingelogd op een willekeurige machine. Het is ook een makkelijke manier om te controleren op rouge gebruikers op je netwerk.

Publiceren en feedback

De code is gepubliceerd op PowerShellGallery.

Help me alsjeblieft door het voor me te testen. Ik zou graag willen weten of dit in de echte wereld werkt 🙂

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

Dit zou moeten werken als je WMF 5 + hebt geïnstalleerd en op Windows 10 out of the box.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.