Pythonで次のことを実現したい
- ハードウェアを一意に識別したい
- ハードウェアごとのIDを取得したい
完全に一意なUUIDを取得したいです。
それならライブラリなどでUUIDを生成すればという話ですが、
ここではハードウェア固有の物理的UUIDを取得したかったです。
その方法を色々模索してみました。
具体的方法とかコード例とかまとめます。
このページの目次
MACアドレスは固有だが変わるリスクがある
真っ先に思いつくのはMACアドレスです。
▼ MACアドレスとは何ぞやの解説
MACアドレス(Media Access Control address)は、ネットワークカード(パソコンやルータなどのネットワーク機器)に付いている番号です。全世界でMACアドレスが重複することはありません。(ただし、MACアドレスを変更するソフトウエアなどもあり、意図的に変更した場合は重複することがあります)パソコンの有線LANの他にも無線LANやスマートフォンにもMACアドレスが割り当てされています。
LANやインターネットでのイーサネット通信で利用されています。通信データのヘッダー部分に「送信先MACアドレス」と「送信元MACアドレス」を格納することで宛先や戻し先を確定しています。MACアドレスが無いと通信ができなくなります。
重複することがない一意のアドレスのこと
パソコン・ルーターに付属してる番号のことです。
これを使うのは1つの手なのですが…
上記説明を見ても分かるように欠点があります。
- ソフトウェア的に変更できてしまう
- 意図的に重複させることができる
- ハードウェアごとに真に一意ではない
だから一意なUUIDとしてMACアドレスは不向きです。
Macアドレスはpythonからも簡単に取得可能
Pythonからも簡単に取得できます。
▼ こんな数行のコードを書くだけ
1 2 3 4 |
from uuid import getnode as get_mac mac = get_mac() print("mac : ", hex(mac)) /// => mac : 0x1efd3ad5c7be |
例えば16進表記なら 2D-0E-4F-C6-B8-AD のような16桁のアドレスが返ってきます。ipconfigコマンドだと物理アドレスなどと呼ばれます。
簡単に取得できるけど、さっき書いたように重複しないことは保証されません。というかソフト的に書き換えもできてしまいます。
だからOS固有のIDを探すことにしました。
WindowsでのハードウェアUUIDはwmicから取得可能
まずはWindowsでのハードウェアUUIDについて
これにはwmicコマンドを使います。
▼ このようなコマンドで取得可能
1 2 3 4 |
> wmic csproduct get uuid UUID 12345678-9ABC-0000-0000-000000000000 |
上記の 12345678-9ABC-0000-0000-000000000000 がWindowsのハードウェアIDです。この8桁-4桁-4桁-4桁-12桁はまさしくUUID v4 の形式ですね。(参考記事 : 重複しないIDを生成するNG方法と正しい方法)
これがWin環境でのハードウェアUUIDの取得方法
wmicコマンドは非推奨になったらしい…
あとで分かったけどwmicコマンドは非推奨です。
代わりにpowershellからハードウエアID取得できる模様
▼ 詳しくはこちらの記事とか参照
だからpowershell経由で取得することにしました。
LinuxでのハードウェアUUIDはmachine-idから取得可能
次にLinuxでのハードウェアUUIDについて
ググってみると /etc/machine-id から取得可能です。
▼ このような情報が出てきた
On modern machines with systemd: machine id is created by systemd-machine-id-setup. The location of machine id is documented - in freedesktop machine-id and man machine-id and machine id has a more standardized format - see RFC4122. Just:
cat /etc/machine-id
引用元 : https://stackoverflow.com/questions/10152762/best-way-to-get-machine-id-on-linux#answer-63148464
上記コマンドでハードウェアUUIDが手に入ります。
Linuxが生成したUUID v4が返ってくる模様です。
Windows/LinuxでハードウェアUUID取得のコード例
それでは具体的な取得コードを紹介。
このようなモジュールを作ってみました。
▼ hardware-id.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import platform import subprocess from uuid import getnode as get_mac def hardware_id(): os_name = platform.system().lower() hardware_id = "" if os_name == "windows": rc_wmic = subprocess.call(["where", "wmic"]) rc_powershell = subprocess.call(["where", "powershell"]) if rc_wmic == 0: hardware_id = subprocess.check_output( 'wmic csproduct get uuid', encoding="utf8" ).split()[-1].strip() elif rc_powershell == 0: hardware_id = subprocess.check_output( "powershell -Command "+ "(Get-WmiObject -Class Win32_ComputerSystemProduct).UUID", encoding="utf8" ).split()[-1].strip() else: hardware_id = get_mac() elif os_name == "linux": hardware_id = subprocess.check_output( 'cat /etc/machine-id', encoding="utf8" ).split()[0].strip() else: hardware_id = get_mac() |
▼ このような場合分け
- Windowsの場合 : wmicコマンドからUUID取得
- Linuxの場合 : machine-idからUUID取得
- その他OSの場合 : MACアドレスがUUIDの代わり
色々突っこみどころがあるかもしれません。
結局OS(Win/Linux)が生成してるUUIDを取得してるだけなので、それなら「コード側でUUID生成すれば?」という感じも……
でもハードウェアが生成したUUID(=コード的に生成しなくても一意に識別できる)メリットがあるため、その点が利点だと考えます。