Question: I posted this question, asking how to get the CPU and GPU temp on Windows 10: Get CPU and GPU Temp using Python Windows. For that question, I didn't include the restriction (at least when I first posted the answer, and for quite a bit after that) for no admin access. I then modified my question to invalidate answers that need admin access (which the only working answer then). A mod rolled back to a previous version of my question, and asked me to post a new question, so I have done that. I was wondering if there was a way to get the CPU and the GPU temperature in python. I have already found a way for Linux (using psutil.sensors_temperature), and I wanted to find a way for Windows. Info:  OS: Windows 10  Python: Python 3.8.3 64-bit (So no 32 bit DLLs) Below are some of the stuff I tried: When I try doing the below, I get None (from here - https://stackoverflow.com/a/3264262/13710015): import wmi w = wmi.WMI() prin(w.Win32_TemperatureProbe()[0].CurrentReading)  When I try doing the below, I get an error (from here - https://stackoverflow.com/a/3264262/13710015): import wmi w = wmi.WMI(namespace="root\wmi") temperature_info = w.MSAcpi_ThermalZoneTemperature()[0] print(temperature_info.CurrentTemperature)  Error: wmi.x_wmi: <x_wmi: Unexpected COM Error (-2147217396, 'OLE error 0x8004100c', None, None)>  When I tried doing the below, I got (from here - https://stackoverflow.com/a/58924992/13710015): import ctypes import ctypes.wintypes as wintypes from ctypes import windll LPDWORD = ctypes.POINTER(wintypes.DWORD) LPOVERLAPPED = wintypes.LPVOID LPSECURITY_ATTRIBUTES = wintypes.LPVOID GENERIC_READ = 0x80000000 GENERIC_WRITE = 0x40000000 GENERIC_EXECUTE = 0x20000000 GENERIC_ALL = 0x10000000 FILE_SHARE_WRITE=0x00000004 ZERO=0x00000000 CREATE_NEW = 1 CREATE_ALWAYS = 2 OPEN_EXISTING = 3 OPEN_ALWAYS = 4 TRUNCATE_EXISTING = 5 FILE_ATTRIBUTE_NORMAL = 0x00000080 INVALID_HANDLE_VALUE = -1 FILE_DEVICE_UNKNOWN=0x00000022 METHOD_BUFFERED=0 FUNC=0x900 FILE_WRITE_ACCESS=0x002 NULL = 0 FALSE = wintypes.BOOL(0) TRUE = wintypes.BOOL(1) def CTL_CODE(DeviceType, Function, Method, Access): return (DeviceType << 16) | (Access << 14) | (Function <<2) | Method def _CreateFile(filename, access, mode, creation, flags): """See: CreateFile function http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).asp """ CreateFile_Fn = windll.kernel32.CreateFileW CreateFile_Fn.argtypes = [ wintypes.LPWSTR, # _In_ LPCTSTR lpFileName wintypes.DWORD, # _In_ DWORD dwDesiredAccess wintypes.DWORD, # _In_ DWORD dwShareMode LPSECURITY_ATTRIBUTES, # _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes wintypes.DWORD, # _In_ DWORD dwCreationDisposition wintypes.DWORD, # _In_ DWORD dwFlagsAndAttributes wintypes.HANDLE] # _In_opt_ HANDLE hTemplateFile CreateFile_Fn.restype = wintypes.HANDLE return wintypes.HANDLE(CreateFile_Fn(filename, access, mode, NULL, creation, flags, NULL)) handle=_CreateFile('\\\\\.\PhysicalDrive0',GENERIC_WRITE,FILE_SHARE_WRITE,OPEN_EXISTING,ZERO) def _DeviceIoControl(devhandle, ioctl, inbuf, inbufsiz, outbuf, outbufsiz): """See: DeviceIoControl function http://msdn.microsoft.com/en-us/library/aa363216(v=vs.85).aspx """ DeviceIoControl_Fn = windll.kernel32.DeviceIoControl DeviceIoControl_Fn.argtypes = [ wintypes.HANDLE, # _In_ HANDLE hDevice wintypes.DWORD, # _In_ DWORD dwIoControlCode wintypes.LPVOID, # _In_opt_ LPVOID lpInBuffer wintypes.DWORD, # _In_ DWORD nInBufferSize wintypes.LPVOID, # _Out_opt_ LPVOID lpOutBuffer wintypes.DWORD, # _In_ DWORD nOutBufferSize LPDWORD, # _Out_opt_ LPDWORD lpBytesReturned LPOVERLAPPED] # _Inout_opt_ LPOVERLAPPED lpOverlapped DeviceIoControl_Fn.restype = wintypes.BOOL # allocate a DWORD, and take its reference dwBytesReturned = wintypes.DWORD(0) lpBytesReturned = ctypes.byref(dwBytesReturned) status = DeviceIoControl_Fn(devhandle, ioctl, inbuf, inbufsiz, outbuf, outbufsiz, lpBytesReturned, NULL) return status, dwBytesReturned class OUTPUT_temp(ctypes.Structure): """See: http://msdn.microsoft.com/en-us/library/aa363972(v=vs.85).aspx""" _fields_ = [ ('Board Temp', wintypes.DWORD), ('CPU Temp', wintypes.DWORD), ('Board Temp2', wintypes.DWORD), ('temp4', wintypes.DWORD), ('temp5', wintypes.DWORD) ] class OUTPUT_volt(ctypes.Structure): """See: http://msdn.microsoft.com/en-us/library/aa363972(v=vs.85).aspx""" _fields_ = [ ('VCore', wintypes.DWORD), ('V(in2)', wintypes.DWORD), ('3.3V', wintypes.DWORD), ('5.0V', wintypes.DWORD), ('temp5', wintypes.DWORD) ] def get_temperature(): FUNC=0x900 outDict={} ioclt=CTL_CODE(FILE_DEVICE_UNKNOWN, FUNC, METHOD_BUFFERED, FILE_WRITE_ACCESS) handle=_CreateFile('\\\\\.\PhysicalDrive0',GENERIC_WRITE,FILE_SHARE_WRITE,OPEN_EXISTING,ZERO) win_list = OUTPUT_temp() p_win_list = ctypes.pointer(win_list) SIZE=ctypes.sizeof(OUTPUT_temp) status, output = _DeviceIoControl(handle, ioclt , NULL, ZERO, p_win_list, SIZE) for field, typ in win_list._fields_: #print ('%s=%d' % (field, getattr(disk_geometry, field))) outDict[field]=getattr(win_list,field) return outDict def get_voltages(): FUNC=0x901 outDict={} ioclt=CTL_CODE(FILE_DEVICE_UNKNOWN, FUNC, METHOD_BUFFERED, FILE_WRITE_ACCESS) handle=_CreateFile('\\\\\.\PhysicalDrive0',GENERIC_WRITE,FILE_SHARE_WRITE,OPEN_EXISTING,ZERO) win_list = OUTPUT_volt() p_win_list = ctypes.pointer(win_list) SIZE=ctypes.sizeof(OUTPUT_volt) status, output = _DeviceIoControl(handle, ioclt , NULL, ZERO, p_win_list, SIZE) for field, typ in win_list._fields_: #print ('%s=%d' % (field, getattr(disk_geometry, field))) outDict[field]=getattr(win_list,field) return outDict print(OUTPUT_temp._fields_)  Output: [('Board Temp', <class 'ctypes.c_ulong'>), ('CPU Temp', <class 'ctypes.c_ulong'>), ('Board Temp2', <class 'ctypes.c_ulong'>), ('temp4', <class 'ctypes.c_ulong'>), ('temp5', <class 'ctypes.c_ulong'>)]  I tried this code, and it worked, but it needs admin (from here - https://stackoverflow.com/a/62936850/13710015): import clr # the pythonnet module. clr.AddReference(r'YourdllPath') from OpenHardwareMonitor.Hardware import Computer c = Computer() c.CPUEnabled = True # get the Info about CPU c.GPUEnabled = True # get the Info about GPU c.Open() while True: for a in range(0, len(c.Hardware[0].Sensors)): # print(c.Hardware[0].Sensors[a].Identifier) if "/intelcpu/0/temperature" in str(c.Hardware[0].Sensors[a].Identifier): print(c.Hardware[0].Sensors[a].get_Value()) c.Hardware[0].Update()  I tried this code, but it also needed admin (from here - https://stackoverflow.com/a/49909330/13710015): import clr #package pythonnet, not clr openhardwaremonitor_hwtypes = ['Mainboard','SuperIO','CPU','RAM','GpuNvidia','GpuAti','TBalancer','Heatmaster','HDD'] cputhermometer_hwtypes = ['Mainboard','SuperIO','CPU','GpuNvidia','GpuAti','TBalancer','Heatmaster','HDD'] openhardwaremonitor_sensortypes = ['Voltage','Clock','Temperature','Load','Fan','Flow','Control','Level','Factor','Power','Data','SmallData'] cputhermometer_sensortypes = ['Voltage','Clock','Temperature','Load','Fan','Flow','Control','Level'] def initialize_openhardwaremonitor(): file = 'OpenHardwareMonitorLib.dll' clr.AddReference(file) from OpenHardwareMonitor import Hardware handle = Hardware.Computer() handle.MainboardEnabled = True handle.CPUEnabled = True handle.RAMEnabled = True handle.GPUEnabled = True handle.HDDEnabled = True handle.Open() return handle def initialize_cputhermometer(): file = 'CPUThermometerLib.dll' clr.AddReference(file) from CPUThermometer import Hardware handle = Hardware.Computer() handle.CPUEnabled = True handle.Open() return handle def fetch_stats(handle): for i in handle.Hardware: i.Update() for sensor in i.Sensors: parse_sensor(sensor) for j in i.SubHardware: j.Update() for subsensor in j.Sensors: parse_sensor(subsensor) def parse_sensor(sensor): if sensor.Value is not None: if type(sensor).__module__ == 'CPUThermometer.Hardware': sensortypes = cputhermometer_sensortypes hardwaretypes = cputhermometer_hwtypes elif type(sensor).__module__ == 'OpenHardwareMonitor.Hardware': sensortypes = openhardwaremonitor_sensortypes hardwaretypes = openhardwaremonitor_hwtypes else: return if sensor.SensorType == sensortypes.index('Temperature'): print(u"%s %s Temperature Sensor #%i %s - %s\u00B0C" % (hardwaretypes[sensor.Hardware.HardwareType], sensor.Hardware.Name, sensor.Index, sensor.Name, sensor.Value)) if __name__ == "__main__": print("OpenHardwareMonitor:") HardwareHandle = initialize_openhardwaremonitor() fetch_stats(HardwareHandle) print("\nCPUMonitor:") CPUHandle = initialize_cputhermometer() fetch_stats(CPUHandle)  I am also fine with using C/C++ extensions with Python, portable command-line apps (which will be run with subprocess.Popen), DLLs, and commands (which will be run with subprocess.Popen). Non-portable apps are not allowed.

Answer: Problem An unprivileged user needs access to functionality only available by a privileged user in a secure manner. Solution Create an server-client interface where functionality is decoupled from the actual system as to prevent security issues (ie: don't just pipe commands or options directly from client for execution by the server). Consider using gRPC for this server-client interface. If you haven't used gRPC before, here's an example of what this entails: Create a temperature.proto: syntax = "proto3"; option java_multiple_files = true; option java_package = "temperature"; option java_outer_classname = "TemperatureProto"; option objc_class_prefix = "TEMP"; package temperature; service SystemTemperature { rpc GetTemperature (TemperatureRequest) returns (TemperatureReply) {} } message TemperatureRequest { string name = 1; } message TemperatureReply { string message = 1; }  Compile the aforementioned with protoc from protobuf library. python -m grpc_tools.protoc --proto_path=. temperature.proto --python_out=. --grpc_python_out=.  This will generate a file named temperature_pb2_grpc.py, which is where you'll define functionality and response for GetTemperature, note, that you can implement logic branches contextual upon TemperatureRequest options passed from the client. Once complete simply write and run a temperature_server.py from your privileged user, and temperature_client.py from your unprivileged user. References gRPC: https://grpc.io gRPC QuickStart guide: https://grpc.io/docs/languages/ruby/quickstart/ protobuf: https://developers.google.com/protocol-buffers/