Seite 1 von 1
USB-Stick serialnumber and volume letter
Verfasst: Donnerstag 16. November 2023, 10:35
von Pythonboy
Hallo,
kennt ihr vielleicht eine Möglichkeit, oder eine Bibliothek, mit der es möglich ist die Seriennummer (bzw. die eindeutige ID) sowie den Laufwerksbuchstaben der eingebunden Sticks auszulesen?
Gewünscht wäre am Ende ine Auflistung wie folgt z.B.:
Code: Alles auswählen
("F:", "579EF173")
("G:", "878FH189")
("H:", "8G6T9AF8")
Re: USB-Stick serialnumber and volume letter
Verfasst: Donnerstag 16. November 2023, 11:29
von __deets__
Ich kenne keine Module dafuer, aber man findet zB
https://superuser.com/questions/498083/ ... mmand-line - damit wuerde ich mal rumspielen.
Re: USB-Stick serialnumber and volume letter
Verfasst: Donnerstag 16. November 2023, 12:17
von Sirius3
Re: USB-Stick serialnumber and volume letter
Verfasst: Donnerstag 16. November 2023, 13:41
von Pythonboy
Danke für die Hinweise, ich habe es jetzt wie folgt gelöst:
Code: Alles auswählen
from subprocess import Popen, PIPE
import re
VOLUME_LETTERS = ["A:","B:","C:","D:","E:","F:","G:","H:","I:","J:","K:","L:","M:","N:","O:","P:","Q:","R:","S:","T:","U:","V:","W:","X:","Y:","Z:"]
def get_volume_serial_number_and_letter():
volume_letter_to_serial_number = {}
for volume_letter in VOLUME_LETTERS:
process = Popen(['vol', volume_letter], stdout=PIPE, stderr=PIPE, shell=True)
stdout, stderr = process.communicate()
decoded_stdout = stdout.decode('windows-1252')
search_index_start = re.search("Volumeseriennummer: ", decoded_stdout)
try:
volume_letter_to_serial_number[volume_letter] = decoded_stdout[search_index_start.span()[1]:search_index_start.span()[1] + 9] #serial number is 9 chars long
except AttributeError:
volume_letter_to_serial_number[volume_letter] = None
return volume_letter_to_serial_number
print(get_volume_serial_number_and_letter())
Meine Idee ist es, dass man für gewisse Dinge auszuführen kein Passwort braucht, sondern bestimmte USB-Sticks in der richtigen Reihenfolge in ein USB-Hub stecken muss, um die Dinge freizuschalten.
Jetzt muss ich nur noch eine Funktion machen zum initialisieren, die mir die Laufwerksbuchstaben zusammen mit der gehashten Seriennummer in eine Datei auslagert und eine Funktion, die die aktuell ausgelesenen Werte mit dieser Datei abgleicht.
Re: USB-Stick serialnumber and volume letter
Verfasst: Donnerstag 16. November 2023, 14:15
von __deets__
Uh. Da wird mir mein Herz ganz schwer, wenn ich sehe, wie du hier die VOLUME_LETTERS hart hinschreibst.
Das erzeugt man programmatisch, zB so:
Code: Alles auswählen
for i in range(26):
volume = f"{chr(ord('A') + i)}:"
print(volume)
Re: USB-Stick serialnumber and volume letter
Verfasst: Donnerstag 16. November 2023, 14:34
von Pythonboy
So ähnlich habe ich mir die Liste generiert:
Code: Alles auswählen
import string
print([f"{char}:" for char in string.ascii_uppercase])
--> dann noch ' durch " ersetzt, weil ich dachte dass es so besser lesbar ist.
Auf den Ansatz mit ord und chr wäre ich jetzt nicht gekommen, danke!

Re: USB-Stick serialnumber and volume letter
Verfasst: Donnerstag 16. November 2023, 14:59
von __deets__
ascii_uppercase ist ja auch fein, wenn nicht sogar besser. Gibt halt viele Wege nach Rom, aber sowas wie aufzaehlen lassen sind Computer recht gut drin, da lasse ich den das machen

Re: USB-Stick serialnumber and volume letter
Verfasst: Donnerstag 16. November 2023, 15:49
von kbr
ascii_uppercase ist schon eine gute Idee, aber nicht zum Erzeugen einer anschließend hartkodierten Liste. Ich würde statt dessen einen Generator bauen:
Code: Alles auswählen
import string
def volumeletters():
for item in string.ascii_uppercase:
yield f"{item}:"
for volumeletter in volumeletters():
print(volumeletter)
Re: USB-Stick serialnumber and volume letter
Verfasst: Donnerstag 16. November 2023, 16:09
von Sirius3
Warum einfach, wenn's auch kompliziert geht

.
Ich hatte Dich ja schon auf das richtige Modul hingewiesen:
Code: Alles auswählen
import wmi
for device in wmi.WMI().Win32_LogicalDisk():
name = device.wmi_property('Name').value
serial_number = device.wmi_property('VolumeSerialNumber').value
print(name, serial_number)
Re: USB-Stick serialnumber and volume letter
Verfasst: Freitag 17. November 2023, 13:27
von Pythonboy
Hallo Siruis,
deine Version sieht wirklich etwas lesbarer aus. Diese habe ich nun übernommen, mein aktueller Entwurf sieht so aus, damit bin ich aber noch nicht zufrieden.
Habt ihr Vorschläge wie ich es verbessern könnte?
Code: Alles auswählen
import wmi
import argon2
def get_volume_serial_number_and_letter_wmi():
volume_letter_to_serial_number = dict()
for volume in wmi.WMI().Win32_LogicalDisk():
name = volume.wmi_property('Name').value
serial_number = volume.wmi_property('VolumeSerialNumber').value
volume_letter_to_serial_number[name] = serial_number
return volume_letter_to_serial_number
def get_difference_of_dicts(dict1, dict2):
difference = {}
for key in dict1.keys():
if key not in dict2.keys():
difference[key] = dict1[key]
return difference
def main():
while True:
print("Was möchtest du tun?: ")
choice = int(input("1 - Einstellungen setzen \n2 - Einstellungen prüfen\n\n> "))
if choice == 1:
input("Entferne alle USB-Sticks aus dem USB-Hub. Drücke [Enter], sobald alle USB-Sticks entfernt sind\n")
volume_letters_and_serial_without_usb_sticks = get_volume_serial_number_and_letter_wmi()
input("Stecke nun die USB-Sticks in der gewünschten Reihenfolge in den USB-Hub und drücke anschließend [Enter]\n")
volume_letters_and_serial_with_usb_sticks = get_volume_serial_number_and_letter_wmi()
difference = get_difference_of_dicts(volume_letters_and_serial_with_usb_sticks, volume_letters_and_serial_without_usb_sticks)
for key, value in difference.items():
difference[key] = argon2.PasswordHasher().hash(value)
print(difference)
if choice == 2:
volume_letters_and_serial_with_usb_sticks = get_volume_serial_number_and_letter_wmi()
difference2 = get_difference_of_dicts(volume_letters_and_serial_with_usb_sticks, volume_letters_and_serial_without_usb_sticks)
if difference2:
for key, value in difference2.items():
if key in difference.keys():
if argon2.PasswordHasher().verify(difference[key],difference2[key]):
print("YES")
else:
print("NO")
else:
print("NO")
else:
print("NO")
main()
Re: USB-Stick serialnumber and volume letter
Verfasst: Freitag 17. November 2023, 13:54
von Sirius3
Was gefällt Dir daran nicht?
In `get_volume_serial_number_and_letter_wmi` ist die Einrückung falsch.
`get_difference_of_dicts` läßt sich deutlich eleganter schreiben:
Code: Alles auswählen
def get_difference_of_dicts(input, keys_to_be_removed):
return {key: input[key] for key in set(input) - set(keys_to_be_removed)}
Vor dem `main`-Aufruf sollte `if __name__ == "__main__":` stehen.
Im choice == 2-Zweig werden `difference` und `volume_letters_and_serial_without_usb_sticks` nicht gesetzt, was zu einem Fehler führen kann.
Wenn Dich nur die USB-Sticks interessieren, würde ich ja auf WMI-Property DeviceType == 2 prüfen, oder die Description auswerten. Ich denke, es ist ziemlich umständlich erst alle USB-Sticks zu ziehen, um sie danach wieder einzustecken.
Ist denn wichtig, ob das Laufwerk als Q: eingebunden wird oder als V:?
Und wenn Dich eh nur die USB-Devices interessieren, warum fragst Du dann nicht die USB-DeviceID ab, statt Dich hier mit einem VolumeSerialNumber herumzuschlagen?
Volume-IDs sind keine Passwörter, mit argon2 darauf loszugehen ist vielleicht etwas übertrieben. Was soll das ganze Programm überhaupt tun?
Re: USB-Stick serialnumber and volume letter
Verfasst: Freitag 17. November 2023, 14:12
von Pythonboy
Meine Grundidee ist es, bestimmte Funktionen nur freizuschalten, sofern die richtigen USB-Sticks in der richtigen Reihenfolge in das USB-Hub gesteckt werden.
Das mit dem deutlich eleganter habe ich versucht, bin aber leider kläglich gescheitert. Danke für das Snippet.
Die Seriennummer habe ich genommen, damit wirklich nur die USB-Sticks dafür genutzt werden können, die ich hier vor mir liegen habe und keine anderen. Ist die DeviceID auch immer gleich, oder ist die bei unterschiedlichen Systemen unterschiedlich?
Das mit dem USB-Sticks vorher entfernen und wieder reinstecken hat mich auch sehr beim Testen genervt, aber da ich verbundene Netzlaufwerke habe, dachte ich das wäre Notwendig damit wirklich nur die USB-Sticks beachtet werden. Das mit der WMI-Property DeviceTyp == 2 habe ich noch nicht gewusst, danke auch von meinen USB-Sockets für diesen Vorschlag, weil ich diese nun nicht mehr so penetrieren muss.
Was wür ein Hashalgorhymus würdest du empfehlen?
Re: USB-Stick serialnumber and volume letter
Verfasst: Freitag 17. November 2023, 14:15
von __blackjack__
@Pythonboy: `pathlib` und `json` werden importiert, aber nirgends verwendet.
Man könnte verhindern das `main()` aufgerufen wird wenn man das als Modul importiert.
Die Benutzereingaben sollte man gegen Fehleingaben absichern.
Das Programm kommt auch nicht damit klar wenn der Benutzer zuerst 2 auswählt. Das darf er sinnvollerweise erst dann machen wenn mindestens einmal der erste Punkt gewählt wurde. Da es nur zwei Punkte gibt, braucht man dem Benutzer am Anfang gar keine Auswahl anbieten, sondern kann gleich die Einstellungen abfragen. Am besten steckt man die beiden Aktionen sowieso in eigene Funktionen, dann ist das auch kein Problem vor der Schleife einmal bedingungslos die Funktion für die Einstellungen aufzurufen.
Beim Überprüfen gibt es eine Schleife über `items()` aber `value` aus dieser Schleife wird dann gar nicht verwendet.
Man sollte nicht `key` und `value` als Namen verwenden, wenn man dafür einen passenderen hat, wie `letter` und `serial` beispielsweise.
`difference` und `difference2` sind auch keine guten Namen.
Zwischenstand (ungetestet):
Code: Alles auswählen
#!/usr/bin/env python3
import argon2
import wmi
def get_property(volume, name):
return volume.wmi_property(name).value
def get_volume_serial_numbers():
return dict(
(
get_property(volume, "Name"),
get_property(volume, "VolumeSerialNumber"),
)
for volume in wmi.WMI().Win32_LogicalDisk()
)
def subtract_mappings(mapping_a, mapping_b):
return {key: mapping_a[key] for key in mapping_a.keys() - mapping_b.keys()}
def configure():
input(
"Entferne alle USB-Sticks aus dem USB-Hub. Drücke [Enter], sobald"
" alle USB-Sticks entfernt sind\n"
)
volume_letters_and_serial_without_usb_sticks = get_volume_serial_numbers()
input(
"Stecke nun die USB-Sticks in der gewünschten Reihenfolge in den"
" USB-Hub und drücke anschließend [Enter]\n"
)
volume_letters_and_serial_with_usb_sticks = get_volume_serial_numbers()
difference = {
letter: argon2.PasswordHasher().hash(serial)
for letter, serial in subtract_mappings(
volume_letters_and_serial_with_usb_sticks,
volume_letters_and_serial_without_usb_sticks,
).items()
}
print(difference)
return volume_letters_and_serial_without_usb_sticks, difference
def verify(volume_letters_and_serial_without_usb_sticks, difference):
volume_letters_and_serial_with_usb_sticks = get_volume_serial_numbers()
difference2 = subtract_mappings(
volume_letters_and_serial_with_usb_sticks,
volume_letters_and_serial_without_usb_sticks,
)
if difference2:
for letter, serial in difference2.items():
if letter in difference:
if argon2.PasswordHasher().verify(difference[letter], serial):
print("YES")
else:
print("NO")
else:
print("NO")
else:
print("NO")
def main():
volume_letters_and_serial_without_usb_sticks, difference = configure()
while True:
print("Was möchtest du tun?")
while True:
try:
choice = int(
input(
"1 - Einstellungen setzen\n"
"2 - Einstellungen prüfen\n\n> "
)
)
break
except ValueError:
print("Fehler: Bitte eine ganze Zahl eingeben!")
if choice == 1:
(
volume_letters_and_serial_without_usb_sticks,
difference,
) = configure()
elif choice == 2:
verify(volume_letters_and_serial_without_usb_sticks, difference)
else:
print("Fehler: Ungültige Auswahl!")
if __name__ == "__main__":
main()
Re: USB-Stick serialnumber and volume letter
Verfasst: Freitag 17. November 2023, 14:23
von Pythonboy
Danke __blackjack__ für die ganzen Verbesserungen, bzgl. "`pathlib` und `json` werden importiert, aber nirgends verwendet." ist mir im letzten Moment noch selber aufgefallen, daher habe ich es noch hier nachträglich bearbeitet (nicht dass sich jemand wundert dass es in meinem obigem Code nicht vorkommt), da hattest du aber wahrscheinlich schon auf Antworten geklickt (Man, seid ihr schnell!)
Re: USB-Stick serialnumber and volume letter
Verfasst: Montag 20. November 2023, 14:22
von Pythonboy
Hallo,
ich habe versucht die Verbesserungen umzusetzen, jetzt bin ich hier gelandet:
Code: Alles auswählen
import wmi
import argon2
import json
import pathlib
CONFIGURATION_FILE = pathlib.Path("TEST.txt")
def get_property(volume, name):
return volume.wmi_property(name).value
def get_usb_serial_and_drive_letter():
return dict((get_property(volume, "Name"),get_property(volume, "VolumeSerialNumber")) for volume in wmi.WMI().Win32_LogicalDisk() if volume.DriveType == 2)
def write_to_config_file(configuration):
with open (CONFIGURATION_FILE, 'w', encoding='UTF-8') as output_file:
output_file.write(json.dumps(configuration))
def read_config_file():
if CONFIGURATION_FILE.exists():
with open (CONFIGURATION_FILE, 'r', encoding='UTF-8') as input_file:
return json.loads(input_file.read())
else:
return
def verify_config(saved_config, current_connected_usb_volumes):
try:
results = [argon2.PasswordHasher().verify(saved_config[letter], current_connected_usb_volumes[letter]) for letter in saved_config.keys()]
except:
return False
if results:
return all(results)
else:
return False
def main():
while True:
print("Was möchtest du tun?")
while True:
try:
choice = int(input("1 - Einstellungen setzen\n2 - Einstellungen prüfen\n\n> "))
break
except ValueError:
print("Fehler: Bitte eine ganze Zahl eingeben!")
if choice == 1:
hashed_current_connected_usb_volumes = {letter: argon2.PasswordHasher().hash(serial) for letter, serial in get_usb_serial_and_drive_letter().items()}
if hashed_current_connected_usb_volumes:
write_to_config_file(hashed_current_connected_usb_volumes)
else:
print("Keine USB-Stick gefunden. Vergewissere dich, dass USB-Sticks eingesteckt sind und versuche es erneut.")
if choice == 2:
saved_config = read_config_file()
if saved_config:
current_connected_usb_volumes = get_usb_serial_and_drive_letter()
is_verified = verify_config(saved_config, current_connected_usb_volumes)
if is_verified:
print("Die USB-Sticks sind in der richtigen Reihenfolge eingesteckt")
else:
print("Die USB-Sticks sind nicht in der richtigen Reihenfolge eingesteckt")
else:
print("Es wurde keine Konfigurationsdatei gefunden.")
if __name__ == "__main__":
main()
#edit: Fehler in Zeile 28 korrigiert von
Code: Alles auswählen
results = [argon2.PasswordHasher().verify(saved_config[letter], current_connected_usb_volumes[letter]) for letter in current_connected_usb_volumes.keys()]
zu
Code: Alles auswählen
results = [argon2.PasswordHasher().verify(saved_config[letter], current_connected_usb_volumes[letter]) for letter in saved_config.keys()]
Re: USB-Stick serialnumber and volume letter
Verfasst: Montag 20. November 2023, 15:09
von Sirius3
Statt des dict-Aufrufs würde man heutzutage Dict-Comprehension verwenden:
Code: Alles auswählen
def get_usb_serial_and_drive_letter():
return {
get_property(volume, "Name"): get_property(volume, "VolumeSerialNumber")
for volume in wmi.WMI().Win32_LogicalDisk()
if volume.DriveType == 2
}
Man darf gerne ein paar Zeilenumbrüche einfügen, um die Lesbarkeit zu erhöhen.
Dass `read_config_file` mal explizit ein Wörterbuch und mal implizit None zurückgibt, sollte nicht sein. Wenn keine Datei gefunden wird, dann ist das ein Fall für eine Exception.
Es darf keine nackten excepts geben, wie in `verify_config`. Was für Fehler können wirklich auftreten?
Re: USB-Stick serialnumber and volume letter
Verfasst: Montag 20. November 2023, 19:11
von __blackjack__
@Sirius: Den `dict()`-Aufruf hatte ich weil das hier blöd aussieht:
Code: Alles auswählen
def get_usb_serial_and_drive_letter():
return {
get_property(volume, "Name"): get_property(
volume, "VolumeSerialNumber"
)
for volume in wmi.WMI().Win32_LogicalDisk()
if volume.DriveType == 2
}
Hat halt Vor- und Nachteile wenn man ein Werkzeug zum formatieren verwendet das so gut wie keine Einstellungen hat.

Re: USB-Stick serialnumber and volume letter
Verfasst: Dienstag 21. November 2023, 09:44
von Pythonboy
@Sirius: Ich habe die Funktion read_config_file() jetzt geändert, sodass immer ein dict zurück gegeben wird und bei verify_config() wird jetzt die genaue Exception abgefangen:
Code: Alles auswählen
import wmi
import argon2
import json
CONFIGURATION_FILE = "TEST.txt"
def get_property(volume, name):
return volume.wmi_property(name).value
def get_usb_serial_and_drive_letter():
return {get_property(volume, "Name") : get_property(volume, "VolumeSerialNumber") for volume in wmi.WMI().Win32_LogicalDisk() if volume.DriveType == 2}
def write_to_config_file(configuration):
with open (CONFIGURATION_FILE, 'w', encoding='UTF-8') as output_file:
output_file.write(json.dumps(configuration))
def read_config_file():
try:
with open (CONFIGURATION_FILE, 'r', encoding='UTF-8') as input_file:
return json.loads(input_file.read())
except FileNotFoundError:
return {}
except json.JSONDecodeError:
return {}
def verify_config(saved_config, current_connected_usb_volumes):
try:
results = [argon2.PasswordHasher().verify(saved_config[letter], current_connected_usb_volumes[letter]) for letter in saved_config.keys()]
if results:
return all(results)
else:
return False
except argon2.exceptions.VerifyMismatchError:
return False
except argon2.exceptions.VerificationError:
return False
def main():
while True:
while True:
print("Was möchtest du tun?")
try:
choice = int(input("1 - Einstellungen setzen\n2 - Einstellungen prüfen\n\n> "))
break
except ValueError:
print("Fehler: Bitte eine ganze Zahl eingeben!\n")
if choice == 1:
hashed_current_connected_usb_volumes = {letter : argon2.PasswordHasher().hash(serial) for letter, serial in get_usb_serial_and_drive_letter().items()}
if hashed_current_connected_usb_volumes:
write_to_config_file(hashed_current_connected_usb_volumes)
else:
print("Keine USB-Stick gefunden. Vergewissere dich, dass USB-Sticks eingesteckt sind und versuche es erneut.\n")
if choice == 2:
saved_config = read_config_file()
if saved_config:
current_connected_usb_volumes = get_usb_serial_and_drive_letter()
is_verified = verify_config(saved_config, current_connected_usb_volumes)
if is_verified:
print("Verifikation erfolgreich.\n")
else:
print("Verifikation fehlgeschlagen\n")
else:
print("Es wurde keine Konfigurationsdatei gefunden, oder die Konfigurationsdatei ist fehlerhaft.\n")
if __name__ == "__main__":
main()