Tracking the entire history of RDP sessions - powershell

We are trying to get the entire history of rdp servers via powershell.
I already looked at some example's like Qwinsta, quser, query user;
but that is not exactly what I am looking for.
I am looking for something I can write in Powershell to give me the entire history of it. from the day the machine is up.
example :
lets say I have a server I created last year.
I want to know who are the users that has logged into this server in the last year, which one is diss or active (kind of like query user or qwinsta) and when was the last time someone connected to this server.
NAME_OF_SERVER
SESSIONNAME USERNAME ID STATE DEVICE LAST_LOGIN
services 0 Disc
console 1 Conn
rdp-tcp#29 user1 2 Active
user2 3 Disc
appreciate any kind of help.

You can find the history by querying for RDP event logs. There's a handful of different events that will denote an RDP logon, but I'm going to use the RemoteConnectionManager log here:
$RDPAuths = Get-WinEvent -LogName 'Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational' -FilterXPath #'
<QueryList><Query Id="0"><Select>
*[System[EventID=1149]]
</Select></Query></QueryList>
'#
# Get specific properties from the event XML
[xml[]]$xml=$RDPAuths|Foreach{$_.ToXml()}
$EventData = Foreach ($event in $xml.Event) {
# Create custom object for event data
New-Object PSObject -Property #{
TimeCreated = (Get-Date ($event.System.TimeCreated.SystemTime) -Format 'yyyy-MM-dd hh:mm:ss K')
User = $event.UserData.EventXML.Param1
Domain = $event.UserData.EventXML.Param2
Client = $event.UserData.EventXML.Param3
}
}
$EventData | FT
You could pretty easily sort by user and find the last time they logged in using the output in $EventData:
TimeCreated User Domain Client
----------- ---- ------ ------
2021-09-23 12:02:03 -04:00 User01 MyDomain 10.10.10.10
2021-09-23 12:00:42 -04:00 User01 MyDomain 10.10.10.10
2021-09-21 11:39:08 -04:00 User02 MyDomain 10.10.10.20
There's an obvious limitation here that you can only search as far back as your event log goes, so "from the day the machine is up." may not be possible depending on how your event logs are configured.
Another option here can be to just check C:\users\* for which users have ever logged in.
For checking current sessions, I mostly use quser. If your server is running Terminal Services, you can use the RemoteDesktop module and run commands like Get-RDUserSession.

Related

Showing currently logged in user in a PowerShell running from a RMM Software as SYSTEM

i searched hours of my time and saw many ideas for this scenario but nothing worked for my like it should (i tested every code i saw on my own machine but nothing got me to the result i wanted.)
background: we are using a script in our RMM Software to Rename the Agents
$benutzer = [Environment]::UserName
Set-ItemProperty -Path "HKLM:\Software\MMSOFT Design\PC Monitor" -Name ComputerName -Value "$env:USERDOMAIN - $env:Computername - $benutzer"
This script gives us for the $env:USERNAME the user SYSTEM but we actually want the real USERNAME which is logged into this system.
Please help me out :)
The environment variable [System.Environment]::GetEnvironmentVariable('username') will give you the username for the executor of the script, in your case that is System because this is user who ran the code.
If you want to user the environment variable for the user, you must make it so the script been ran from or on behalf of the user, this also means that user must have "permissions" to modify the registry.
If I understand right, you need to know who is the "Logged in user" for the machine where that script runs, unfortunately there is nothing available from PowerShell that do that to my knowledge, instead you could use the build-in tool query for Windows machines, which will provide you with a list with all logged in users to that machine, you would need to further test it to get what you want from it, the output looks like this :
PS C:\Users\t-user> query user
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
>t-user console 1 Active none 8/29/2022 11:58 AM
The trick with query user is that it will provide you with the list of users in case more than one have logged in.
I see what you are trying to do, and here is a "dirty" example of doing it :
$loggedUserList= query user
if($loggedUserList.count -eq 2){
$user = $loggedUserList -split ">" -replace '\s\s+', ';' | convertfrom-csv -Delimiter ';' | select -ExpandProperty username
Write-Host "Logged in user is - $user"
}else{
Write-Host "More than one user have signed"
}

Environment variable clientname gives no result on domain users

I am having trouble getting the expected result for environmental variable clientname in PowerShell.
On Windows 2016 Server through RDP session.
I run the request $env:clientname with a domain user and get no result
I run the request $env:clientname with a local user and get expected connected terminal Hostname.
This is affecting functions on apps running through TS with domain users.
Domain user result:
Local user result:
Read this (very old) MS article
https://support.microsoft.com/en-us/help/2509192/clientname-and-sessionname-enviroment-variable-may-be-missing
It still applies.
Possible fix:
$sessionID = (Get-Process -PID $pid).SessionID
$sessionCLIENTNAME = (Get-ItemProperty -path ("HKCU:\Volatile Environment\" + $sessionID) -name "CLIENTNAME").CLIENTNAME

Powershell - last logged on user - same input, different output

UPDATE
# HAL9256
Your answer really made me think!
I did some more googling, and found this website which offers another approach
http://blogs.technet.com/b/heyscriptingguy/archive/2012/02/19/use-powershell-to-find-last-logon-times-for-virtual-workstations.aspx
So far, it works!
I remote into another server to run a powershell script that displays the last logged on user.
Several things
It only works when I run it in the context of a service account, not
the Administrator
It takes several minutes to output
But when I run it in the contenxt of a service account, I get different output for the same input
$line_array = #()
$multi_array = #()
[hashtable]$my_hash = #{}
foreach ($i in $args){
$line_array+= $i.split(" ")
}
foreach ($j in $line_array){
$multi_array += ,#($j.split("="))
}
foreach ($k in $multi_array){
$my_hash.add($k[0],$k[1])
}
$Sender_IP = $my_hash.Get_Item("sender-ip")
$eventList = #()
Get-EventLog "Security" -computername $Sender_IP `
| Where -FilterScript {$_.EventID -eq 4624 -and $_.ReplacementStrings[4].Length -gt 10 -and $_.ReplacementStrings[5] -notlike "*$"} `
| Select-Object -First 2 `
| foreach-Object {
$row = "" | Select UserName, LoginTime
$row.UserName = $_.ReplacementStrings[5]
$row.LoginTime = $_.TimeGenerated
$eventList += $row
}
$userId = $eventList[0].UserName
$userId
For instance, I invoke the script on commandline with
script.ps1 "sender-ip=10.10.10.10"
The first time I run it, it outputs the user's Window's logon name
The second time I run the same script with same input, it outputs the same service account I used to run the powershell script with
And when I try to run same script with same input, I get the output of this same service account.
~~~~~~~
Next, I try to run the script with another IP address
First time I run the script it outputs the Window's logon name
Second time I run the script, it outputs that same service account from which the powershell script is running
~~~~~~~
This seems to be a pattern. First time script it run, it return correct input, second time it is run, it returns the service account.
Why is this happening?
How to make the script always return the correct output no matter how many times it is invoked?
How to troubleshoot this?
This is because of how your script gets the information about the last logged on user.
You are getting the last logged on user from the security event log. This logs everyone who "logs on" to the computer... including accesses by WMI, service accounts, etc.
What's happening is:
Before Script Runs
Contoso\User1 logs onto computer
EventID 4624 - Logon Success - Contoso\User1 is Logged
Run Script the First time
Script runs as Contoso\ServiceAccount
Script access computer Via WMI to pull Security Event Log
Security Event Log shows last logged on user was Contoso\User1
EventID 4624 - Logon Success - Contoso\ServiceAccount is Logged
EventID 4634 - Logoff Success - Contoso\ServiceAccount is Logged
Run Script the Second time
Script runs as Contoso\ServiceAccount
Script access computer Via WMI to pull Security Event Log
Security Event Log shows last logged on user was Contoso\ServiceAccount
EventID 4624 - Logon Success - Contoso\ServiceAccount is Logged
EventID 4634 - Logoff Success - Contoso\ServiceAccount is Logged
This is because in order to access WMI, you have to authenticate on the computer. Essentially, WMI uses your service account to "log onto" the computer, access the information that it needs, returns the information, and logs off.
This is why you are getting the weird results.
To fix this, you have 3 options:
1.Continue to use the same script to pull out the event log entries. Add code to Filter out the service account name. i.e. use this to get the username:
[System.Security.Principal.WindowsIdentity]::GetCurrent().Name
Then use the "Where -FilterScript" to filter out the user that the script is running as.
The only downside to this method, is that there could be a lot of other service accounts that are running various scheduled tasks, or startup scripts that could change who the "last" logged on user was. It may be better to pull the last 5 logged on users, and then you would have a better idea of what's going on.
2.Use this code to get the currently logged on user:
(gwmi -class win32_computerSystem -computer "ComputerName").username
3.A different and unique way of getting the last logged on user is to use the last write access time on the user profile file (ntuser.dat). Typically only a user logging in "Interactively" will get have a user profile created.
(Get-ChildItem C:\users\*\ntuser.dat -Force | select #{e={(Split-path $_.Directory -Leaf)}},last* | sort lastwritetime -Descending

Measure 'Idle' time between CTRL-ALT-DEL and user typing in password and loging on -Windows 7

Windows 7 has the built in 'Boot Performance Diagnostics' and judging by the numerous reboots i've done, it does generate every now and then a detailed log on the user's login process and possible slowness.
That is not good enough for what I'm after though.
I want to measure EVERY Boot on a given machine.
There is little information however available on how to force it, except fiddling with registry keys that are System Protected so you don't tamper with them.
Some of the information can be found in the eventlogs so i switched to tracing the eventid 12
$yesterday = (get-date) - (New-TimeSpan -day 2)
$startuplog= Get-WinEvent -FilterHashTable #{LogName='System'; ID=12;
StartTime=$yesterday} -ErrorAction SilentlyContinue
But does anyone know how one can measure when the system was ready (ctrl-alt-del) and when the user hit the enter button after typing in the password? Is there a flag that can be set to raise such an event in a (diagnostics) event log?
You can compare the power state timestamp to the "Last Interactive Logon" feature of AD DS. That feature requires a domain functional level (DFF) of Windows Server 2008 r2 to work and workstation infrastructure of windows vista or later. The "msDS-LastSuccessfulInteractiveLogonTime" attribute is what you want. It's the time stamp of the last successful interactive logon (ctrl+alt+del).
To enable Last Interactive Logon on your domain:
http://technet.microsoft.com/en-us/library/dd446680(v=ws.10).aspx
Command to query attribute:
$Computer = 'hostname'
Get-ADComputer -Filter "name -eq $Computer" -Properties * | Select msDS-LastSuccessfulInteractiveLogonTime
P.S. Try to get away from using "-ErrorAction". In it's place, use Try/Catch/Finally code blocks.
http://blogs.technet.com/b/heyscriptingguy/archive/2010/03/11/hey-scripting-guy-march-11-2010.aspx

check for last number of users logged in to machine?

I'm trying to come up with a powershell script thatcan determine the last number of users that logged on to a machine. I'm stuck on to how to approach it. If I'm correct, using a get-wmiobject call will only get the last user. I'm wondering if maybe there is a call I can do to get the history of something like the user folder and get the last users that modified that?Or is there some simpler way?
http://social.technet.microsoft.com/Forums/en/winserverpowershell/thread/c61dc944-6c40-4ab8-93f8-8c345c37b0d4
Basically, all user logins are saved in the security log of each windows server. These are set in the log with the following eventIDs: 528 and 540. These two IDs are for a direct or a remote login to a machine. For my specific need, I have to following line in my script. If you have a similar need, be sure to read up on windows eventIDs on a site like this one
Get-EventLog -logname security -ComputerName $svr -Newest 100 | where {$_.eventID -eq 528
-or 540} | select time,user
enjoy!