Polityki haseł są najlepsze 😀 Czasami jednak prowadzą do wylogowania konta gdy ktoś zapomni wylogować się z sesji gdzieś w sieci. Może to być sesja TS, której używają raz na kwartał do raportowania, a może znasz to uczucie, gdy po przejściu przez RDP na serwer okazuje się, że jest on zablokowany przez 2 innych adminów, którzy zapomnieli się wylogować, gdy wyszli. (Off cause this never happens… we all use PowerShell…) Anyway, this had me searching for a user session somewhere on the network. Najgorszą rzeczą jest, gdy moje własne hasło wygasa. Nienawidzę, gdy moje konto kończy się zablokowaniem. Dlatego też uczyniłem to regułą, aby po prostu sprawdzić wszystkie serwery przed zmianą hasła. Istnieje wiele sposobów, aby to zrobić, ale oczywiście mam tendencję, aby przejść do trasy PowerShell.
Badania
Pierwotna metoda, której użyłem jest z galerii TechNet
W skrócie: Get-WmiObject -Class Win32_process
To w zasadzie znajduje wszystkich unikalnych użytkowników uruchamiających procesy na maszynie. Jest to fajne, ponieważ znajduje wszystko, nawet rzeczy działające jako usługi, ale nie jestem przekonany, że jest to najbardziej efektywny sposób.
Sprawdzając w google znalazłem wiele kreatywnych sposobów na sprawdzenie kto jest zalogowany na twoim komputerze.
peetersonline.nl/2008/11/oneliner-get-logged-on-users-with-powershell/ dał mi pomysł, aby sprawdzić Win32_LoggedOnUser co wydaje się oczywiste.
To wygląda świetnie i wydaje się, że działa również z Get-CimInstance, chociaż dane wyjściowe są nieco inne.
learn-powershell.net/…/Quick-hit-find-currently-logged-on-users/ przyjął trochę bardziej oldschoolowe podejście, które mi się podoba, ponieważ jest trochę szorstkie i zmusza mnie do zabawy z moim parsowaniem opartym na szablonach.
Nie jestem pewien, która metoda jest szybsza, więc dlaczego nie spróbować zaimplementować wszystkich 3 w module i przetestować to.
Sketching
Zawsze dobrze jest zacząć od zrobienia szkicu tego, co próbujesz osiągnąć.
Pseudo code:Get-ActiveUser -ComputerName -Method Wanted output:Username ComputerName-------- ------------TestUser1 Svr3TestUser3 Svr3DonaldDuck Client2
Teraz mam wszystkie informacje, których potrzebuję, aby skonfigurować repozytorium GitHub.
github.com/mrhvid/Get-ActiveUser
Code
Przede wszystkim interesujące mnie parametry to ComputerName i Method.
Param ( # Computer name, IP, Hostname ] $ComputerName, # Choose method, WMI, CIM or Query $Method )
Mam już w głowie 3 możliwe Methods, więc ustawiam ValidateSet z tymi 3 możliwościami. Wtedy nie muszę się martwić o to wejście później.
Process { switch ($Method) { 'WMI' { } 'CIM' { } 'Query' { } } }
W części Process mojej funkcji po prostu używam przełącznika dla 3 różnych metod, które pozwoliłem w Parameter.
Teraz jest to podstawowe wypełnienie pustych pól.
WMI
Moje stare rozwiązanie jest simpel i działa dobrze.
$WMI = Get-WmiObject -Class Win32_Process -ComputerName $ComputerName -ErrorAction Stop$ProcessUsers = $WMI.getowner().user | Select-Object -Unique
Ale teraz, gdy znalazłem Win32_LoggedOnUser, wydaje się, że źle jest robić to w ten sposób. Lets look at the new idea instead.
To są wszystkie właściwe dane, ale wydaje się, że są one w formacie ciągów znaków, więc będę musiał zrobić trochę manipulacji. Można to zrobić na milion sposobów.
function Get-MyLoggedOnUsers { param($Computer) Get-WmiObject Win32_LoggedOnUser -ComputerName $Computer | Select Antecedent -Unique | %{"{0}{1}" -f $_.Antecedent.ToString().Split('"'), $_.Antecedent.ToString().Split('"')} }
Wspomniany wcześniej one-liner Petera nie wydawał mi się zbyt przyjazny dla czytelnika, co jest ok jak na one-liner, ale chciałbym, aby był nieco bardziej czytelny, jeśli to możliwe.
$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)}
To wydaje się w porządku 🙂 Zapiszę dane wyjściowe w zmiennej $ActiveUsers i zrobię to samo dla CIM i Query.
CIM
Spróbujmy z CIM.
To wygląda o wiele bardziej uporządkowane.
CIM kończy się jako łatwy do zrozumienia one-liner 😀
$ActiveUsers = (Get-CimInstance Win32_LoggedOnUser -ComputerName $ComputerName).antecedent.name | Select-Object -Unique
Query
Używając dobrego ol’ Query.exe znalazłem omówiony wcześniej parsowanie oparte na szablonach bardzo przydatne.
$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
Teraz muszę tylko sformatować i wyprowadzić użytkowników w ładny sposób. Chcę mieć czyste obiekty z ComputerName i UserName.
# Create nice output format$UsersComputersToOutput = @()foreach($User in $ActiveUsers) { $UsersComputersToOutput += New-Object psobject -Property @{ ComputerName=$ComputerName; UserName=$User } }}# output data$UsersComputersToOutput
Testowanie
Teraz mam problem. Nie mogę tego przetestować, ponieważ nie mam kilku serwerów testowych do mojej dyspozycji. Wszystkie moje testy zostały przeprowadzone na moim własnym komputerze z Windows 10. Wygląda na to, że zapytanie jest o wiele szybsze działające lokalnie, ale WMI/CIM może dać bardziej kompletny widok na to, jakie usługi są uruchomione.
Mam kilka standardowych kont usług działających, które mogą być miłe do usunięcia z danych wyjściowych. Ponadto, aby to było użyteczne, będziemy chcieli uruchomić to na wielu maszynach.
Połączenie Get-ActiveUser z Start-Multithread z ostatniego tygodnia wydaje się działać zgodnie z przeznaczeniem.
Start-Multithread -Script { param($C) Get-ActiveUser -ComputerName $C -Method Query } -ComputerName ::1,Localhost | Out-GridView
Przekazanie powyższego do Out-GridView jest moim ulubionym sposobem na osiągnięcie czegoś naprawdę użytecznego.
Teraz mamy wszystkie dane w ładny, przeszukiwalny sposób i naprawdę łatwo jest sprawdzić czy użytkownik jest zalogowany na jakiejś losowej maszynie. Jest to również łatwy sposób na sprawdzenie użytkowników rouge w twojej sieci.
Publikacja i opinie
Kod jest opublikowany na PowerShellGallery.
Proszę pomóż mi testując go dla mnie. Bardzo chciałbym wiedzieć, czy to działa w prawdziwym świecie 🙂
# To install Get-ActiveUserInstall-Module Get-ActiveUser#To install Start-MultithreadInstall-Module Start-Multithread
To powinno działać, gdy masz zainstalowany WMF 5 + i na Windows 10 po wyjęciu z pudełka.