Terminal Services/Remote Desktop Script Library

These are TS-specific VBScript procedures I have pulled from code I keep up; the page also includes any non-TS functions upon which the TS functions are dependent.

These procedures have all been tried at one time or another against a Windows 2000 Terminal Server, and against XP Professional if appropriate.  They will probably all work against .NET server.

They have not been tested against NT 4 TSE nor in a Citrix environment.  If run on NT4 TSE they might work if WMI and a recent (5.1+) versionof WSH have been installed.  If you try it, let me know the effects.

Besides the functions, I also have some TS miniscript fragments that may be useful.


Logging User Logon Events

This chunk of VBScript can be used in logon scripts to record client name, username, and time of any successful TS/Remote Desktop logons.

Set Sh = CreateObject("WScript.Shell")
sys = Sh.ExpandEnvironmentStrings("%CLIENTNAME%")
User = CreateObject("WScript.Network").Username
Sh.LogEvent 4, "Logon by " & User & " from " & sys

Where's TSWeb?

Not sure where your TSWeb folder is?  Run this to pop it open.

'Webclients.vbs
Set Sh = CreateObject("WScript.Shell")
sData = Sh.Regread( _
 "HKLM\SOFTWARE\Microsoft\TS Web Clients\InstallDir")
WScript.Echo "Web Clients folder is", sData
Sh.Run "%COMSPEC% /c start " & sData & "\.", 0

Kill TS Sessions

The script below will kill off all active TS Sessions.  Use judiciously; it will NOT impress your boss to lose 2 hours of unsaved work on a presentation because you forced everyone out with this on a Sunday night.

' KillTsSessions.vbs
' Finds all active TS sessions on server HOST defined
' below and terminates them.  Does not terminate the
' current session if being run remotely.
' If running on local host, set HOST value to ""

HOST = ""


' Get disconnected sessions and log them off
sessions = DisconnectedSessions(HOST)

For each session in sessions
 TerminateWinSession HOST, sessionId
Next

' Now get active sessions and log them off
sessions = ActiveSessions(HOST)

For each session in sessions
 TerminateWinSession HOST, sessionId
Next

Sub TerminateWinSession(Host, sessionId)
 Dim Sh, tmpHost
 Set Sh = createobject("WScript.Shell")
 if trim(Host)="" Then
  tmpHost = ""
 Else
  tmpHost = " /SERVER:" & Host
 End If
 Sh.Run "%COMSPEC% /C rwinsta " & sessionId & tmpHost, 0, False
End Sub 

Function ActiveSessions(Host)
 Dim tmpHost, aTmp, aTmp1(), i
 if trim(Host)="" Then
  tmpHost = ""
 Else
  tmpHost = " /SERVER:" & Host
 End If
 aTmp = Split(cmd("qwinsta" & tmpHost & " | find ""Active"""), _
  vbCrLf)
 ReDim aTmp1(-1)
 For i = 0 to UBound(aTmp)
  If Left(aTmp(i),1) <> ">" Then
   Redim Preserve aTmp1(UBound(aTmp1) + 1)
   aTmp1(UBound(aTmp1)) = Trim(Mid(aTmp(i), 42, 6))
  End If
 Next
 ActiveSessions = aTmp1
End Function


Function DisconnectedSessions(Host)
 Dim tmpHost, aTmp, aTmp1(), i
 if trim(Host)="" Then
  tmpHost = ""
 Else
  tmpHost = " /SERVER:" & Host
 End If
 aTmp = Split(cmd("qwinsta" & tmpHost & " | find ""Disconnected"""), _
  vbCrLf)
 ReDim aTmp1(-1)
 For i = 0 to UBound(aTmp)
  If Left(aTmp(i),1) <> ">" Then
   Redim Preserve aTmp1(UBound(aTmp1) + 1)
   aTmp1(UBound(aTmp1)) = Trim(Mid(aTmp(i), 42, 6))
  End If
 Next
 DisconnectedSessions = aTmp1
End Function


Function Cmd(cmdline)
 ' Wrapper for getting StdOut from a console command
 Dim Sh, FSO, fOut, OutF, sCmd
 Set Sh = createobject("WScript.Shell")
 Set FSO = createobject("Scripting.FileSystemObject")
 fOut = FSO.GetTempName
 sCmd = "%COMSPEC% /c " & cmdline & " >" & fOut
 Sh.Run sCmd, 0, True
 If FSO.FileExists(fOut) Then
  If FSO.GetFile(fOut).Size>0 Then
   Set OutF = FSO.OpenTextFile(fOut)
   Cmd = OutF.Readall
   OutF.Close
  End If
  FSO.DeleteFile(fOut)
 End If
End Function

TS Procedures Library

NOTE: For "bulk" changes on a LAN, the best approach in an XP environment is to use the Group Policy Settings available via GPEdit.msc.  Remote Desktop, Remote Assistance, and a host of other features are accessible there.  See Q306300 - How to Disable Remote Desktop by Using Group Policy for details.

Function ConsoleUser(sHost)
 ' Returns name of user logged on to console
 ' If no users are logged on, returns nothing
 Dim WMI, Processes, Process, sUser, sDomain
 Set WMI = GetObject("winmgmts://" & sHost)
 Set Processes = WMI.InstancesOf("Win32_Process")
 ConsoleUser = ""
 For Each Process In Processes
  If (Process.Caption = "explorer.exe") _
   And (Process.SessionID = 0 ) Then
   lRet = Process.GetOwner(sUser, sDomain)
   If (Err = 0) And (lRet = 0) Then
    ConsoleUser = sUser
   End If
  End If
 Next
End Function

Function LoggedOnUsers(sHost)
 ' Returns array containing all users logged in to
 ' interactive explorer-based sessions on sHost
 ' This WILL NOT WORK with applications as the shell!
 Dim WMI, Processes, Process, sUser, sDomain, aTmp()
 Set WMI = GetObject("winmgmts://" & sHost)
 Set Processes = WMI.InstancesOf("Win32_Process")
 ReDim aTmp(-1)
 For Each Process In Processes
  If (Process.Caption = "explorer.exe") Then
   lRet = Process.GetOwner(sUser, sDomain)
   If (Err = 0) And (lRet = 0) Then
    ReDim aTmp(UBound(aTmp)+1)
    aTmp(UBound(aTmp)) = sUser
   End If
  End If
 Next
 LoggedOnUsers = aTmp
End Function

Function IsTSSession
 ' Returns true if this is a non-console TS/RD session
 Dim Sh, x
 Set Sh = WScript.CreateObject("WScript.Shell")
 x =  LCase(Sh.ExpandEnvironmentStrings("%Clientname%"))
 If (x <> "") And (x <> "console") Then
  IsTSSession = True
 Else
  IsTSSession = False
 End If
End Function

Function IsTS
 ' Returns true if this system is a TS/RD host
 Dim Sh, x
 Set Sh = WScript.CreateObject("WScript.Shell")
 x =  LCase(Sh.ExpandEnvironmentStrings("%Clientname%"))
 If (x <> "") Then
  IsTS = True
 Else
  IsTS = False
 End If
End Function

Sub LogoffDisconnectedSessions
 ' Logs off disconnected sessions on a terminal server
 ' DEPENDENCIES: Cmd function
 sData = Cmd("query session")
 Lines = Split(sData, vbCrLf)
 For Each Line In Lines
  'WScript.Echo InStr(Line,"Disc "), vbCrLf, Line
  If CBool(InStr(Line,"Disc ")) Then
   SessionId = Trim(Mid(Line,42,6))
   CreateObject("WScript.Shell").Run "logoff " & SessionId
  End If
 Next
End Sub

Function RAssistEnabled
 ' True if Remote Assistance enabled
 Dim Sh, sKey, sValueName, sValue
 Set Sh = CreateObject("WScript.Shell")
 sKey = "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\"
 sValueName = "fAllowToGetHelp"
 sValue = Sh.RegRead(sKey & sValueName)
 RAssistEnabled = CBool(sValue)
End Function 

Function RDeskEnabled
 ' True if Remote Desktop enabled
 Dim Sh, sKey, sValueName, sValue
 Set Sh = CreateObject("WScript.Shell")
 sKey = "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\"
 sValueName = "fDenyTSConnections"
 sValue = Sh.RegRead(SKey & sValueName)
 RDeskEnabled = CBool(sValue)
End Function 


Function RDeskAdvertised
 ' True if Remote Desktop is "advertising"
 Dim Sh, sKey, sValueName, sValue
 Set Sh = CreateObject("WScript.Shell")
 sKey = "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\"
 sValueName = "TSAdvertise"
 sValue = Sh.RegRead(SKey & sValueName)
 RdAdvertisedStatus = CBool(sValue)
End Function

Function RdpPort
 ' Returns current RDP port
 Dim Sh, sKey, sValueName, sValue
 Set Sh = CreateObject("WScript.Shell")
 sKey = "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\" _
 & "WinStations\RDP-Tcp\"
 sValueName = "PortNumber"
 sValue = Sh.RegRead(SKey & sValueName)
 RdpPort = sValue
End Function

Function Set_RdAdvertised(bStatus)
 ' Sets Remote Desktop advertising
 ' Returns a value of TRUE if status changed successfully
 Dim Sh, sKey, sValueName, sValue
 Set Sh = CreateObject("WScript.Shell")
 sKey = "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\"
 sValueName = "TSAdvertise"
 Set_RdAdvertisedStatus = FALSE
 On Error Resume Next
 Sh.RegWrite SKey & sValueName, Abs(bStatus)
 If Err.Number = 0 Then Set_RdAdvertisedStatus = TRUE
 On Error Goto 0
End Function

Function Cmd(cmdline)
 ' Wrapper for getting StdOut from a console command
 Dim Sh, FSO, fOut, OutF, sCmd
 Set Sh = createobject("WScript.Shell")
 Set FSO = createobject("Scripting.FileSystemObject")
 fOut = FSO.GetTempName
 sCmd = "%COMSPEC% /c " & cmdline & " >" & fOut
 Sh.Run sCmd, 0, True
 If FSO.FileExists(fOut) Then
  If FSO.GetFile(fOut).Size>0 Then
   Set OutF = FSO.OpenTextFile(fOut)
   Cmd = OutF.Readall
   OutF.Close
  End If
  FSO.DeleteFile(fOut)
 End If
End Function