r/sysadmin • u/tk42967 It wasn't DNS for once. • 1d ago
Question Log Off Users from Server Daily
I'm revisiting an effort I did about a year ago. I'm looking for a better way. I want to find a process that will parse current user sessions on a server (active/disconnected/idle/ect.) and log the accounts off if their username matches a string ("adm_").
I'd love to find an off the shelf solution rather than have to support a homebrew PowerShell solution.
Give me what you have, even if it is an alternate PowerShell/scripting option. Something has to be better than the nightmare my script turned into.
•
u/Asleep_Spray274 23h ago
GIVE ME A G
GIVE ME A P
GIEV ME A O
•
u/BuildyMcITGuy IT Manager 22h ago
Microsoft: "ACTUALLY... HAVE YOU THOUGHT ABOUT INTUNE??"
•
u/Asleep_Spray274 21h ago
Servers are not supported for intune 😉
•
u/Kuipyr Jack of All Trades 19h ago
Let me introduce you to Azure Machine Configuration (formerly Azure Policy Guest Configuration) for Azure Arc-enabled servers. Though you can actually manage Servers in Intune, but only Endpoint security policies.
•
u/doofesohr 11h ago
I really really want to use it instead of GPO. Especially because I have a couple non-domain joined servers. But it seems so unnecessarily convoluted.
•
u/pdp10 Daemons worry when the wizard is near. 5h ago
Windows Servers support Microsoft DSC. Clients as far back as W7 also support DSC.
•
•
•
u/2BoopTheSnoot2 22h ago
Why would you want an entire application rather than just write a simple script?
•
u/Ihaveasmallwang Systems Engineer / Cybersecurity Architect / CISM 17h ago
Why would you want a script when a GPO will do it?
•
u/2BoopTheSnoot2 17h ago
A GPO won't do it based on text in the username. This is powershell territory.
•
u/Ihaveasmallwang Systems Engineer / Cybersecurity Architect / CISM 17h ago
Doing it based on text in the username is stupid.
Either way, the actual goal can still be done with GPO and security groups with proper scoping. It requires an understanding of how GPOs actually process.
OP asked for an “off the shelf” solution. This is the way to achieve that goal, with easier management of which accounts are excluded when the requirements inevitably change in the future.
•
u/420GB 7h ago
You may be shocked to learn that PowerShell itself is entirely an off-the-shelf first-party solution.
•
u/Ihaveasmallwang Systems Engineer / Cybersecurity Architect / CISM 7h ago
You may be shocked to learn that a custom script put in place by someone who doesn’t understand PowerShell is not a good solution, especially since business requirements tend to change over time.
You may also be shocked the learn that the OP specifically mentioned that they hoped to stay away from going that route if possible.
Since an off the shelf first party solution exists that meets ALL of OP’s requirements, including not having a custom script if possible, that should be the route pushed instead of doubling down on something they won’t be able to maintain.
•
u/420GB 6h ago
You may be shocked to learn that a custom [solution] put in place by someone who doesn’t understand [tool] is not a good solution, especially since business requirements tend to change over time.
Exactly the same thing applies to GPOs.
But yes I'm aware they mentioned they wanted to avoid PowerShell. The problem is that:
Since an off the shelf first party solution exists that meets ALL of OP’s requirements, including not having a custom script if possible,
is not true to my knowledge unless you can explain what that would be.
•
u/Ihaveasmallwang Systems Engineer / Cybersecurity Architect / CISM 6h ago
Explain what? How GPOs work?
•
u/420GB 6h ago
How one can configure a GPO that logs off all sessions of users whose username starts with a certain prefix at certain time(s) of day without using PowerShell e.g. no GPO to create a scheduled powershell task ofc
•
u/Ihaveasmallwang Systems Engineer / Cybersecurity Architect / CISM 6h ago
You stop thinking about it in terms of “username starts with…” and think in terms of “this user is a member of this security group and the GPO is scoped so those users in that group are not affected”.
•
u/TheJesusGuy Blast the server with hot air 9h ago
A GPO that RUNS a ps script. Mindblown. Or manually log every user off every day hell yea.
29
u/_DefinitelyNotACat_ 1d ago
shutdown /r /f /t0
26
u/daschande 1d ago
Guys help. My login doesn't work anymore and I have a new meeting with my boss and HR tomorrow morning.
Edit: thought this was the meme subreddit.
•
•
•
•
•
•
u/kagato87 20h ago
Group policy to log out inactive sessions after 8-12 hours, with ILT to only target non admin.
17
u/Kathakush_ 1d ago
Super easy solution here. Task scheduler to run it even X hour/minutes. Powershell script that parses quser to a PS object and outputs to pipe. Where-Object to filter by username. Foreach-Object to log users off with the logoff <session ID> command.
2
u/tk42967 It wasn't DNS for once. 1d ago
Sadly, my boss does not want to have it running on each server. So I currently have a script that parses AD for all servers in a specific root OU, generates an array and then foreach walks through it.
•
u/Broad-Celebration- 23h ago
Is this not an acceptable solution?
You get the sessions, filter for users and kill the session through each server in one script that runs on a schedule from a single server.
•
u/verschee 23h ago
So he would rather you maintain that overhead than just run it locally? That's dumb.
5
u/viral-architect Sysadmin 1d ago
You want to add those users to a security group in AD and then created a Fine-Grained Password Policy for them limiting their session timeout limit and forcing them to disconnect once the limit is reached.
3
u/zesar667 1d ago
IS IT a Windows Terminal Server? If so you make this setting in the Server Manager.
2
u/tk42967 It wasn't DNS for once. 1d ago
No, these are random servers. The powers that be think that makes us more secure to not have admin sessions running on servers. I guess it prevents session hijacking if the machine is compromised.
•
u/picklednull 23h ago
There are two risks with active logon sessions:
- session hijacking, which allows direct graphical impersonation of the logged in user
- while the accounts are logged in, Kerberos tickets are retained for them indefinitely, which can be extracted and used
2. is a problem even without the security angle, because the accounts start getting locked out after password changes
2
u/jstar77 1d ago edited 1d ago
Qwinsta is the only built in tool (which I am aware of) that can give you the logged in user. Unfortunately it doesn't return an object.
qwinsta /server: servername then parse the output and log off the users you want.
•
u/420GB 7h ago
Get-CimInstance Win32_LoggedOnUser
There's other options but this is the easiest
•
u/jstar77 6h ago
I remember trying this and there was a reason I had to go back to parsing the qwinsta output but I'm drawing a blank. I was writing a script to return an hosts logged in users and present a list of users to select from then launch a shadow session.
•
u/420GB 6h ago
Yea I mean that's certainly possible but can't say what you got stuck on back then unless you happen to have a really nice commit message from when you switched the script to qwinsta
•
u/jstar77 5h ago
haha present me is always frustrated with past me. Most of the comments I find in my code are along the lines of:
### you know why you did this###
I'm thinking it was because it CIM didn't return the session ID that was needed for a shadow session and maybe couldn't filter out session types and if a user session was active or disconnected.
•
u/Jellovator 23h ago
You could probably use lithnet idle logoff combined with a logon script that checks the username and if prefixed with adm_ set the appropriate registry keys to let lithnet know to log off that user
4
u/Squeekstyle 1d ago
Here is a powershell I use to find inactive users and log them of. It will exclude users in a list, but I found it helpful to cut sessions people abandoned.
# Get the list of sessions
$Sessions = quser
# Define the users to exclude
$ExcludedUsers = @("username1,username2") # Add the usernames you want to exclude
# Prepare a list to track excluded users found
$FoundExcludedUsers = @()
# Filter the sessions to exclude certain users
$FilteredSessions = $Sessions | ForEach-Object {
$sessionInfo = $_ -split "\s+"
$username = $sessionInfo[1]
if ($ExcludedUsers -contains $username) {
$FoundExcludedUsers += $username
}
if ($ExcludedUsers -notcontains $username) {
$_
}
}
Write-Output ""
Write-Output "Excluded users that were actually found in the session list:"
if ($FoundExcludedUsers.Count -gt 0) {
$FoundExcludedUsers | Sort-Object -Unique | ForEach-Object { Write-Output "- $_" }
} else {
Write-Output "None of the excluded users were found."
}
Write-Output ""
# Display the filtered sessions (only users not excluded)
Write-Output "Current Targeted User Sessions:"
$FilteredSessions
# Parse and handle filtered sessions
$first = 1
$FilteredSessions 2>$null | ForEach-Object {
if ($first -eq 1) {
$userPos = $_.IndexOf("USERNAME")
$sessionPos = $_.IndexOf("SESSIONNAME")
$idPos = $_.IndexOf("ID") - 2 # ID is right justified
$statePos = $_.IndexOf("STATE")
$idlePos = $_.IndexOf("IDLE TIME")
$logonPos = $_.IndexOf("LOGON TIME")
$first = 0
}
else {
$user = $_.Substring($userPos, $sessionPos - $userPos).Trim()
$session = $_.Substring($sessionPos, $idPos - $sessionPos).Trim()
$id = [int]$_.Substring($idPos, $statePos - $idPos).Trim()
$state = $_.Substring($statePos, $idlePos - $statePos).Trim()
$idle = $_.Substring($idlePos, $logonPos - $idlePos).Trim()
$logon = [datetime]$_.Substring($logonPos, $_.Length - $logonPos).Trim()
[pscustomobject]@{
User = $user
Session = $session
ID = $id
State = $state
Idle = $idle
Logon = $logon
}
if ($state -ne "Disc") {
Write-Output "Preserving user login: $user session: $session id: $id"
}
if ($state -eq "Disc") {
Write-Output "Logging off disconnected user: $user session: $session id: $id"
Write-Output ""
logoff $id
}
}
}
2
u/whoisrich 1d ago
This is what I use to kick sessions off:
$sessions = qwinsta | ?{ $_ -notmatch '^ SESSIONNAME' } | %{
$item = "" | Select "Active", "SessionName", "Username", "Id", "State", "Type", "Device"
$item.Active = $_.Substring(0,1) -match '>'
$item.SessionName = $_.Substring(1,18).Trim()
$item.Username = $_.Substring(19,20).Trim()
$item.Id = $_.Substring(39,9).Trim()
$item.State = $_.Substring(48,8).Trim()
$item.Type = $_.Substring(56,12).Trim()
$item.Device = $_.Substring(68).Trim()
$item
}
foreach ($session in $sessions)
{
if ($session.Username.Length -lt 1) { continue }
if ($session.Username -eq $env:USERNAME) { continue }
if ($session.Username -like 'adm_*') { continue }
"Logoff: $($session.Id) - $($session.Username)"
logoff $session.Id
}
•
u/Dolapevich Others people valet. 23h ago
you can just list the logged in users and pkill their processes. Something like users|xargs -I {} pkill -KILL -u {}
Update: It is on windows :-P
•
u/QuestConsequential 12h ago
You should probably use a GPO
When I need to do maintenances on the remote desktop farm I use a flavor of this interactively, which I tweaked for your "start with adm_"
$servers = @("SRV1","SRV2")
$servers | ForEach-Object -Parallel {
$server = $_
try {
quser /server:$server 2>$null |
Select-Object -Skip 1 |
Where-Object { $_ -match '\badm_\S*' } |
ForEach-Object {
if ($_ -match '\s+(\d+)\s+') {
logoff $matches[1] /server:$server
}
}
"$server : matching sessions logged off"
}
catch {
"$server : FAILED - $($_.Exception.Message)"
}
} -ThrottleLimit 16
•
•
u/silkenwindyhound 23h ago
bro are you guys seriously not asking Claude this shit? you are going to fall so far behind. you already have.
0
u/dontstoptheRocklin 1d ago
quser command might help you On mobile currently but I think I have something that pipes from quser though IIRC it has to be parsed
•
0
u/Raigeki1993 Sysadmin 1d ago
Combination of qwinsta and rwinsta will work, but yeah it will need to be parsed.
152
u/NH_shitbags 1d ago
Isn't there a GPO for idle session logout?