Advanced Windows PowerShell Scripting Video Training

Advanced Windows PowerShell Scripting Video Training
Advanced Windows PowerShell Scripting Video Training

Thursday, October 3, 2013

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.

6 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.

Jason Yoder, MCT said...

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.

Jason Yoder, MCT said...

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!

Jason Yoder, MCT said...

Glad this I could help!