Recently I was asked how to show all logged on users. So I had the idea to make a function out of it. And now I’ll share this function to the community. Who logged on to which computer and when? That is the question for this article. Actually, the main question is: Who is currently logged in?
Prerequisite for this article is a tidy and clean Active Directory environment. Why? Because it takes about 4 seconds to query a computer’s logged on user. If there are still computer accounts in the database which are no longer used, it will take needless longer. Especially if you try to query the entire domain. Let’s dive in.
The Goal
The target is a function that shows all logged on users by computer name or OU. It’s also possible to query all computers in the entire domain. Note that this could take some time. In my test environment it took about 4 seconds per computer on average.
In Action
Computer
Getting the logged on user of client01. It’s Petra. She logged in at 06:41 PM.
Get-UserLogon -Computer client01

OU
Let’s say we have an OU Workstations. If you want to retrieve all logged on users of all computers in this OU run
Get-UserLogon -OU 'ou=Workstations,dc=sid-500,dc=com'

The second example shows the current logged on user on all Domain Controllers.
Ok I have to admit that my screen is a little boring. I’m in in a small Active Directory testing environment. 😉
Entire Domain
Which brings me to the last parameter. It’s a switch parameter. Don’t provide a value.
Get-UserLogon -All

Ok, that’s it. I think this is quite helpful for many of us.
The Function Get-UserLogon
And here is the function itself:
function Get-UserLogon {
[CmdletBinding()]
param
(
[Parameter ()]
[String]$Computer,
[Parameter ()]
[String]$OU,
[Parameter ()]
[Switch]$All
)
$ErrorActionPreference="SilentlyContinue"
$result=@()
If ($Computer) {
Invoke-Command -ComputerName $Computer -ScriptBlock {quser} | Select-Object -Skip 1 | Foreach-Object {
$b=$_.trim() -replace '\s+',' ' -replace '>','' -split '\s'
If ($b[2] -like 'Disc*') {
$array= ([ordered]@{
'User' = $b[0]
'Computer' = $Computer
'Date' = $b[4]
'Time' = $b[5..6] -join ' '
})
$result+=New-Object -TypeName PSCustomObject -Property $array
}
else {
$array= ([ordered]@{
'User' = $b[0]
'Computer' = $Computer
'Date' = $b[5]
'Time' = $b[6..7] -join ' '
})
$result+=New-Object -TypeName PSCustomObject -Property $array
}
}
}
If ($OU) {
$comp=Get-ADComputer -Filter * -SearchBase "$OU" -Properties operatingsystem
$count=$comp.count
If ($count -gt 20) {
Write-Warning "Search $count computers. This may take some time ... About 4 seconds for each computer"
}
foreach ($u in $comp) {
Invoke-Command -ComputerName $u.Name -ScriptBlock {quser} | Select-Object -Skip 1 | ForEach-Object {
$a=$_.trim() -replace '\s+',' ' -replace '>','' -split '\s'
If ($a[2] -like '*Disc*') {
$array= ([ordered]@{
'User' = $a[0]
'Computer' = $u.Name
'Date' = $a[4]
'Time' = $a[5..6] -join ' '
})
$result+=New-Object -TypeName PSCustomObject -Property $array
}
else {
$array= ([ordered]@{
'User' = $a[0]
'Computer' = $u.Name
'Date' = $a[5]
'Time' = $a[6..7] -join ' '
})
$result+=New-Object -TypeName PSCustomObject -Property $array
}
}
}
}
If ($All) {
$comp=Get-ADComputer -Filter * -Properties operatingsystem
$count=$comp.count
If ($count -gt 20) {
Write-Warning "Search $count computers. This may take some time ... About 4 seconds for each computer ..."
}
foreach ($u in $comp) {
Invoke-Command -ComputerName $u.Name -ScriptBlock {quser} | Select-Object -Skip 1 | ForEach-Object {
$a=$_.trim() -replace '\s+',' ' -replace '>','' -split '\s'
If ($a[2] -like '*Disc*') {
$array= ([ordered]@{
'User' = $a[0]
'Computer' = $u.Name
'Date' = $a[4]
'Time' = $a[5..6] -join ' '
})
$result+=New-Object -TypeName PSCustomObject -Property $array
}
else {
$array= ([ordered]@{
'User' = $a[0]
'Computer' = $u.Name
'Date' = $a[5]
'Time' = $a[6..7] -join ' '
})
$result+=New-Object -TypeName PSCustomObject -Property $array
}
}
}
}
Write-Output $result
}
Important Note regarding the Operating System Language
Be aware that the function above uses the quser command that outputs plain text. There are differences between e.g. German servers and English servers. This means, that you’ll get the output shown above only on Englisch operating systems.
Make it permanent
If you like my approach open PowerShell ISE. Copy the function into your ISE session. Create a folder in C:\Program Files\Windows PowerShell\Modules and save the code as psm1 file. Make sure that your file name and folder name match.

From now on, PowerShell will load the custom module each time PowerShell is started.
Acknowledements
Thanks to Jaap Brasser (MVP) for his awesome function Get-LoggedOnUser. His function was a great help for me and it inspired me to get a step further and call all logged on users by OU or the entire domain.
His function can be found here:
https://gallery.technet.microsoft.com/scriptcenter/Get-LoggedOnUser-Gathers-7cbe93ea
Categories: PowerShell, Windows Server




quser is not recognized
LikeLike
Hi Patrick, Got the script to work, except when using “All” – get the following:
PS C:\windows\system32> get-userlogon -All
Get-UserLogon : Missing an argument for parameter ‘All’. Specify a parameter of type ‘System.String’ and try again.
At line:1 char:15
+ get-userlogon -All
+ ~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-UserLogon], ParameterBindingException
+ FullyQualifiedErrorId : MissingArgument,Get-UserLogon
LikeLike
Hello Patrick, thank you for this script – just what I am looking for. However when I run it, the prompt immediately returns with no results on the screen. I’ve copied your script with no alterations. Is there any external modules this script relies on that I may be missing? (Windows 7 workstation)
LikeLike
Hi, there’s an error action silentlycontinue in the script. I would recommend to remove this line and see what happens
LikeLike
Hi Patrick, Like James I do not see any output. I have tried commenting out line 20 with no change. I also changed the property to ‘continue’ with no change. Any ideas?
LikeLike
Hi,
I have tried this method many times, even tried to access the WMI for the user login details. You can get this data for online machines, but do you have any method to get this data directly from AD for all offline machines.
LikeLike
Hi, the solution is a live query for online computer. For all other tasks use other monitoring tools.
LikeLike
Hej, i run the command with the -OU extension. My problem is now this one.
http://prntscr.com/k2vlsn
LikeLike
Hi, can you try it with another OU with less computer
LikeLike
i still have the problem, the funny thing is, i only got the issue stopped at, nothing more.
now i testet a OU with 6 pc i think.
https://prnt.sc/k2vv7e
LikeLike
I have no idea, sorry
LikeLike
Hi there, My script is not working and I am getting Error ( The term ‘Get-UserLogon’ is not recognized as the name of a cmdlet )…
I basically want to get all user names and their respective computers names they use on Domain. Please help in finding such Powershell script.
LikeLike
You have to place it in the correct folder as described.
LikeLike
I would advise against using it… https://support.microsoft.com/en-gb/help/974524/event-log-message-indicates-that-the-windows-installer-reconfigured-al it’s bad news now…
LikeLike
Hello, maybe you could look for the eventlog id then it would be no problem if one os is english and one os is german. Regards
LikeLike
Hi,
Thank you for the hint. You’re right. There are different approaches to accomplish the last user’s logon.
Regards,
P
LikeLike
Hello,
First, thanks a lot for this wonderful script.
I just have one remark. If we run this script targeting a server on which WINRM is not installed, result will be null.
Do you think it could work using “QWINSTA /server:” instead of “quser” ?
In this way, using Invoke-Command won’t be necassary and solve the problem of WINRM.
Best Regards.
Jack!
LikeLike
Hi Jack!
Thanks for your comment and compliment.
You’ll also get a result of null if the computer is not switched on.
Feel free to customize the script to your needs. I had the best results with quser.
All the best,
P
LikeLike
While good enough for small AD for large one it’s not going to work really. Much easier/better would be to utilize Event Logs from AD controller such as https://gallery.technet.microsoft.com/scriptcenter/Get-All-AD-Users-Logon-9e721a89. This way you don’t require machine to online, in correct language and won’t take as much time to query.
LikeLike
Hi!
Thank you for comment.
My command is a live query. What’s better depends on everyone’s needs.
As mentioned in the article it will take about 4 seconds per computer. I am game with that in large environments searching the event logs will be the better solution, but remember that using quser on a client gives you different information than event logs.
All the best,
P
LikeLike
Hello.
Is it possible To get a list of installed application for each users or computer in domain?
I can just extract list of all application from sccm but I want per user or machine
Best Regards/ Cordialement
Mounir
+1 514 293 6955
LikeLike
Hi,
Yes, run Get-CimInstance win32_product to get a list of all installed software on remote computers. But I guess SCCM should give you a list that meets your requirements.
All the best,
P
LikeLike