Skip to main content

Discover Who is Logged Onto Your Clients

Recently I helped an IT Pro on PowerShell.com who needed to find out how to discover who was logged into his clients.  Here is the advanced version of the code that allows you to send information via the PowerShell Pipeline.

This code was tested in a PowerShell V3 environment.  If you need to alter the code for a PowerShell V2 without WinRM turned on, make the following changes:

Line 50: "ClassName" to "Class"
Line 58: "Get-CIMInstance" to Get-WMIObject"


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

Function Get-LoggedOnUsers
{
[cmdletBinding()]
    Param (
        [parameter(Mandatory=$true,
         ValueFromPipelineByPropertyName=$true,
         ParameterSetName="Object")]
        [String[]]
        $ComputerName,
        [Parameter(Mandatory=$true,
         ValueFromPipeline=$true,
         ParameterSetName="Name")]
         [String[]]
         $Name
        )

    Begin
    {
        Function CustomObj
        {
            # Create the empty object.
            $Obj = New-Object -TypeName PSObject -Property @{
                'User' = $Null
                'Computer' = $Null
                'Online' = $Null}

                # Provide the object with a custom type name.
            $Obj.psobject.TypeNames.Insert(0, "LoggedOnUser")
           
            # Send the object to the calling statement.
            Write-Output $Obj
        }
    }
    # This is an advance function.
    Process
    {
       
        # If the "Name" parameter is used, copy
        # its contents to the "ComputerName"
        # Parameter.
        If ($Name -ne $Null)
        {$ComputerName = $Name}

        # Cycle through each item in "ComputerName".
        ForEach ($Computer in $ComputerName)
        {   
            Try
            {
                # Hash value used with Get-CIMInstance.
                $CIMHash = @{'ClassName' = "Win32_ComputerSystem";
                             'ComputerName' = $Computer;
                             'EA' = "Stop"}
               
                # Create the object to output.
                $Obj = CustomObj

                # Plug in the data ito the blank object.
                $Obj.User = (Get-CimInstance @CIMHash |
                    Select-Object -ExpandProperty UserName)
                $Obj.Computer = $Computer
                $Obj.Online = $True
          
            }
            Catch
            {
                # Create the object to output.
                # This is the output if no user
                # is currently logged into the
                # target client.
                $Obj = CustomObj
                $Obj.User = "n\a"
                $Obj.Computer = $Computer
                $Obj.Online = $False
            }

            Finally
            {
                # Send the object to the pipeline.
                Write-Output $Obj
            }
         }
    } # End: Process
 
<#
.SYNOPSIS
Returns a list of the users logged into clients targeted by
this cmdlet.

.DESCRIPTION
Returns a list of the users logged into clients targeted by
this cmdlet.  If the user name is listed as " ", then there
is not a user currently logged on.

===============================================================================
== Cmdlet: Get-LoggedOnUsers                                                 ==
== Module: PSV3                                                              ==
==---------------------------------------------------------------------------==
== Author: Jason A. Yoder                                                    ==
== Company: MCTExpert, Inc.                                                  ==
== Blog: MCTExpert.Blogspot.com                                              ==
== Twitter: @JasonYoder_MCT                                                  ==
==---------------------------------------------------------------------------==
== License Information:                                                      ==
== Copyright 2013 - MCTExpert, Inc.                                          ==
== This code is licensed for personal use only.  This code may not be        ==
== re published or distributed in whole or in part without the express       ==
== written consent of MCTExpert, Inc.  All rights reserved.                  ==
==---------------------------------------------------------------------------==
== Disclaimer: The user takes full responsibility for the execution of any   ==
== PowerShell code.  This code is provided without warranty or support.      ==
== As with all PowerShell code, review it and test it in a test environment  ==
== prior to using it in a production environment.  The user takes complete   ==
== responsibility for the results of executing this code.                    ==
===============================================================================

.PARAMETER ComputerName
The names of the computers to return the currently logged
on user.  Use this when passing objects via with a
ComputerName property

.PARAMETER Name
The names of the computers to return the currently logged
on user.

.EXAMPLE
"CL-154", "CL-155", "CL-156"  | Get-LoggedOnUsers

User                 Computer
----                 --------
INDNet\Administrator CL-154 
INDNet\Administrator CL-155 
N\a                  CL-156

.EXAMPLE
Get-ADComputer -filter * |
    Select -Property @{N="ComputerName";E={$PSItem.Name}} |
    Get-LoggedOnUsers

Extracts all the clients from Active Directory and returns
the logged on user.

.EXAMPLE
Get-LoggedOnUsers -Name "CL-154", "CL-155", "CL-156"

User                 Computer
----                 --------
INDNet\Administrator CL-154 
INDNet\Administrator CL-155 
N\a                  CL-156
#>
} # End: Function Get-LoggedOnUsers






Lines 4 – 15 define our two parameters of $ComputerName and $Name.  A parameter set is used so that these two parameters cannot be used at the same time.  $ComputerName is designed to be used from a object that contains a property called “ComputerName”.  $Name is designed to accept a string of names.
Line 17 – 34 is our begin block.   It contains a function that creates a new, empty object.  Line 28 assigned a typename to our object.  This method of creating a object is done to make updating the object with new properties easier and also to  reduce clutter when populating the objects properties.
Lines 35 – 82 executes for each object passed to this cmdlet.
Lines 41 and 42 ensure that no matter which parameter is used, the data is processed.
Lines 45 – 81 loops through each client.
Lines 47 and 64 are the Try..Catch blocks that will handle any clients that are not online.  A possible error may occur on line 58 where the script reaches out to the remote client.  If the client is online, the currently logged on user name is extracted.  If it is not online, the CATCH block executes and populates the object with user “n\a” and Online = $False.
Line 76 starts the FINALLY block which will execute no matter if a connection error occurred or not.  It wends the object to the PowerShell pipeline.

Comments

Anonymous said…
I'm a noob and I can't get it to work. I save your code in a .ps1 file and run it in powershell and it just goes back to a command prompt, no error, no output, nothing.
Anonymous said…
Noob again, I now have the script generating output but all computers are reporing n/a offline but I know for a fact they are online with users logged in and I can ping the machines. Any ideas? Thanks.
Take a look at line 58. The remoting technology used is provided by the WIMRM service. Here are two work arounds to try.


1) Enable PowerShell remoting: http://mctexpert.blogspot.com/2011/03/enable-powershell-v2-remote-management.html

2) Change line 50 from 'ClassName' to 'Class"
Change line 58 from Get-CIMInstance to Get-WMIObject.

hope this helps.
Remember, this is a script cmdlet. you can dot source it into global memory of your current session: http://mctexpert.blogspot.com/2011/04/dot-sourcing-powershell-script.html

You can also place it into a personal module. http://mctexpert.blogspot.com/2011/04/creating-powershell-module.html

In the end, you need to type the cmdlet name to get it to work.
Anonymous said…
Thank you Jason! You sir, are a genius! After making your changes to lines 50 and 58 and dot sourcing it as you mentioned it now seems to be working! Thank you again!
Glad this I could help!

Popular posts from this blog

How to list all the AD LDS instances on a server

AD LDS allows you to provide directory services to applications that are free of the confines of Active Directory.  To list all the AD LDS instances on a server, follow this procedure: Log into the server in question Open a command prompt. Type dsdbutil and press Enter Type List Instances and press Enter . You will receive a list of the instance name, both the LDAP and SSL port numbers, the location of the database, and its status.

How to run GPResult on a remote client with PowerShell

In the past, to run the GPResult command, you would need to either physically visit this client, have the user do it, or use and RDP connection.  In all cases, this will disrupt the user.  First, you need PowerShell remoting enabled on the target machine.  You can do this via Group Policy . Open PowerShell and type this command. Invoke-Command –ScriptBlock {GPResult /r} –ComputerName <ComputerName> Replace <ComputerName> with the name of the target.  Remember, the target needs to be online and accessible to you.

Error icon when creating a GPO Preference drive map

You may not have an error at all.  Take a look at the drive mapping below. The red triangle is what threw us off.  It is not an error.  It is simply a color representation of the Replace option of the Action field in the properties of the drive mappings. Create action This give you a green triangle. The Create action creates a new mapped drive for users. Replace Action The Replace action gives you a red triangle.  This action will delete and recreate mapped drives for users. The net result of the Replace action is to overwrite all existing settings associated with the mapped drive. If the drive mapping does not exist, then the Replace action creates a new drive mapping. Update Action The Update action will have a yellow triangle. Update will modify settings of an existing mapped drive for users. This action differs from Replace in that it only updates settings defined within the preference item. All other settings remain as configured on the mapped drive. If the