Get a unique computer ID in Python on windows and linux

岁酱吖の 提交于 2019-12-27 21:05:04

问题


I'd like to get an id unique to a computer with Python on Windows and Linux. It could be the CPU ID, the motherboard serial, ... or anything else.

I looked at several modules (pycpuid, psi, ...) without luck.

Any idea on how to do that?


回答1:


How about using the MAC address as unique id?

The discussion here Obtain MAC Address from Devices using Python shows how to obtain the MAC address




回答2:


There seems to be no direct "python" way of doing this. On modern PC hardware, there usually is an UUID stored in the BIOS - on Linux there is a command line utility dmidecode that can read this; example from my desktop:

System Information
        Manufacturer: Dell Inc.
        Product Name: OptiPlex 755                 
        Version: Not Specified
        Serial Number: 5Y8YF3J
        UUID: 44454C4C-5900-1038-8059-B5C04F46334A
        Wake-up Type: Power Switch
        SKU Number: Not Specified
        Family: Not Specified

The problem with MAC addresses is that usually you can easily change them programmatically (at least if you run the OS in a VM)

On Windows, you can use this C API




回答3:


for Windows you need DmiDecode for Windows (link) :

subprocess.Popen('dmidecode.exe -s system-uuid'.split())

for Linux (non root):

subprocess.Popen('hal-get-property --udi /org/freedesktop/Hal/devices/computer --key system.hardware.uuid'.split())



回答4:


For python3.6 and windows must be used decode

>>> import subprocess
... current_machine_id = subprocess.check_output('wmic csproduct get uuid').decode().split('\n')[1].strip()
... print(current_machine_id)



回答5:


Or if you don't want to use subprocess, (It's slow) use ctypes. This is for Linux non root.

import ctypes
from ctypes.util import find_library
from ctypes import Structure

class DBusError(Structure):
    _fields_ = [("name", ctypes.c_char_p),
                ("message", ctypes.c_char_p),
                ("dummy1", ctypes.c_int),
                ("dummy2", ctypes.c_int),
                ("dummy3", ctypes.c_int),
                ("dummy4", ctypes.c_int),
                ("dummy5", ctypes.c_int),
                ("padding1", ctypes.c_void_p),]


class HardwareUuid(object):

    def __init__(self, dbus_error=DBusError):
        self._hal = ctypes.cdll.LoadLibrary(find_library('hal'))
        self._ctx = self._hal.libhal_ctx_new()
        self._dbus_error = dbus_error()
        self._hal.dbus_error_init(ctypes.byref(self._dbus_error))
        self._conn = self._hal.dbus_bus_get(ctypes.c_int(1),
                                            ctypes.byref(self._dbus_error))
        self._hal.libhal_ctx_set_dbus_connection(self._ctx, self._conn)
        self._uuid_ = None

    def __call__(self):
        return self._uuid

    @property
    def _uuid(self):
        if not self._uuid_:
            udi = ctypes.c_char_p("/org/freedesktop/Hal/devices/computer")
            key = ctypes.c_char_p("system.hardware.uuid")
            self._hal.libhal_device_get_property_string.restype = \
                                                            ctypes.c_char_p
            self._uuid_ = self._hal.libhal_device_get_property_string(
                                self._ctx, udi, key, self._dbus_error)
        return self._uuid_

You can use this like:

get_uuid = HardwareUuid()
print get_uuid()



回答6:


Funny! But uuid.getnode return the same value as dmidecode.exe.

subprocess.Popen('dmidecode.exe -s system-uuid'.split())

00000000-0000-0000-0000-001FD088565A

import uuid    
uuid.UUID(int=uuid.getnode())

UUID('00000000-0000-0000-0000-001fd088565a')



回答7:


I don't think there is a reliable, cross platform, way to do this. I know of one network device that changes its MAC address as a form of hardware error reporting, and there are a million other ways this could fail.

The only reliable solution is for your application to assign a unique key to each machine. Yes it can be spoofed, but you don't have to worry about it completely breaking. If you are worried about spoofing you can apply some sort of heuristic (like a change in mac address) to try and determine if the key has been moved.

UPDATE: You can use bacterial fingerprinting.




回答8:


Invoke one of these in the shell or through a pipe in Python to get the hardware serial number of Apple machines running OS X >= 10.5:

/usr/sbin/system_profiler SPHardwareDataType | fgrep 'Serial' | awk '{print $NF}'

or

ioreg -l | awk '/IOPlatformSerialNumber/ { print $4 }' | sed s/\"//g

BTW: MAC addresses are not a good idea: there can be >1 network cards in a machine, and MAC addresses can be spoofed.




回答9:


UUID -Universally Unique Identifier

Python uuid module

[RFC 4122] A Universally Unique IDentifier (UUID) URN Namespace




回答10:


This should work on windows:

import subprocess
current_machine_id = subprocess.check_output('wmic csproduct get uuid').split('\n')[1].strip()



回答11:


I found something else that I'm using. Mac address for linux, MachineGuid for windows and there is also something for mac.

More details here: http://www.serialsense.com/blog/2011/02/generating-unique-machine-ids/




回答12:


2019 Answer (for Windows):

from typing import Optional
import re
import subprocess
import uuid

def get_windows_uuid() -> Optional[uuid.UUID]:
    try:
        # Ask Windows for the device's permanent UUID. Throws if command missing/fails.
        txt = subprocess.check_output("wmic csproduct get uuid").decode()

        # Attempt to extract the UUID from the command's result.
        match = re.search(r"\bUUID\b[\s\r\n]+([^\s\r\n]+)", txt)
        if match is not None:
            txt = match.group(1)
            if txt is not None:
                # Remove the surrounding whitespace (newlines, space, etc)
                # and useless dashes etc, by only keeping hex (0-9 A-F) chars.
                txt = re.sub(r"[^0-9A-Fa-f]+", "", txt)

                # Ensure we have exactly 32 characters (16 bytes).
                if len(txt) == 32:
                    return uuid.UUID(txt)
    except:
        pass # Silence subprocess exception.

    return None

print(get_windows_uuid())

Uses Windows API to get the computer's permanent UUID, then processes the string to ensure it's a valid UUID, and lastly returns a Python object (https://docs.python.org/3/library/uuid.html) which gives you convenient ways to use the data (such as 128-bit integer, hex string, etc).

Good luck!

PS: The subprocess call could probably be replaced with ctypes directly calling Windows kernel/DLLs for the Win32_ComputerSystemProduct API (which is what wmic uses internally). But then you have to be very careful and ensure that you call it properly on all systems. For my purposes this wmic-based function is safer and is all I need. It does strong validation and produces correct results. And if the wmic output is wrong or if the command is missing, our function returns None to let you handle that any way you want (such as generating a random UUID and saving it in your app's config file instead).



来源:https://stackoverflow.com/questions/2461141/get-a-unique-computer-id-in-python-on-windows-and-linux

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!