Re: [python-win32] Need a value from pywin32

2022-06-22 Thread Steven Manross
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', 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__ = ()
_field

Re: [python-win32] Need a value from pywin32

2022-06-22 Thread Eryk Sun
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, 

Re: [python-win32] Need a value from pywin32

2022-06-22 Thread Steven Manross
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

2022-06-21 Thread Tim Roberts

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

2022-06-21 Thread Steven Manross
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=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

2022-06-20 Thread Tim Roberts

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