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

Adding a Comment to a GPO with PowerShell

As I'm writing this article, I'm also writing a customization for a PowerShell course I'm teaching next week in Phoenix.  This customization deals with Group Policy and PowerShell.  For those of you who attend my classes may already know this, but I sit their and try to ask the questions to myself that others may ask as I present the material.  I finished up my customization a few hours ago and then I realized that I did not add in how to put a comment on a GPO.  This is a feature that many Group Policy Administrators may not be aware of. This past summer I attended a presentation at TechEd on Group Policy.  One organization in the crowd had over 5,000 Group Policies.  In an environment like that, the comment section can be priceless.  I always like to write in the comment section why I created the policy so I know its purpose next week after I've completed 50 other tasks and can't remember what I did 5 minutes ago. In the Group Policy module for PowerShell V3, th

Return duplicate values from a collection with PowerShell

If you have a collection of objects and you want to remove any duplicate items, it is fairly simple. # Create a collection with duplicate values $Set1 = 1 , 1 , 2 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 2   # Remove the duplicate values. $Set1 | Select-Object -Unique 1 2 3 4 5 6 7 What if you want only the duplicate values and nothing else? # Create a collection with duplicate values $Set1 = 1 , 1 , 2 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 2   #Create a second collection with duplicate values removed. $Set2 = $Set1 | Select-Object -Unique   # Return only the duplicate values. ( Compare-Object -ReferenceObject $Set2 -DifferenceObject $Set1 ) . InputObject | Select-Object – Unique 1 2 This works with objects as well as numbers.  The first command creates a collection with 2 duplicates of both 1 and 2.   The second command creates another collection with the duplicates filtered out.  The Compare-Object cmdlet will first find items that are diffe

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.