How do I find what computer a user is logged into in Powershell?

I have a list of user names that I need to find out what computer each is logged into.  I would like to do this in Powershell.  How do I do this?
mossybackAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

TribusCommented:
See if this script from Spiceworks helps you:

http://community.spiceworks.com/scripts/show/1055-find-computers-a-user-is-logged-into

And here is another article to integrate this into AD:

http://deployhappiness.com/find-out-what-computer-a-user-logged-into/
0
arrorynCommented:
This command should remotely interrogate what you need:

"gwmi -computername computername -class win32_computersystem -property username"

(remove the quotes)

You can attach this to a scheduled task and report at logon, if you don't want to do this kind of stuff via GPO.

Info sourced from here
0
mossybackAuthor Commented:
Thanks Tribus.  Unfortunately my rights allow me to query AD but not make any changes to it.  So no snappins or group policie changes will work for me.  If I could take a list of user names and run it against an OU with thousands of computers in it to find the computer name the user is logged into that would be fine.
0
Simplify Active Directory Administration

Administration of Active Directory does not have to be hard.  Too often what should be a simple task is made more difficult than it needs to be.The solution?  Hyena from SystemTools Software.  With ease-of-use as well as powerful importing and bulk updating capabilities.

becraigCommented:
Here is a rough concept:

Import-Module activedirectory
$servers = Get-ADComputer  -filter {name -like "whatever filter you are using"} | select -expand name 
Foreach ($server in $servers)
{
#you could simply use if / else logic here it is expensive but gets what you want
$logcheck =  Get-WmiObject Win32_LoggedOnUser {$_.Antecedent -like "*user*"}
if ($logcheck -ne "")
{
#you can make some action here
write-host "user is logged on to computer"
}
}

Open in new window

0
footechCommented:
This is a bit of a difficult question to answer.  See this link for some explanation of different methods that can work and their problems.
http://blogs.technet.com/b/heyscriptingguy/archive/2011/03/17/use-powershell-to-detect-if-a-workstation-is-in-use.aspx

Here's a script I had put together to find all machines where a user was logged on using the SysInternals tool PsLoggedOn.exe (if you look at the code you can see its path referenced).  I have modified it a bit to check for multiple users.
# This script checks machines to see if a specific user is currently logged on.
# Utilizes the SysInternals tool PsLoggedOn.exe
# Since the Remote Registry service has to be running for that utility to
# function, the script first checks if the service is running; if it is not, 
# the service is started.  After the user check, the service is stopped only
# if it was started by this script.


Import-Module ActiveDirectory
$usernames = Get-Content "userlist.txt"
$computers = Get-ADComputer -filter * | Select -ExpandProperty Name | Sort
$results = @()
$results += "Beginning operation at $(Get-Date)"
$i = 0
[bool]$regStart = $false
[bool]$regDisabled = $false
Foreach ($computer in $computers)
{
    $i++
    Write-Progress -activity "Progress Indicator" -status "Testing Connection" -currentOperation "Checking computer ""$computer"" ($i of $($computers.count))" -percentComplete (($i/$computers.count) * 100)
    # Check if the account is alive
    If (Test-Connection $computer -count 1 -quiet)
    {
        Write-Progress -activity "Progress Indicator" -status "Checking Remote Registy Service" -currentOperation "Checking computer ""$computer"" ($i of $($computers.count))" -percentComplete (($i/$computers.count) * 100)
        # Check if the Remote Registry service is stopped.  If so, we need to start it (PSLoggedOn.exe needs it to be running).
        $regSvcStatus = gwmi win32_service -computername $computer -filter "name = 'RemoteRegistry'" -property State,StartMode -ErrorAction SilentlyContinue
        If ($regSvcStatus.State -eq "Stopped")
        {
            If ($regSvcStatus.StartMode -eq "Manual")
            {
                & cmd /c "sc \\$computer start RemoteRegistry" | Out-Null
                [bool]$regStart = $true
                Start-Sleep -Seconds 2
            }
            ElseIf ($regSvcStatus.StartMode -eq "Disabled")
            {
                & cmd /c "sc \\$computer config RemoteRegistry start= demand" | Out-Null
                & cmd /c "sc \\$computer start RemoteRegistry" | Out-Null
                [bool]$regStart = $true
                [bool]$regDisabled = $true
                Start-Sleep -Seconds 1
            }
        }
            
        
        Write-Progress -activity "Progress Indicator" -status "Querying Logged On Users" -currentOperation "Checking computer ""$computer"" ($i of $($computers.count))" -percentComplete (($i/$computers.count) * 100)
        
        $results += c:\sysinternalssuite\PsLoggedon.exe -x -l \\$computer |
         Where-Object {$_ -match '^\s{2,}((?<domain>\w+)\\(?<user>\S+))|(?<user>\S+)'} |
         Where { $usernames -contains $matches.user } |
         ForEach `
         {
            Write-Output "$($matches.user) is logged on to $computer"
         }
        # If we start the Remote Registry service earlier, return it to the stopped state.
        If ($regStart -eq $true)
        {
            Write-Progress -activity "Progress Indicator" -status "Resetting Remote Registry Service" -currentOperation "Checking computer ""$computer"" ($i of $($computers.count))" -percentComplete (($i/$computers.count) * 100)
            & cmd /c "sc \\$computer stop RemoteRegistry" | Out-Null
            [bool]$regStart = $false
        }
        If ($regDisabled -eq $true)
        {
            Write-Progress -activity "Progress Indicator" -status "Disabling Remote Registry Service" -currentOperation "Checking computer ""$computer"" ($i of $($computers.count))" -percentComplete (($i/$computers.count) * 100)
            & cmd /c "sc \\$computer config RemoteRegistry start= disabled" | Out-Null
            [bool]$regDisabled = $false
        }
    }
}
$results += "Finished operation at $(Get-Date)"
$results | Out-File loggedon.txt

Open in new window

0
becraigCommented:
I also bumped into a function here for what you need as well:

     [Cmdletbinding()]
        param (
            [Parameter(Position=0)]
            [String[]]$Computername = $ENV:COMPUTERNAME,
                   
                    [Parameter(Position=1)]
                    [ValidateSet('0','LocalSystem','2','Interactive','3','Network','4','Batch','5',
                    'Service','6','Proxy','7','Unlock','8','NetworkCleartext','9','NewCredentials',
                    '10','RemoteInteractive','11','CachedInteractive','12','CachedRemoteInteractive',
                    '13','CachedUnlock','All')]
                    [String[]]$LogonType = @('0','2','3','4','5','6','7','8','9','10','11','12','13') # All
        )
     
        Begin{
                # define LogOnType hashtable for to convert Numbers into Text
                $HashLogonType = @{
                    '0'='LocalSystem'
                    '2'='Interactive'
                    '3'='Network'
                    '4'='Batch'
                    '5'='Service'
                    '6'='Proxy'
                    '7'='Unlock'
                    '8'='NetworkCleartext'
                    '9'='NewCredentials'
                    '10'='RemoteInteractive'
                    '11'='CachedInteractive'
                    '12'='CachedRemoteInteractive'
                    '13'='CachedUnlock'
                }
               
        } # end Begin block
     
        Process {       
            ForEach($CurComputerName in $ComputerName) {           
                $LogonSessions = Get-WmiObject Win32_LogonSession -ComputerName $CurComputerName     
                ForEach($LogonSession in $LogonSessions) {                   
                    $LoggedOnUser = Get-WmiObject -Query "Associators of {Win32_LogonSession.LogonId=$($LogonSession.LogonId)} Where AssocClass=Win32_LoggedOnUser Role=Dependent" -ComputerName $CurComputerName |
                        Select-Object Domain,Name,SID,StartTime,LogonID,LogonType,LogonTypeName,ComputerName
                   
                    $LoggedOnUser.StartTime = [Management.ManagementDateTimeConverter]::ToDateTime($LogonSession.starttime)
                    $LoggedOnUser.LogonID = $LogonSession.LogonID
                    $LoggedOnUser.LogonType = $LogonSession.logontype
                    $LoggedOnUser.LogonTypeName = $HashLogonType[[String]$LogonSession.logontype]
                    $LoggedOnUser.ComputerName = $CurComputerName
                   
                                    # Filter selected LogonTypes to report
                                    If($LogonType -contains [String]$LoggedOnUser.LogonType -or $LogonType -contains $LoggedOnUser.LogonTypeName) {
                                            # return result object
                                            $LoggedOnUser
                                    }
                } # end  ForEach $LogonSession
               
            }  # end ForEach $Computer
             
        } # end process block
        End {}
     
    }

Open in new window


reposted from:
http://poshcode.org/4304


You can modify the script above to do exactly what you are asking for (feeding in both computer name from an AD scan and users from a text file input).
0
becraigCommented:
So here you go this is so simple it made me smile :)

Import-Module activedirectory
$servers = (Get-ADComputer  -filter {name -like "*"} | select -expand name )
$users = (gc usertext.txt)       
            ForEach($server in $servers) {
                $LogonSessions = Get-WmiObject Win32_LogonSession -ComputerName $server     
                ForEach($LogonSession in $LogonSessions) {
                    $LoggedOnUser = Get-WmiObject -Query "Associators of {Win32_LogonSession.LogonId=$($LogonSession.LogonId)} Where AssocClass=Win32_LoggedOnUser Role=Dependent" -ComputerName $server | select-Object Domain,Name,SID,StartTime,LogonID,LogonType,LogonTypeName,ComputerName
foreach ($user in $users)
{
if ($LoggedOnUser.Name -eq "username")
{
                    $LoggedOnUser.StartTime = [Management.ManagementDateTimeConverter]::ToDateTime($LogonSession.starttime)
                    $LoggedOnUser.LogonID = $LogonSession.LogonID
                    $LoggedOnUser.LogonType = $LogonSession.logontype
                    $LoggedOnUser.ComputerName = $server
                    $since = $LoggedOnUser.StartTime
@"
==============================================
Login found on $server for username
Logged in since $since
==============================================
"@
                 }
				 } #End foreach user
                } # end  ForEach $LogonSession               
            }  # end ForEach $Computer
             
  

Open in new window


Here is the concept:
We search the ad for the computer you can create your own filter.
Once we have done that we simply do a wmi call for login session
Then we proceed to get the other object such as domain username etc based on the previous wmi query
Last we check if any of the users in your text file show a current login and show the login since time.

Of course guys like footech subsun and Qlemo can tweak this even more for you but I think this gets you where you need to go.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
mossybackAuthor Commented:
All,

There is some good stuff here for me to try which sadly I have not had the time to do.  I hope to get back to it this weekend.  Thanks for the comments!
0
becraigCommented:
Did this ever work for you ?

Or did you need any additional help to identify a better solution ?
0
mossybackAuthor Commented:
I am having a can not locate a server with AD web services available.  I may not be able to do what I want since I am not an AD administrator.
0
becraigCommented:
Can you try running this from a poweshell console and tell me what you get:
Import-Module activedirectory
$servers = (Get-ADComputer  -filter {name -like "*"} | select -expand name )
$servers

Open in new window


You can simply run that from a powershell window, let me know if you get an error or not.

If you get an error paste the exact output in your response
0
mossybackAuthor Commented:
Again thanks for your patience becraig - Here's what I am getting when running the command posted by: becraigPosted on 2013-10-16 at 14:48:43ID: 39577805 .  


Import-Module activedirectory
$servers = (Get-ADComputer  -filter {name -like "*"} | select -expand name )
$servers
WARNING: Error initializing default drive: 'Unable to find a default server with Active Directory Web Services running.'.
Get-ADComputer : Unable to find a default server with Active Directory Web Services running.
At line:2 char:27
+ $servers = (Get-ADComputer <<<<   -filter {name -like "*"} | select -expand name )
    + CategoryInfo          : ResourceUnavailable: (:) [Get-ADComputer], ADServerDownException
    + FullyQualifiedErrorId : Unable to find a default server with Active Directory Web Services running.,Microsoft.ActiveDirectory.Management.Commands.GetADComputer
0
mossybackAuthor Commented:
When I run get-module right the above command after I get:

get-module

ModuleType Name                      ExportedCommands                                              
---------- ----                      ----------------                                                          
Manifest   activedirectory           {Set-ADOrganizationalUnit, Get-ADDomainControllerPasswordReplicationPoli...
0
becraigCommented:
Do you already have a list of servers you want to run this against or do you really need to query the AD for all computers ?
0
mossybackAuthor Commented:
I could query an OU in Ad to see what computers the list of users I have are logged into.  I still can NOT get past the error "unable to find a default server with Active Directory Web services running".
0
footechCommented:
Could query, or could not query?
There's only one command in my script and in becraig's that uses a MS AD cmdlet, and it's used to gather a list of computers.  That's why becraig asked if you already have a list of servers, since if you do we can skip the AD query and avoid that error.

If you have a text file with the list of servers you could just do
$servers = Get-Content serverlist.txt

Open in new window


Another way of performing the query without the MS AD cmdlets is
$servers = ([ADSISearcher]"ObjectClass=Computer").FindAll() | % {$_.Properties.name}

Open in new window

0
footechCommented:
This question's been open for quite a while.  Please respond to comments promptly or close the question.  Thanks.
0
Senior IT System EngineerIT ProfessionalCommented:
Somehow my script error as follow:

Get-WmiObject : Not found 
At C:\Users\administrator\AppData\Local\Temp\bdd24f5d-3f01-46e7-a963-e6226a529443.ps1:8 char:50
+                     $LoggedOnUser = Get-WmiObject <<<<  -Query "Associators of {Win32_LogonSession.LogonId=$($LogonSession.LogonId)} Where AssocClass=Win32_LoggedOnUser Role=Dependent" -ComputerName $server
 | select-Object Domain,Name,SID,StartTime,LogonID,LogonType,LogonTypeName,ComputerName
    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], ManagementException
    + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.