Re: [python-win32] Need a value from pywin32
We have a winner! Huge thanks from me even though I wasn’t the OP because I've wanted to know how to do this for a while and just started to get my feet wet in this arena!!! I now have a VERY GOOD EXAMPLE of how to start looking at doing a complex task like this with all the nested references. UGH! In [16]: get_idle_time(2) # session id = 2 Out[16]: 0.0156271 Please note that line wraps (and or a missing newline) in the previous email may cause copy/paste issues in Eryk's code around these lines: winsta.WinStationQueryInformationW.restype = wintypes.BOOLEAN # this needs to be a newline winsta.WinStationQueryInformationW.argtypes = ( wintypes.HANDLE, # ServerHandle wintypes.ULONG, # SessionId ctypes.c_long, # WinStationInformationClass wintypes.LPVOID, # pWinStationInformation wintypes.ULONG, # WinStationInformationLength wintypes.PULONG, # pReturnLength ) I HOPE THIS HELPS AND THANK YOU VERY MUCH! Steven -Original Message- From: Eryk Sun Sent: Wednesday, June 22, 2022 1:28 PM To: Steven Manross Cc: python-win32@python.org Subject: Re: [python-win32] Need a value from pywin32 On 6/21/22, Steven Manross wrote: > > class WinStationInformation(ctypes.Structure): > __fields__ = [ > ('ConnectState', ctypes.c_long), > ('WinStationName', ctypes.wintypes.WCHAR), > ('LogonId', ctypes.c_ulong), > ('ConnectTime', ctypes.wintypes.LARGE_INTEGER), > ('DisconnectTime', ctypes.wintypes.LARGE_INTEGER), > ('LastInputTime', ctypes.wintypes.LARGE_INTEGER), > ('LogonTime', ctypes.wintypes.LARGE_INTEGER), > ('Status', ctypes.c_int()), > ('Domain', ctypes.wintypes.WCHAR * (17 + 1)), > ('UserName', ctypes.wintypes.WCHAR * (20 + 1)), > ('CurrentTime', ctypes.wintypes.LARGE_INTEGER), > ] The above definition is incorrect for `WinStationName` and `Status`. Defining the PROTOCOLSTATUS type for `Status` is tedious. Note also that the ctypes attribute to set is `_fields_`, not `__fields__`, so the above struct is actually defined with no fields (i.e. zero size). Here's an example that defines a get_idle_time() function, based on the difference between the current time and the last input time in the session. import ctypes from ctypes import wintypes winsta = ctypes.WinDLL('winsta', use_last_error=True) WINSTATIONNAME_LENGTH = 32 DOMAIN_LENGTH = 17 USERNAME_LENGTH = 20 MAX_THINWIRECACHE = 4 SERVERNAME_CURRENT = None LOGONID_CURRENT = -1 # WINSTATIONINFOCLASS WinStationInformation = 8 # WINSTATIONSTATECLASS State_Active = 0 State_Connected = 1 State_ConnectQuery = 2 State_Shadow = 3 State_Disconnected = 4 State_Idle = 5 State_Listen = 6 State_Reset = 7 State_Down = 8 State_Init = 9 class TSHARE_COUNTERS(ctypes.Structure): __slots__ = () _fields_ = ( ('Reserved', wintypes.ULONG), ) class PROTOCOLCOUNTERS(ctypes.Structure): __slots__ = () class SPECIFIC(ctypes.Union): __slots__ = () _fields_ = ( ('TShareCounters', TSHARE_COUNTERS), ('Reserved', wintypes.ULONG * 100), ) _fields_ = ( ('WdBytes', wintypes.ULONG), ('WdFrames', wintypes.ULONG), ('WaitForOutBuf', wintypes.ULONG), ('Frames', wintypes.ULONG), ('Bytes', wintypes.ULONG), ('CompressedBytes', wintypes.ULONG), ('CompressFlushes', wintypes.ULONG), ('Errors', wintypes.ULONG), ('Timeouts', wintypes.ULONG), ('AsyncFramingError', wintypes.ULONG), ('AsyncOverrunError', wintypes.ULONG), ('AsyncOverflowError', wintypes.ULONG), ('AsyncParityError', wintypes.ULONG), ('TdErrors', wintypes.ULONG), ('ProtocolType', wintypes.USHORT), ('Length', wintypes.USHORT), ('Specific', SPECIFIC), ) class THINWIRECACHE (ctypes.Structure): __slots__ = () _fields_ = ( ('CacheReads', wintypes.ULONG), ('CacheHits', wintypes.ULONG), ) class RESERVED_CACHE(ctypes.Structure): __slots__ = () _fields_ = ( ('ThinWireCache[', THINWIRECACHE * MAX_THINWIRECACHE), ) class CACHE_STATISTICS(ctypes.Structure): __slots__ = () class SPECIFIC(ctypes.Union): __slots__ = () _fields_ = ( ('ReservedCacheStats', RESERVED_CACHE), ('TShareCacheStats', wintypes.ULONG), ('Reserved', wintypes.ULONG * 20), ) _fields_ = ( ('ProtocolType', wintypes.USHORT), ('Length', w
Re: [python-win32] Need a value from pywin32
On 6/21/22, Steven Manross wrote: > > class WinStationInformation(ctypes.Structure): > __fields__ = [ > ('ConnectState', ctypes.c_long), > ('WinStationName', ctypes.wintypes.WCHAR), > ('LogonId', ctypes.c_ulong), > ('ConnectTime', ctypes.wintypes.LARGE_INTEGER), > ('DisconnectTime', ctypes.wintypes.LARGE_INTEGER), > ('LastInputTime', ctypes.wintypes.LARGE_INTEGER), > ('LogonTime', ctypes.wintypes.LARGE_INTEGER), > ('Status', ctypes.c_int()), > ('Domain', ctypes.wintypes.WCHAR * (17 + 1)), > ('UserName', ctypes.wintypes.WCHAR * (20 + 1)), > ('CurrentTime', ctypes.wintypes.LARGE_INTEGER), > ] The above definition is incorrect for `WinStationName` and `Status`. Defining the PROTOCOLSTATUS type for `Status` is tedious. Note also that the ctypes attribute to set is `_fields_`, not `__fields__`, so the above struct is actually defined with no fields (i.e. zero size). Here's an example that defines a get_idle_time() function, based on the difference between the current time and the last input time in the session. import ctypes from ctypes import wintypes winsta = ctypes.WinDLL('winsta', use_last_error=True) WINSTATIONNAME_LENGTH = 32 DOMAIN_LENGTH = 17 USERNAME_LENGTH = 20 MAX_THINWIRECACHE = 4 SERVERNAME_CURRENT = None LOGONID_CURRENT = -1 # WINSTATIONINFOCLASS WinStationInformation = 8 # WINSTATIONSTATECLASS State_Active = 0 State_Connected = 1 State_ConnectQuery = 2 State_Shadow = 3 State_Disconnected = 4 State_Idle = 5 State_Listen = 6 State_Reset = 7 State_Down = 8 State_Init = 9 class TSHARE_COUNTERS(ctypes.Structure): __slots__ = () _fields_ = ( ('Reserved', wintypes.ULONG), ) class PROTOCOLCOUNTERS(ctypes.Structure): __slots__ = () class SPECIFIC(ctypes.Union): __slots__ = () _fields_ = ( ('TShareCounters', TSHARE_COUNTERS), ('Reserved', wintypes.ULONG * 100), ) _fields_ = ( ('WdBytes', wintypes.ULONG), ('WdFrames', wintypes.ULONG), ('WaitForOutBuf', wintypes.ULONG), ('Frames', wintypes.ULONG), ('Bytes', wintypes.ULONG), ('CompressedBytes', wintypes.ULONG), ('CompressFlushes', wintypes.ULONG), ('Errors', wintypes.ULONG), ('Timeouts', wintypes.ULONG), ('AsyncFramingError', wintypes.ULONG), ('AsyncOverrunError', wintypes.ULONG), ('AsyncOverflowError', wintypes.ULONG), ('AsyncParityError', wintypes.ULONG), ('TdErrors', wintypes.ULONG), ('ProtocolType', wintypes.USHORT), ('Length', wintypes.USHORT), ('Specific', SPECIFIC), ) class THINWIRECACHE (ctypes.Structure): __slots__ = () _fields_ = ( ('CacheReads', wintypes.ULONG), ('CacheHits', wintypes.ULONG), ) class RESERVED_CACHE(ctypes.Structure): __slots__ = () _fields_ = ( ('ThinWireCache[', THINWIRECACHE * MAX_THINWIRECACHE), ) class CACHE_STATISTICS(ctypes.Structure): __slots__ = () class SPECIFIC(ctypes.Union): __slots__ = () _fields_ = ( ('ReservedCacheStats', RESERVED_CACHE), ('TShareCacheStats', wintypes.ULONG), ('Reserved', wintypes.ULONG * 20), ) _fields_ = ( ('ProtocolType', wintypes.USHORT), ('Length', wintypes.USHORT), ('Specific', SPECIFIC), ) class PROTOCOLSTATUS(ctypes.Structure): __slots__ = () _fields_ = ( ('Output', PROTOCOLCOUNTERS), ('Input', PROTOCOLCOUNTERS), ('Cache', CACHE_STATISTICS), ('AsyncSignal', wintypes.ULONG), ('AsyncSignalMask', wintypes.ULONG), ) class WINSTATIONINFORMATION(ctypes.Structure): __slots__ = () _fields_ = ( ('ConnectState', ctypes.c_long), ('WinStationName', wintypes.WCHAR * (WINSTATIONNAME_LENGTH + 1)), ('LogonId', wintypes.ULONG), ('ConnectTime', wintypes.LARGE_INTEGER), ('DisconnectTime', wintypes.LARGE_INTEGER), ('LastInputTime', wintypes.LARGE_INTEGER), ('LogonTime', wintypes.LARGE_INTEGER), ('Status', PROTOCOLSTATUS), ('Domain', wintypes.WCHAR * (DOMAIN_LENGTH + 1)), ('UserName', wintypes.WCHAR * (USERNAME_LENGTH + 1)), ('CurrentTime', wintypes.LARGE_INTEGER) ) winsta.WinStationQueryInformationW.restype = wintypes.BOOLEAN winsta.WinStationQueryInformationW.argtypes = ( wintypes.HANDLE, # ServerHandle wintypes.ULONG, # SessionId ctypes.c_long, # WinStationInformationClass wintypes.LPVOID, # pWinStationInformation wintypes.ULONG, # WinStationInformationLength wintypes.PULONG, # pReturnLength ) def get_idle_time(session_id=LOGONID_CURRENT, server_handle=SERVERNAME_CURRENT): info = WINSTATIONINFORMATION() rlen = wintypes.ULONG() if not winsta.WinStationQueryInformationW( server_handle, session_id, WinStationInfo
Re: [python-win32] Need a value from pywin32
Thanks a lot for the help!!! This is no longer Excepting... But the Result is 0 and there doesn't seem to be any data in the Buf structure or indication that there were results in RtnLen... I get to debug this more.. YAY!!! Steven -Original Message- From: python-win32 On Behalf Of Tim Roberts Sent: Tuesday, June 21, 2022 10:04 PM To: python-win32@python.org Subject: Re: [python-win32] Need a value from pywin32 On 6/21/22 13:39, Steven Manross wrote: > I was intrigued by this and I would like to get it to work, but I cannot... > I know I'm doing something wrong, but don't know what. I will leave this for > the archives, and maybe it will help someone else some day. > ... > def get_wts_info(session_id): > ''' > Get WTS Info > ''' > # This only tries to work on the local server currently but I get > an access violation running the WinStationQueryInformationW line > > Buf = ctypes.POINTER(WinStationInformation)() > BufLen = 260 > > hWinSta = ctypes.windll.LoadLibrary("WINSTA.DLL") > if hWinSta: > winsta_handle = hWinSta._handle > print(f'winsta_handle = {winsta_handle}') > QueryInfoHandle = > ctypes.windll.kernel32.GetProcAddress(ctypes.c_ulonglong(winsta_handle > ), b"WinStationQueryInformationW") > > # This handle is 0... possibly because of the numeric > conversion from the winsta_handle to a ctypes.c_ulonglong ??? unsure No, 0 is the error return that means the name was not found. You shouldn't need to use LoadLibrary and GetProcAddress. ctypes does that for you automatically. winsta = ctypes.WinDLL('winsta.dll') winsta.WinStationQueryInformationW( 0, session_id, 8, ctypes.byref(Buf), BufLen, ctypes.byref(RtnLen)) If you have Visual Studio, you can try doing "link /dump /exports \windows\system32\winsta.dll" to make sure it has that entry point. -- Tim Roberts, t...@probo.com Providenza & Boekelheide, Inc. ___ python-win32 mailing list python-win32@python.org https://mail.python.org/mailman/listinfo/python-win32 ___ python-win32 mailing list python-win32@python.org https://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Need a value from pywin32
On 6/21/22 13:39, Steven Manross wrote: I was intrigued by this and I would like to get it to work, but I cannot... I know I'm doing something wrong, but don't know what. I will leave this for the archives, and maybe it will help someone else some day. ... def get_wts_info(session_id): ''' Get WTS Info ''' # This only tries to work on the local server currently but I get an access violation running the WinStationQueryInformationW line Buf = ctypes.POINTER(WinStationInformation)() BufLen = 260 hWinSta = ctypes.windll.LoadLibrary("WINSTA.DLL") if hWinSta: winsta_handle = hWinSta._handle print(f'winsta_handle = {winsta_handle}') QueryInfoHandle = ctypes.windll.kernel32.GetProcAddress(ctypes.c_ulonglong(winsta_handle), b"WinStationQueryInformationW") # This handle is 0... possibly because of the numeric conversion from the winsta_handle to a ctypes.c_ulonglong ??? unsure No, 0 is the error return that means the name was not found. You shouldn't need to use LoadLibrary and GetProcAddress. ctypes does that for you automatically. winsta = ctypes.WinDLL('winsta.dll') winsta.WinStationQueryInformationW( 0, session_id, 8, ctypes.byref(Buf), BufLen, ctypes.byref(RtnLen)) If you have Visual Studio, you can try doing "link /dump /exports \windows\system32\winsta.dll" to make sure it has that entry point. -- Tim Roberts, t...@probo.com Providenza & Boekelheide, Inc. ___ python-win32 mailing list python-win32@python.org https://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Need a value from pywin32
I was intrigued by this and I would like to get it to work, but I cannot... I know I'm doing something wrong, but don't know what. I will leave this for the archives, and maybe it will help someone else some day. My guess is that the issue is the conversion of the winsta_handle to a ctypes.c_ulonglong() is generating an invalid handle ID or the GetProcAddress isn't finding the correct info using that handle. I'm very new to C programming ''' Get Terminal Services Idle Time and other values from WINSTA.DLL for local server > THIS DOES NOT WORK! < > ONLY SENT AS STARTER CODE FOR SOMEONE TO FIGURE OUT WHAT I AM MISSING < Microsoft Info: https://docs.microsoft.com/en-us/previous-versions/aa383827(v=vs.85) Google Thread: https://groups.google.com/g/microsoft.public.win32.programmer.kernel/c/xt2G599tJuQ?hl=en&pli=1#91fc4e79a5d6c495 ''' import ctypes class WinStationInformation(ctypes.Structure): __fields__ = [ ('ConnectState', ctypes.c_long), ('WinStationName', ctypes.wintypes.WCHAR), ('LogonId', ctypes.c_ulong), ('ConnectTime', ctypes.wintypes.LARGE_INTEGER), ('DisconnectTime', ctypes.wintypes.LARGE_INTEGER), ('LastInputTime', ctypes.wintypes.LARGE_INTEGER), ('LogonTime', ctypes.wintypes.LARGE_INTEGER), ('Status', ctypes.c_int()), ('Domain', ctypes.wintypes.WCHAR * (17 + 1)), ('UserName', ctypes.wintypes.WCHAR * (20 + 1)), ('CurrentTime', ctypes.wintypes.LARGE_INTEGER), ] def get_wts_info(session_id): ''' Get WTS Info ''' # This only tries to work on the local server currently but I get an access violation running the WinStationQueryInformationW line Buf = ctypes.POINTER(WinStationInformation)() BufLen = 260 hWinSta = ctypes.windll.LoadLibrary("WINSTA.DLL") if hWinSta: winsta_handle = hWinSta._handle print(f'winsta_handle = {winsta_handle}') QueryInfoHandle = ctypes.windll.kernel32.GetProcAddress(ctypes.c_ulonglong(winsta_handle), b"WinStationQueryInformationW") # This handle is 0... possibly because of the numeric conversion from the winsta_handle to a ctypes.c_ulonglong ??? unsure # I had to convert it because the handle was generating an error as a regular value: # ArgumentError: argument 1: : int too long to convert # print(f'QueryInfoHandle = {QueryInfoHandle}') WinStationQueryInformationW = hWinSta._FuncPtr(QueryInfoHandle) RtnLen = ctypes.c_ulong() try: Result = WinStationQueryInformationW(0, session_id, 8, ctypes.byref(Buf), BufLen, ctypes.byref(RtnLen)) except Exception as e: print(f'Excepted running WinStationQueryInformationW: {e}') return False print(f'Result = {Result}') return True get_wts_info(11) # where 11 is a valid session id on the local RDP server as defined by: # Server Manager -> Remote Desktop Services -> Collections -> your Collection Name -> Connections #Right Click on the columns in Connections Tab and add "ID" to the list of columns My output: winsta_handle = 140703764119552 QueryInfoHandle = 0 Excepted running WinStationQueryInformationW: exception: access violation writing 0x HTH Steven -Original Message- From: python-win32 On Behalf Of Tim Roberts Sent: Monday, June 20, 2022 10:06 AM To: python-win32@python.org Subject: Re: [python-win32] Need a value from pywin32 Craig R. Matthews wrote: > > I have a need to determine the "IDLE TIME" as provided by the Windows > Query program. > > Sample output: > C:\>query user /server:CTX202201 > USERNAME SESSIONNAME ID STATE IDLE TIME LOGON > TIME > administrator rdp-tcp#67 2 Active 1:38 > 6/15/2022 10:48 AM > > I can't find the above "IDLE TIME" anywhere in pywin32 "Python for > Win32 Extensions". > > I need this time value, and would rather keep all the code in python > without having to resort to something like subprocess to encapsulate > the Windows Query program. This is part of Windows Terminal Services. The API to fetch the idle time is undocumented and unsupported, but you can find the information here: https://groups.google.com/g/microsoft.public.win32.programmer.kernel/c/xt2G599tJuQ?hl=en#91fc4e79a5d6c495 Because it is undocumented, it might be better to parse the output of "query user". -- Tim Roberts, t...@probo.com Providenza & Boekelheide, Inc. ___ python-win32 mailing list python-win32@python.org https://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Need a value from pywin32
Craig R. Matthews wrote: I have a need to determine the "IDLE TIME" as provided by the Windows Query program. Sample output: C:\>query user /server:CTX202201 USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME administrator rdp-tcp#67 2 Active 1:38 6/15/2022 10:48 AM I can't find the above "IDLE TIME" anywhere in pywin32 "Python for Win32 Extensions". I need this time value, and would rather keep all the code in python without having to resort to something like subprocess to encapsulate the Windows Query program. This is part of Windows Terminal Services. The API to fetch the idle time is undocumented and unsupported, but you can find the information here: https://groups.google.com/g/microsoft.public.win32.programmer.kernel/c/xt2G599tJuQ?hl=en#91fc4e79a5d6c495 Because it is undocumented, it might be better to parse the output of "query user". -- Tim Roberts, t...@probo.com Providenza & Boekelheide, Inc. smime.p7s Description: S/MIME Cryptographic Signature ___ python-win32 mailing list python-win32@python.org https://mail.python.org/mailman/listinfo/python-win32
[python-win32] Need a value from pywin32
I have a need to determine the "IDLE TIME" as provided by the Windows Query program. Sample output: C:\>query user /server:CTX202201 USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME administrator rdp-tcp#67 2 Active 1:38 6/15/2022 10:48 AM I can't find the above "IDLE TIME" anywhere in pywin32 "Python for Win32 Extensions". I need this time value, and would rather keep all the code in python without having to resort to something like subprocess to encapsulate the Windows Query program. Thank you. ___ python-win32 mailing list python-win32@python.org https://mail.python.org/mailman/listinfo/python-win32