Do you know this situation? You are responsible for some servers and you planned to do some patching during the weekend. You open a remote desktop to the server with the administrator user and you see that the session is still active. Visual Studio is open with unsaved source code, some config files are open, even somebody’s Facebook is nicely ready for you…
Or you start to install some critical updates and when you want to reboot, Windows tells you that there are other users logged on… you check the users tab in the task manager and you see some “disconnected” sessions. Arggh! 👿
I grew tired of reminding people to log off instead of just closing the session. Some people listened, some are too lazy and won’t listen.
So, I wrote myself a little script which runs every evening and terminates all disconnected sessions, regardless of unsaved shizzle that’s happening in them. Really, people only learn to follow the rules when you hit them where it hurts. Sad, but true.
So, here’s the script…
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 |
<# .SYNOPSIS Checks for disconnected sessions and logs off the disconnected user sessions. .DESCRIPTION Checks for disconnected sessions and logs off the disconnected user sessions. .NOTES File Name: Logoff-DisconnectedSession.ps1 Author : Bart Kuppens Version : 1.1 .EXAMPLE PS > .\Logoff-DisconnectedSession.ps1 #> function Ensure-LogFilePath([string]$LogFilePath) { if (!(Test-Path -Path $LogFilePath)) {New-Item $LogFilePath -ItemType directory >> $null} } function Write-Log([string]$message) { Out-File -InputObject $message -FilePath $LogFile -Append } function Get-Sessions { $queryResults = query session $starters = New-Object psobject -Property @{"SessionName" = 0; "UserName" = 0; "ID" = 0; "State" = 0; "Type" = 0; "Device" = 0;} foreach ($result in $queryResults) { try { if($result.trim().substring(0, $result.trim().indexof(" ")) -eq "SESSIONNAME") { $starters.UserName = $result.indexof("USERNAME"); $starters.ID = $result.indexof("ID"); $starters.State = $result.indexof("STATE"); $starters.Type = $result.indexof("TYPE"); $starters.Device = $result.indexof("DEVICE"); continue; } New-Object psobject -Property @{ "SessionName" = $result.trim().substring(0, $result.trim().indexof(" ")).trim(">"); "Username" = $result.Substring($starters.Username, $result.IndexOf(" ", $starters.Username) - $starters.Username); "ID" = $result.Substring($result.IndexOf(" ", $starters.Username), $starters.ID - $result.IndexOf(" ", $starters.Username) + 2).trim(); "State" = $result.Substring($starters.State, $result.IndexOf(" ", $starters.State)-$starters.State).trim(); "Type" = $result.Substring($starters.Type, $starters.Device - $starters.Type).trim(); "Device" = $result.Substring($starters.Device).trim() } } catch { $e = $_; Write-Log "ERROR: " + $e.PSMessageDetails } } } Ensure-LogFilePath($ENV:LOCALAPPDATA + "\DisconnectedSessions") $LogFile = $ENV:LOCALAPPDATA + "\DisconnectedSessions\" + "sessions_" + $([DateTime]::Now.ToString('yyyyMMdd')) + ".log" [string]$IncludeStates = '^(Disc)$' Write-Log -Message "Disconnected Sessions CleanUp" Write-Log -Message "=============================" $DisconnectedSessions = Get-Sessions | ? {$_.State -match $IncludeStates -and $_.UserName -ne ""} | Select ID, UserName Write-Log -Message "Logged off sessions" Write-Log -Message "-------------------" foreach ($session in $DisconnectedSessions) { logoff $session.ID Write-Log -Message $session.Username } Write-Log -Message " " Write-Log -Message "Finished" |
I created a task in the task scheduler to run this every evening at 9PM.
You can find this script in my GitHub PowerShell repository.
Your tha man Bart! We’re using this with auto task memory monitors too!
thanks, good job