Scenario
Let's say you are a user logged into a bunch of machines and you suddenly get locked out? The problem is you don't remember all the machines where you are currently logged in! So you call into your company support line and there are a couple things you need them to:
- Unlock your AD Account
- Figure out what machines you are logged into
During this session, we are going to show a script example that the support personnel can use to find where you are. I began to think of approaches we could use. Some options include:
- Combination of Win32_LogonSession and Win32_LoggedOnUser
- Look for an explorer.exe process and grab the owner
The Idea
I want to keep the script as simple as possible and this isn't the only approach, but here is an example that will essentially enumerate thru a list of reachable (online) computers in ActiveDirectory and check process ownership of explorer.exe. The output is returned to the screen. Then, if we want, we can log the user out on their behalf.
The final script
1: Import-Module -Name ActiveDirectory
2:
3: $computers = Get-ADComputer -Filter * |
4: Select-Object -ExpandProperty Name
5:
6: $username = "Administrator"
7:
8: # This will return only reacheable machines and store
9: # just the destination address
10:
11: $params = @{
12: ComputerName = $computers
13: Count = 1
14: ErrorAction = "SilentlyContinue"
15: }
16:
17: $reacheable = Test-Connection @params |
18: Select-Object -ExpandProperty Address
19:
20: $params = @{
21: Class = "Win32_Process"
22: ComputerName = $reacheable
23: Filter = "name = 'explorer.exe'"
24: Property = "Handle", "CSName"
25: }
26:
27: # Potentially time-consuming as there is no direct
28: # property to return a process owner so we're limited
29: # to local Where-Object filtering
30:
31: $userIsPresent = Get-WmiObject @params |
32: Where-Object { $_.GetOwner().User -eq $username } |
33: Select-Object -ExpandProperty csname
34:
35: "{0} is present on {1}" -f $username, $($userIsPresent -join ", ")
Let's break this out into pieces…
Lines 1-4: We load the ActiveDirectory module for our lone AD Query (Get-ADComputer). The module you can get via the RSAT tools. Click here for where to find them. If you don't like having a dependency on the AD Module for Windows PowerShell, you can use instead the System.DirectoryServices.DirectorySearcher .NET class to do our search for us.
Line 6: We specify a $username value for purposes of the script. To make it more useable, you can instead get the name from the user using the Read-Host cmdlet.
Line 11-18: We first check if the machines are online. The quickest way I can see is to use Test-Connection and have it return just the reachable machines. Now, if the machine is offline or unreachable (aka the plug pulled from the network) then there isn't much we can do about that. The online machines are then stored into a variable called $reacheable.
Line 20-33: This is the heavy lifting and potentially time-consuming component. We set up our parameters and pass it into the Get-WmiObject using a technique called splatting. Line 24 contains the bare minimum property list that we need for this to work. We could have returned all parameters but this is a tad more friendly on the network.
It basically makes it easier to read especially if we have a large number of parameters we are using. We check the result against our $username variable. There isn't a built-in property called Owner so what we do is call the GetOwner() method and that returned object has a User property. That is the property we compare against. We then send it further thru the pipeline where we return an array of the computer names we searched and evaluated to true in the Where-Object cmdlet.
Line 35: We wrap it up by outputting to the user what machines he/she is currently on.