GUI to log off Remote Desktop users by non-admins

I’ve blogged about the issues with the well-intentioned but ill-though-out Remote Desktop Management Server concept in Windows Server 2012 (inc R2) before, trying to come up with workarounds to all the things you used to be able to do easily with tsadmin in previous version, that you now just cannot do.

Like delegate non-admin users (e.g. helpdesk, expert users) the ability to log off other users.

So here’s a PowerShell script that falls back on the (very) old but thankfully still perfectly functional quser and logoff commands. My suggestion is to create a group, put the helpdesk users who need this functionality into the group, then grant the group permission via the following command:

wmic /namespace:\\root\CIMV2\TerminalServices PATH Win32_TSPermissionsSetting WHERE (TerminalName ="RDP-Tcp") CALL AddAccount "domain\group",2

You need to run that on all your RDS servers.

Once the helpdesk staff are in the group they’ll need to log off the RDS server and back on again. Now you can give them the script to run.

The script uses quser to get the current user sessions on the server where it’s being run, parses it and displays it in a GridView (with multi-select). Selected users are then logged off via the (also old) logoff Command.
Get your helpdesk user to right-click the script, select “Run with PowerShell”, then just select one or more users to log off and click “OK”.

# Log off RDS user sessions
# For regular users to be able to do this you need to grant them permission:
# wmic /namespace:\\root\CIMV2\TerminalServices PATH Win32_TSPermissionsSetting WHERE (TerminalName ="RDP-Tcp") CALL AddAccount "domain\group",2

# Get the list of users using good old quser (query user)
$QUser = &quser.exe
# Get rid of the Sessionname column because it is inconsistent (contains no data for disconnected sessions)
$QUser = $QUser -replace("rdp-tcp#\d+","")
# Remove header row
$QUser = $QUser -replace("username.+time","")
# Tidy up the spaces to leave one space separator only
$QUser = $QUser -replace("\s+"," ")
# Remove the current user line prefix
$QUser = $QUser -replace(">"," ")
# Split into an array, data starts at position 3, 7 items per line
$QUserArray = $Quser -split " "
# Make an array of objects
$CurrentUsers = New-Object System.Collections.ArrayList
for ($i = 3; $i -lt $QUserArray.Count; $i+=7){
    $ThisUser = New-Object -TypeName System.Object
    Add-Member -InputObject $ThisUser -MemberType NoteProperty -Name "UserName" -Value $QUserArray[$i]
    Add-Member -InputObject $ThisUser -MemberType NoteProperty -Name "ID" -Value $QUserArray[$i+1]
    Add-Member -InputObject $ThisUser -MemberType NoteProperty -Name "State" -Value $QUserArray[$i+2]
    Add-Member -InputObject $ThisUser -MemberType NoteProperty -Name "IdleTime" -Value $QUserArray[$i+3]
    Add-Member -InputObject $ThisUser -MemberType NoteProperty -Name "LogonTime" -Value ($QUserArray[$i+4]+" "+$QUserArray[$i+5])
    $CurrentUsers.Add($ThisUser) | Out-Null
# Display the array in a gridview
$SelectedUsers = $CurrentUsers | Out-GridView -Title "Select users(s) to log off" -OutputMode Multiple
# Log off selected sessions
foreach($User in $SelectedUsers){
    Write-Host ("Logging off "+$User.UserName+" (session ID "+$User.ID+")... ") -NoNewline
    $x = &logoff.exe $User.ID
    Write-Host "Done"
Start-Sleep -Seconds 1
This entry was posted in PowerShell, Remote Desktop, Windows and tagged , , , , , , , , , , , . Bookmark the permalink.

1 Response to GUI to log off Remote Desktop users by non-admins

  1. Bill Leuze says:

    Works great, thanks, finally after quite a search getting something to work for me. 3 things to note:

    -1) In addition to the given command to give the group permissions, I also had to do step 4 in Before I did this, I would get “Error [5]:Access is denied.” with every user I tried to log off. Doing this additional step gave me the added feature that I can restrict permitted users to only log off users in their own branches – if they attempt to log off a user in a different branch (security group) they would get “Error [5]:Access is denied.”

    -2) This does not work for terminal servers that default users to the standard US time format (12 hour clock + AM or PM). In order to fix this:
    change line 19 to: for ($i = 3; $i -lt $QUserArray.Count; $i+=8){
    Change line 25 to: Add-Member -InputObject $ThisUser -MemberType NoteProperty -Name “LogonTime” -Value ($QUserArray[$i+4]+” “+$QUserArray[$i+5]+” “+$QUserArray[$i+6])
    I do not know how to make it work for both 12h and 24h regional settings. My way works for 12h, the authors way works for 24h

    -3) to give the user a grid presorted by username:
    Change Line 29 to: $SelectedUsers = $CurrentUsers | Sort-Object -Property UserName | Out-GridView -Title “Select user(s) to log off and click [OK]” -OutputMode Multiple


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.