<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:"Segoe UI Emoji";
        panose-1:2 11 5 2 4 2 4 2 2 3;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
span.EmailStyle20
        {mso-style-type:personal-reply;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="blue" vlink="purple" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal">Ok..  fine…  I was interested so I played with it more.  Here’s what I came up with.  Enjoy!<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">import win32ts<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">protocols = {<o:p></o:p></p>
<p class="MsoNormal">    win32ts.WTS_PROTOCOL_TYPE_CONSOLE: "Console",<o:p></o:p></p>
<p class="MsoNormal">    win32ts.WTS_PROTOCOL_TYPE_ICA: "Citrix",<o:p></o:p></p>
<p class="MsoNormal">    win32ts.WTS_PROTOCOL_TYPE_RDP: "RDP",<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">session_types = {win32ts.WTSConnected: "Connected",<o:p></o:p></p>
<p class="MsoNormal">                 win32ts.WTSActive: "Active",<o:p></o:p></p>
<p class="MsoNormal">                 win32ts.WTSConnectQuery: "Connect Pending",<o:p></o:p></p>
<p class="MsoNormal">                 win32ts.WTSShadow: "Shadowing another session",<o:p></o:p></p>
<p class="MsoNormal">                 win32ts.WTSDisconnected: "Disconnected",<o:p></o:p></p>
<p class="MsoNormal">                 win32ts.WTSIdle: "Idle",<o:p></o:p></p>
<p class="MsoNormal">                 win32ts.WTSListen: "Listening",<o:p></o:p></p>
<p class="MsoNormal">                 win32ts.WTSReset: " Resetting",<o:p></o:p></p>
<p class="MsoNormal">                 win32ts.WTSDown: "Down -- Error",<o:p></o:p></p>
<p class="MsoNormal">                 win32ts.WTSInit: "Initializing"}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">server_name = "someserver.mydomain.com"<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">ts_connection = win32ts.WTSOpenServer(server_name)<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">for s in win32ts.WTSEnumerateSessions(ts_connection, 1):<br>
    if s['WinStationName'] != "Services" and s['State'] != win32ts.WTSListen:<o:p></o:p></p>
<p class="MsoNormal">        user = win32ts.WTSQuerySessionInformation(ts_connection, s['SessionId'], win32ts.WTSUserName)<o:p></o:p></p>
<p class="MsoNormal">        if not user:<o:p></o:p></p>
<p class="MsoNormal">            user = "No one is logged in"<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">        protocol = win32ts.WTSQuerySessionInformation(ts_connection, s['SessionId'], win32ts.WTSClientProtocolType)<o:p></o:p></p>
<p class="MsoNormal">        print(f"Session: {s['SessionId']} - State = {session_types[s['State']]} --> User: {user} -- Protocol: {protocols[protocol]}")<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">win32ts.WTSCloseServer(ts_connection)<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">output:<br>
<br>
Session: 1 - State = Active --> User: myusername -- Protocol: RDP<o:p></o:p></p>
<p class="MsoNormal">Session: 2 - State = Connected --> User: No one is logged in -- Protocol: Console<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">HTH<br>
<br>
Steven<o:p></o:p></p>
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b>From:</b> python-win32 <python-win32-bounces+steven=manross.net@python.org>
<b>On Behalf Of </b>Steven Manross<br>
<b>Sent:</b> Sunday, March 13, 2022 8:26 AM<br>
<b>To:</b> Craig R. Matthews <cmatthew@optonline.net>; python-win32@python.org<br>
<b>Subject:</b> Re: [python-win32] pywin32 question<o:p></o:p></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">While I don’t have a huge environment to test in, this seems to work remotely from my win 10 pc to my Windows Server 2016 which has remote admin RDP enabled…  I would assume it’s the same APIs to talk to a full fledged WTS Server.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Kudos to the internet for having the answer already written down for me…  even if it was in python 2 syntax (what else should I expect from a post in 11/2007?). 
<span style="font-family:"Segoe UI Emoji",sans-serif">😊</span><o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><a href="https://mail.python.org/pipermail/python-win32/2007-November/006425.html">https://mail.python.org/pipermail/python-win32/2007-November/006425.html</a><o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New";color:black">import win32ts<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New";color:black"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New";color:black">for s in win32ts.WTSEnumerateSessions(win32ts.WTSOpenServer("MYSERVER.MYDOMAIN.COM"),1):<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New";color:black">    if s['State'] == win32ts.WTSActive:<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Courier New";color:black">        print(f"Session is active: {s}")
<o:p></o:p></span></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">output:<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Session is active: {'SessionId': 1, 'WinStationName': 'RDP-Tcp#124', 'State': 0}<br>
<br>
take a look at win32ts here:<br>
<br>
<a href="http://timgolden.me.uk/pywin32-docs/win32ts.html">http://timgolden.me.uk/pywin32-docs/win32ts.html</a><o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I am guessing you would also want to use “WTSQuerySessionInformation” as well to get more detailed information about the session, but I will leave that to you to explore.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I just found this today, so I am no expert on use of this module but it looks GREAT and I will likely develop something with it myself eventually.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Steven<o:p></o:p></p>
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b>From:</b> python-win32 <<a href="mailto:python-win32-bounces+steven=manross.net@python.org">python-win32-bounces+steven=manross.net@python.org</a>>
<b>On Behalf Of </b>Craig R. Matthews<br>
<b>Sent:</b> Saturday, March 12, 2022 12:02 AM<br>
<b>To:</b> <a href="mailto:python-win32@python.org">python-win32@python.org</a><br>
<b>Subject:</b> [python-win32] pywin32 question<o:p></o:p></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-family:"Courier New"">I was wondering if there is a way in python to determine the idle time for a terminal server session as QUERY USER does.<br>
<br>
Also, is there a way to get that python code to run for a server other than the one running the code (as in QUERY USER /SERVER:name)?</span><o:p></o:p></p>
</div>
</body>
</html>