• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

Статья Способы получения информации об ОС и железе с помощью Python. Часть 04: ОС Windows и сторонние модули

Что ж, если в трех предыдущих статьях (раз, два, три) мы узнавали информацию об операционной системе с помощью python и библиотек, которые не требуют установки, это: winreg – работа с реестром Windows; subprocess.check_out – запускали утилиту командной строки wmic и парсили ее вывод; wmi – работа с инструментарием управления Windows, то сегодня давайте попробуем использовать сторонние библиотеки для этих целей. Также, как и в предыдущих статьях сравним скорость работы. И, думаю, что подведем некий итог по сбору информации об операционной системе и железе компьютера. Попробуем скомбинировать способы получения информации. Возьмем из каждого способа тот параметр, который недоступен в других и объединим это все в один. После чего, посмотрим на скорость работы объединенного способа.

000.jpg


Что потребуется?

Так как данный скрипт подразумевает в своей работе установку сторонних библиотек, то потребуется установить их довольно много. Ну как много, давайте их все перечислим: pywin32 – с помощью данной библиотеки мы будем получать информацию о материнской плате; py-cpuinfo – эта библиотека позволяет получить подробную информацию о процессоре; GPUtil – библиотека, которая предназначена для получения информации о видеокарте; psutil – это довольно известная библиотека, с помощью которой можно получить множество различной информации о системе, в нашем же случае мы будем получать информацию о HDD/SSD, а также CD/DVD-ROM и сетевых интерфейсах; python-docx – с помощью данной библиотеки мы будем сохранять отчет в документ Microsoft Word.

Для их пакетной установки выполним в терминале команду:

pip install pywin32 py-cpuinfo GPUtil psutil python-docx

Информацию об операционной системе мы получим с помощью модуля platform, потому, установки дополнительных библиотек не потребуется. В данном случае мне это показалось более оптимальным решением, чем использование той же библиотеки psutil. Информацию о BIOS мы получим с помощью библиотеки wmi, так как сторонних библиотек для этих целей найти не удалось, хотя, наверное они существуют )). Также, для получения информации о модулях оперативной памяти воспользуемся этим же модулем – wmi. Так как psutil не представляет информацию о каждой из планок установленных в системный блок.

Теперь, когда мы окончательно определились с выбором библиотек для получения информации, давайте приступим к написанию кода. Но, для начала импортируем все нужные библиотеки в скрипт.

Python:
import time
from datetime import datetime as dt
from os import environ, path
from platform import uname, win32_edition, processor, node

from docx import Document
from cpuinfo import get_cpu_info
from GPUtil import getGPUs
from psutil import disk_partitions, disk_usage, net_if_addrs
from win32com.client import GetObject
from wmi import WMI


Функция для перевода объемов дисков, памяти и др.

Для начала напишем вспомогательную функцию. Думаю, что подробно останавливаться на этой функции не имеет смысла. Создадим функцию get_size(bts: int, ending='iB') -> str, которая на входе получает целое число. Затем в цикле выполняет операцию деления до тех пор, пока данное число не станет меньше 1024. После этого возвращается полученное значение с суффиксом.

Python:
def get_size(bts: int, ending='iB') -> str:
    size = 1024
    for item in ["", "K", "M", "G", "T", "P"]:
        if bts < size:
            return f"{bts:.2f} {item}{ending}" if bts > 0 else f"{bts:.2f} {item}B"
        bts /= size


Получение информации об операционной системе (platform)

Создадим функцию platform_os() -> dict. На выходе она возвращает словарь с полученными значениями. Как вы видите, используются различные методы для получения информации и сразу же формируется словарь, который возвращается из функции. Единственный недостаток данной функции состоит в том, что мне не удалось найти нормального способа получения даты установки операционной системы. И если раньше, в ОС Windows XP, для примера, можно было определить дату установки по времени создания директории Windows, то начиная с Vista данный способ не работает. И максимум, что можно узнать с помощью данного способа, это дату упаковки дистрибутива. Поэтому, я попытался узнать дату установки с помощью определения даты создания папки пользователя. Способ этот крайне не надежный, так как папка пользователя может быть создана раньше. А потому, доверять ему нельзя. Но, тем не менее я включил данный метод в словарь. После того, как вся нужная информация будет получена, возвращаем результирующий словарь из функции.

Python:
# OS
def platform_os() -> dict:
    os_info = dict()
    if node():
        os_info.update({"ComputerName": node()})
    if uname().system and uname().release:
        os_info.update({"Caption": f'{uname().system} {uname().release}'})
    elif uname().system and not uname().release:
        os_info.update({"Caption": f'{uname().system}'})
    elif uname().release and not uname().system:
        os_info.update({"Caption": f'{uname().release}'})
    if win32_edition():
        os_info.update({"EditionID": win32_edition()})
    if uname().version:
        os_info.update({"Version": uname().version})
    if uname().machine:
        os_info.update({"Architecture": uname().machine})
    if environ['WINDIR']:
        os_info.update({"WindowsDirectory": environ['WINDIR']})
    if environ['USERNAME']:
        os_info.update({"UserName": environ['USERNAME']})
    if environ['USERPROFILE']:
        os_info.update({"InstallDate":
                            dt.fromtimestamp(path.getctime(environ['USERPROFILE'])).strftime('%d.%m.%Y, %H:%M:%S')})
    return os_info if os_info else False


Получение информации о BIOS (wmi)

Как я уже писал ранее, найти стороннюю библиотеку для получения информации о BIOS у меня не получилось. Поэтому, для полноты скрипта, я использовал функцию из предыдущей статьи. Она получает данную информацию с помощью библиотеки wmi, которая идет в Python «из коробки».

Создадим функцию bios_wmi() -> (dict, bool). На выходе она возвращает словарь с полученными данными. Создаем объект WMI. Обращаемся к методу Win32_BIOS и забираем нужную информацию. Затем добавляем ее в словарь и возвращаем из функции, если конечно, словарь не пуст.

Python:
# BIOS
def bios_wmi() -> (dict, bool):
    bios_info = dict()
    if c := WMI().Win32_BIOS()[0]:
        bios_info.update({
            'Manufacturer': c.Manufacturer,
            'Name': c.Name,
            'Version': c.Version
        })
    return bios_info if bios_info else False


Получение информации о материнской плате (pywin32)

Для получения информации о материнской плате используем модуль pywin32. Создадим функцию motherboard_win32com() -> (dict, bool), которая возвращает словарь с полученными значениями. Подключаемся к объекту wmi и выполняем запрос SQL, обращаясь к методу Win32_BaseBoard. После чего забираем информацию о производителе и названии материнской платы. Добавляем в результирующий словарь и возвращаем его из функции, если он не пуст. Также обработаем, на всякий случай любое исключение, если что-то пойдет не так.

Python:
# Motherboard
def motherboard_win32com() -> (dict, bool):
    motherboard = dict()
    try:
        if c := GetObject("winmgmts:\\\\.\\root\\cimv2"):
            if boards := c.ExecQuery("SELECT * FROM Win32_BaseBoard"):
                board = boards[0]
                motherboard['Manufacturer'] = board.Manufacturer
                motherboard['Product'] = board.Product
        return motherboard if motherboard else False
    except Exception:
        return False


Получение информации о процессоре (cpuinfo)

Для получения информации о процессоре будем использовать библиотеку cpuinfo. Создадим функцию cpu_cpuinfo() -> (dict, bool), которая возвращает словарь с собранными значениями. Обращаемся к функции = get_cpu_info из данной библиотеки. Данная функция возвращает словарь с данными о процессоре. Потому, обращаемся к ключам словаря и забираем нужную нам информацию, добавляем ее в результирующий словарь и возвращаем из функции.

Python:
# CPU
def cpu_cpuinfo() -> (dict, bool):
    if info := get_cpu_info():
        cpu_info = {
            "Name": info['brand_raw'],
            "Manufacturer": info['vendor_id_raw'],
            "Identifier": processor(),
            "Architecture": info['arch_string_raw'],
            "NumberOfLogicalProcessors": info['count'],
            "NumberOfPhysicalProcessors": int(int(info['count']) / 2),
            "CurrentRefreshRate": info['hz_actual_friendly'],
            "L2CacheSize": info['l2_cache_size'],
            "L3CacheSize": info['l3_cache_size']
        }
        return cpu_info if cpu_info else False
    return False


Получение информации о видеоадаптере (GPUtil)

Создадим функцию gpu_info() -> (dict, bool), которая возвращает словарь с полученными значениями. Получать данные мы будем с помощью библиотеки GPUtil, обратившись к функции данной библиотеки getGPUs, которая возвращает объект <GPUtil.GPUtil.GPU object at 0x00000…> с данными о видеоадаптере. В цикле итерируемся по данному объекту и забираем необходимую информацию, которую добавляем в результирующий словарь, после чего, возвращаем данный словарь из функции, если он не пуст.

Python:
# GPU
def gpu_info() -> (dict, bool):
    gpus_list = dict()
    if gpus := getGPUs():
        for gpu in gpus:
            gpus_list.update({
                "ID": gpu.id,
                "Name": gpu.name,
                "Load": f'{gpu.load * 100}%',
                "FreeMemory": gpu.memoryFree,
                "UsedMemory": gpu.memoryUsed,
                "TotalMemory": gpu.memoryTotal,
                "GPUTemp": f'{gpu.temperature} C'
            })
        return gpus_list if gpus_list else False
    return False


Получение информации об оперативной памяти (wmi)

Для получения информации об оперативной памяти снова воспользуемся библиотекой «из коробки» wmi. С помощью данной библиотеки мы получали эти же данные в предыдущей статье. К сожалению, использование библиотеки psutil не дает полной информации, только лишь в общих чертах, потому, в данном случае решено было его не использовать.

Создадим функцию memory_wmi() -> (dict, bool), возвращающую словарь с полученными данными. Создаем объект WMI, обращаемся к методу Win32_PhysicalMemory. Для начала получаем полный объем оперативной памяти, который, по сути, будет суммарным значением данных об объеме каждой планки. Добавляем полученные данные в результирующий словарь. Затем итерируемся по полученным значениям и забираем нужную информацию по каждой планке, которую добавляем в результирующий словарь. После этого, возвращаем его из функции, если он не пуст.

Python:
# Memory
def memory_wmi() -> (dict, bool):
    memory_dict = dict()
    wmi_obj = WMI()
    if memory_data := wmi_obj.Win32_PhysicalMemory():
        memory_dict.update({"TotalPhysicalMemory": get_size(sum([int(mem.Capacity) for mem in memory_data]))})
        for i, mem in enumerate(memory_data):
            memory_dict[f"Physical Memory {i}"] = dict()
            memory_dict[f"Physical Memory {i}"].update({
                "Capacity": get_size(int(mem.Capacity)),
                "ConfiguredClockSpeed": mem.Speed,
                "Manufacturer": mem.Manufacturer,
                "PartNumber": mem.PartNumber,
                "SerialNumber": mem.SerialNumber
            })
    return memory_dict if memory_dict else False


Получение информации о HDD/SSD (psutil)

Для получения информации о дисках создадим функцию hdd_ssd_psutil() -> (dict, bool). Затем итерируемся по полученным данным и забираем нужную информацию, которую добавляем в результирующий словарь. После получения информации возвращаем его из функции, если он не пуст.

Python:
# HDD, SSD
def hdd_ssd_psutil() -> (dict, bool):
    disks = dict()
    if partitions := disk_partitions():
        for partition in partitions:
            device = partition.device
            mountpoint = partition.mountpoint
            disk_us = disk_usage(mountpoint)
            disk = {'Drive': device,
                    'Mountpoint': mountpoint,
                    'TotalSpace': get_size(disk_us.total),
                    'UsedSpace': get_size(disk_us.used),
                    'FreeSpace': get_size(disk_us.free),
                    'PercentUsed': disk_us.percent}
            disks[device] = disk
        return disks if disks else False
    return False


Получение информации о CD/DVD-ROM (psutil)

Для получения информации о приводах воспользуемся библиотекой psutil. Более того, функция, которая будет получать данную информацию не особо отличается от той, где мы получали информацию о дисках. Здесь мы всего лишь отфильтруем возвращаемые disk_partitions значения по 'cdrom', а затем получим информацию о нужном разделе.

Создадим функцию cdrom_psutil() -> (dict, bool). Для начала, получим информацию обо всех разделах. Затем отфильтруем полученные значения по cd-rom. Дальше, в цикле будем перебирать полученные значения и заберем только ту информацию, которая относиться к конкретному, отфильтрованному нами разделу. После чего возвратим результирующий словарь из функции, если он не пуст.

Python:
# CD-ROM
def cdrom_psutil() -> (dict, bool):
    info = dict()
    if disks := disk_partitions():
        if cdrom_disks := filter(lambda disk: 'cdrom' in disk.opts, disks):
            for dsk in cdrom_disks:
                try:
                    disk_info = disk_usage(dsk.mountpoint)
                    info[dsk.device] = {
                        'TotalSpace': get_size(disk_info.total),
                        'UsedSpace': get_size(disk_info.used),
                        'FreeSpace': get_size(disk_info.free)
                    }
                except Exception:
                    pass
        return info if info else False
    return False


Получение информации о сетевых интерфейсах (psutil)

Для получения информации о сетевых интерфейсах будем использовать библиотеку psutil. Создадим функцию nic_psutil() -> (dict, bool). Обратимся к функции net_if_addrs, которая возвращает информацию о сетевых интерфейсах, выпилим из данной информации локальную петлю, так как она не является физическим устройством. Затем, по каждому из устройств соберем возвращаемую информацию и добавим в результирующий словарь. После чего вернем его из функции, если он не пуст.

Python:
# Network Information
def nic_psutil() -> (dict, bool):
    nic = dict()
    for item in net_if_addrs():
        if "loopback" in item.lower():
            continue
        nic[item] = dict()
        for adapt in net_if_addrs()[item]:
            match adapt.family:
                case -1:
                    nic[item].update({"MACAddress": adapt.address})
                case 2:
                    nic[item].update({"IPv4Address": adapt.address,
                                      "IPSubnet": adapt.netmask})
                case 23:
                    nic[item].update({"IPv6Address": adapt.address})
    return nic if nic else False

На этом, как и в предыдущих статьях, завершим сбор информации. И выведем полученные данные в терминал, а также сохраним в документ Microsoft Word.


Функция печати полученных словарей

Ничего нового в данной функции не будет. Ее подробно я описывал в предыдущих статьях, потому, пробежимся по основным моментам. Для начала создадим глобальную строковую переменную, куда будем складывать полученные данные в строковом виде. Эти данные мы потом запишем в документ.

Создаем функцию print_wmic(part, dict_info), где part, это строка с данными об обрабатываемом словаре, а dict_info – непосредственно, сам словарь с данными. Создаем словарь синонимов, чтобы заменять значения из словарей на их эквиваленты.

Python:
def print_wmic(part, dict_info):
    global wmic_info
    synonyms = {"ComputerName": "Имя компьютера", "Caption": "Название", "InstallDate": "Дата установки",
                "LastBootUpTime": "Время последней загрузки", "Version": "Версия",
                "WindowsDirectory": "Директория Windows", "TimeZone": "Часовой пояс", "UserName": "Имя пользователя",
                "Manufacturer": "Производитель", "Name": "Название", "Product": "Изделие",
                "MaxClockSpeed": "Максимальная тактовая частота", "SocketDesignation": "Название сокета",
                "NumberOfPhysicalProcessors": "Количество физических процессоров", "VideoProcessor": "Видеопроцессор",
                "NumberOfLogicalProcessors": "Количество логических процессоров", "Capacity": "Емкость",
                "AdapterRAM": "Оперативная память адаптера", "CurrentRefreshRate": "Текущая частота обновления",
                "Resolution": "Разрешение", "TotalPhysicalMemory": "Общий объем физической памяти", "Socket": "Сокет",
                "ConfiguredClockSpeed": "Настроенная тактовая частота", "PartNumber": "Номер партии",
                "SerialNumber": "Серийный номер", "DeviceID": "Идентификатор устройства", "MediaType": "Тип носителя",
                "FirmwareRevision": "Ревизия прошивки", "Partitions": "Разделы", "Size": "Объем", "Drive": "Диск",
                "VolumeName": "Имя тома", "VolumeSerialNumber": "Серийный номер тома", "MACAddress": "MAC-адрес",
                "NetConnectionID": "Идентификатор сетевого подключения", "DHCPServer": "DHCP-сервер",
                "IPAddress": "IP-адрес", "BuildNumber": "Номер сборки", "ID": "Идентификатор", "Status": "Статус",
                "DefaultIPGateway": "IP-адрес шлюза по-умолчанию", "DNSHostName": "DNS Имя хоста",
                "IPv4Address": "IPv4-адрес", "IPv6Address": "IPv6-адрес", "IPSubnet": "Маска подсети",
                "ServiceName": "Название службы", "Architecture": "Архитектура", "L2CacheSize": "Размер кэша L2",
                "L3CacheSize": "Размер кэша L3", "Load": "Загрузка", "FreeMemory": "Свободная память",
                "UsedMemory": "Занятая память", "TotalMemory": "Общее количество памяти", "GPUTemp": "Температура GPU",
                "Mountpoint": "Точка монтирования", "TotalSpace": "Размер", "UsedSpace": "Занято",
                "FreeSpace": "Свободно", "PercentUsed": "Процент использования", "EditionID": "Идентификатор редакции",
                "Identifier": "Идентификатор"}

А затем, непосредственно, следует тело функции, в котором мы итерируемся по словарю, проверяем тип значения ключа. Если он является словарем, итерируемся по нему. Если нет, добавляем значение и его расшифровку в переменную part. После всего добавляем значения из part в глобальную переменную wmic_info, а также выводим содержимое part в терминал.

Python:
    part += f'{"-" * 50}\n'
    for key in dict_info:
        if type(dict_info[key]) == dict:
            for item in dict_info[key]:
                part += f'{synonyms[item]}: {dict_info[key][item]}\n'
            part += "\n"
        else:
            part += f'{synonyms[key]}: {dict_info[key]}\n'
    print(part)
    wmic_info += f'{part}\n'


Функция main

Создадим функцию main, в которой будем получать из функций словари, и, если они будут получены, запускать функцию печати значений. Также, в данной функции создадим документ Microsoft Word, добавим в него заголовок, и, после того, как будут получены данные из всех функций, добавим в параграф значение из строковой переменной wmic_info. После чего сохраним созданный документ и выведем для пользователя информацию о файле, а также время работы скрипта.


Python:
def main():
    global wmic_info
    t = time.monotonic()
    document = Document()
    document.add_heading(f'Сводная информация о компьютере: {node()}', 0)

    if os_info := platform_os():
        print_wmic("Информация об операционной системе\n", os_info)
    if bios_info := bios_wmi():
        print_wmic("Информация о BIOS\n", bios_info)
    if mb_info := motherboard_win32com():
        print_wmic("Информация о материнской плате\n", mb_info)
    if cpu_info := cpu_cpuinfo():
        print_wmic("Информация о процессоре\n", cpu_info)
    if gpu := gpu_info():
        print_wmic("Информация о видеокарте\n", gpu)
    if mem_info := memory_wmi():
        print_wmic("Информация об оперативной памяти\n", mem_info)
    if drive_info := hdd_ssd_psutil():
        print_wmic("Информация о HDD и SSD\n", drive_info)
    if cd_rom_info := cdrom_psutil():
        print_wmic("Информация о CD/DVD-ROM\n", cd_rom_info)
    if nic_info := nic_psutil():
        print_wmic("Информация о физических сетевых интерфейсах\n", nic_info)

    document.add_paragraph(wmic_info)
    document.save(f'{node()}.docx')
    print(f"Собранная информация сохранена в файл: {node()}.docx")
    print(f'\nВремя работы скрипта: {time.monotonic() - t} с.')


if __name__ == "__main__":
    main()

Python:
# pip install pywin32 py-cpuinfo GPUtil psutil python-docx

import time
from datetime import datetime as dt
from os import environ, path
from platform import uname, win32_edition, processor, node

from docx import Document
from cpuinfo import get_cpu_info
from GPUtil import getGPUs
from psutil import disk_partitions, disk_usage, net_if_addrs
from win32com.client import GetObject
from wmi import WMI


def get_size(bts: int, ending='iB') -> str:
    size = 1024
    for item in ["", "K", "M", "G", "T", "P"]:
        if bts < size:
            return f"{bts:.2f} {item}{ending}" if bts > 0 else f"{bts:.2f} {item}B"
        bts /= size


# OS
def platform_os() -> dict:
    os_info = dict()
    if node():
        os_info.update({"ComputerName": node()})
    if uname().system and uname().release:
        os_info.update({"Caption": f'{uname().system} {uname().release}'})
    elif uname().system and not uname().release:
        os_info.update({"Caption": f'{uname().system}'})
    elif uname().release and not uname().system:
        os_info.update({"Caption": f'{uname().release}'})
    if win32_edition():
        os_info.update({"EditionID": win32_edition()})
    if uname().version:
        os_info.update({"Version": uname().version})
    if uname().machine:
        os_info.update({"Architecture": uname().machine})
    if environ['WINDIR']:
        os_info.update({"WindowsDirectory": environ['WINDIR']})
    if environ['USERNAME']:
        os_info.update({"UserName": environ['USERNAME']})
    if environ['USERPROFILE']:
        os_info.update({"InstallDate":
                            dt.fromtimestamp(path.getctime(environ['USERPROFILE'])).strftime('%d.%m.%Y, %H:%M:%S')})
    return os_info if os_info else False


# BIOS
def bios_wmi() -> (dict, bool):
    bios_info = dict()
    if c := WMI().Win32_BIOS()[0]:
        bios_info.update({
            'Manufacturer': c.Manufacturer,
            'Name': c.Name,
            'Version': c.Version
        })
    return bios_info if bios_info else False


# Motherboard
def motherboard_win32com() -> (dict, bool):
    motherboard = dict()
    try:
        if c := GetObject("winmgmts:\\\\.\\root\\cimv2"):
            if boards := c.ExecQuery("SELECT * FROM Win32_BaseBoard"):
                board = boards[0]
                motherboard['Manufacturer'] = board.Manufacturer
                motherboard['Product'] = board.Product
        return motherboard if motherboard else False
    except Exception:
        return False


# CPU
def cpu_cpuinfo() -> (dict, bool):
    if info := get_cpu_info():
        cpu_info = {
            "Name": info['brand_raw'],
            "Manufacturer": info['vendor_id_raw'],
            "Identifier": processor(),
            "Architecture": info['arch_string_raw'],
            "NumberOfLogicalProcessors": info['count'],
            "NumberOfPhysicalProcessors": int(int(info['count']) / 2),
            "CurrentRefreshRate": info['hz_actual_friendly'],
            "L2CacheSize": info['l2_cache_size'],
            "L3CacheSize": info['l3_cache_size']
        }
        return cpu_info if cpu_info else False
    return False


# GPU
def gpu_info() -> (dict, bool):
    gpus_list = dict()
    if gpus := getGPUs():
        for gpu in gpus:
            gpus_list.update({
                "ID": gpu.id,
                "Name": gpu.name,
                "Load": f'{gpu.load * 100}%',
                "FreeMemory": gpu.memoryFree,
                "UsedMemory": gpu.memoryUsed,
                "TotalMemory": gpu.memoryTotal,
                "GPUTemp": f'{gpu.temperature} C'
            })
        return gpus_list if gpus_list else False
    return False


# Memory
def memory_wmi() -> (dict, bool):
    memory_dict = dict()
    wmi_obj = WMI()
    if memory_data := wmi_obj.Win32_PhysicalMemory():
        memory_dict.update({"TotalPhysicalMemory": get_size(sum([int(mem.Capacity) for mem in memory_data]))})
        for i, mem in enumerate(memory_data):
            memory_dict[f"Physical Memory {i}"] = dict()
            memory_dict[f"Physical Memory {i}"].update({
                "Capacity": get_size(int(mem.Capacity)),
                "ConfiguredClockSpeed": mem.Speed,
                "Manufacturer": mem.Manufacturer,
                "PartNumber": mem.PartNumber,
                "SerialNumber": mem.SerialNumber
            })
    return memory_dict if memory_dict else False


# HDD, SSD
def hdd_ssd_psutil() -> (dict, bool):
    disks = dict()
    if partitions := disk_partitions():
        for partition in partitions:
            device = partition.device
            mountpoint = partition.mountpoint
            disk_us = disk_usage(mountpoint)
            disk = {'Drive': device,
                    'Mountpoint': mountpoint,
                    'TotalSpace': get_size(disk_us.total),
                    'UsedSpace': get_size(disk_us.used),
                    'FreeSpace': get_size(disk_us.free),
                    'PercentUsed': disk_us.percent}
            disks[device] = disk
        return disks if disks else False
    return False


# CD-ROM
def cdrom_psutil() -> (dict, bool):
    info = dict()
    if disks := disk_partitions():
        if cdrom_disks := filter(lambda disk: 'cdrom' in disk.opts, disks):
            for dsk in cdrom_disks:
                try:
                    disk_info = disk_usage(dsk.mountpoint)
                    info[dsk.device] = {
                        'TotalSpace': get_size(disk_info.total),
                        'UsedSpace': get_size(disk_info.used),
                        'FreeSpace': get_size(disk_info.free)
                    }
                except Exception:
                    pass
        return info if info else False
    return False


# Network Information
def nic_psutil() -> (dict, bool):
    nic = dict()
    for item in net_if_addrs():
        if "loopback" in item.lower():
            continue
        nic[item] = dict()
        for adapt in net_if_addrs()[item]:
            match adapt.family:
                case -1:
                    nic[item].update({"MACAddress": adapt.address})
                case 2:
                    nic[item].update({"IPv4Address": adapt.address,
                                      "IPSubnet": adapt.netmask})
                case 23:
                    nic[item].update({"IPv6Address": adapt.address})
    return nic if nic else False


wmic_info = ""


def print_wmic(part, dict_info):
    global wmic_info
    synonyms = {"ComputerName": "Имя компьютера", "Caption": "Название", "InstallDate": "Дата установки",
                "LastBootUpTime": "Время последней загрузки", "Version": "Версия",
                "WindowsDirectory": "Директория Windows", "TimeZone": "Часовой пояс", "UserName": "Имя пользователя",
                "Manufacturer": "Производитель", "Name": "Название", "Product": "Изделие",
                "MaxClockSpeed": "Максимальная тактовая частота", "SocketDesignation": "Название сокета",
                "NumberOfPhysicalProcessors": "Количество физических процессоров", "VideoProcessor": "Видеопроцессор",
                "NumberOfLogicalProcessors": "Количество логических процессоров", "Capacity": "Емкость",
                "AdapterRAM": "Оперативная память адаптера", "CurrentRefreshRate": "Текущая частота обновления",
                "Resolution": "Разрешение", "TotalPhysicalMemory": "Общий объем физической памяти", "Socket": "Сокет",
                "ConfiguredClockSpeed": "Настроенная тактовая частота", "PartNumber": "Номер партии",
                "SerialNumber": "Серийный номер", "DeviceID": "Идентификатор устройства", "MediaType": "Тип носителя",
                "FirmwareRevision": "Ревизия прошивки", "Partitions": "Разделы", "Size": "Объем", "Drive": "Диск",
                "VolumeName": "Имя тома", "VolumeSerialNumber": "Серийный номер тома", "MACAddress": "MAC-адрес",
                "NetConnectionID": "Идентификатор сетевого подключения", "DHCPServer": "DHCP-сервер",
                "IPAddress": "IP-адрес", "BuildNumber": "Номер сборки", "ID": "Идентификатор", "Status": "Статус",
                "DefaultIPGateway": "IP-адрес шлюза по-умолчанию", "DNSHostName": "DNS Имя хоста",
                "IPv4Address": "IPv4-адрес", "IPv6Address": "IPv6-адрес", "IPSubnet": "Маска подсети",
                "ServiceName": "Название службы", "Architecture": "Архитектура", "L2CacheSize": "Размер кэша L2",
                "L3CacheSize": "Размер кэша L3", "Load": "Загрузка", "FreeMemory": "Свободная память",
                "UsedMemory": "Занятая память", "TotalMemory": "Общее количество памяти", "GPUTemp": "Температура GPU",
                "Mountpoint": "Точка монтирования", "TotalSpace": "Размер", "UsedSpace": "Занято",
                "FreeSpace": "Свободно", "PercentUsed": "Процент использования", "EditionID": "Идентификатор редакции",
                "Identifier": "Идентификатор"}
    part += f'{"-" * 50}\n'
    for key in dict_info:
        if type(dict_info[key]) == dict:
            for item in dict_info[key]:
                part += f'{synonyms[item]}: {dict_info[key][item]}\n'
            part += "\n"
        else:
            part += f'{synonyms[key]}: {dict_info[key]}\n'
    print(part)
    wmic_info += f'{part}\n'


def main():
    global wmic_info
    t = time.monotonic()
    document = Document()
    document.add_heading(f'Сводная информация о компьютере: {node()}', 0)

    if os_info := platform_os():
        print_wmic("Информация об операционной системе\n", os_info)
    if bios_info := bios_wmi():
        print_wmic("Информация о BIOS\n", bios_info)
    if mb_info := motherboard_win32com():
        print_wmic("Информация о материнской плате\n", mb_info)
    if cpu_info := cpu_cpuinfo():
        print_wmic("Информация о процессоре\n", cpu_info)
    if gpu := gpu_info():
        print_wmic("Информация о видеокарте\n", gpu)
    if mem_info := memory_wmi():
        print_wmic("Информация об оперативной памяти\n", mem_info)
    if drive_info := hdd_ssd_psutil():
        print_wmic("Информация о HDD и SSD\n", drive_info)
    if cd_rom_info := cdrom_psutil():
        print_wmic("Информация о CD/DVD-ROM\n", cd_rom_info)
    if nic_info := nic_psutil():
        print_wmic("Информация о физических сетевых интерфейсах\n", nic_info)

    document.add_paragraph(wmic_info)
    document.save(f'{node()}.docx')
    print(f"Собранная информация сохранена в файл: {node()}.docx")
    print(f'\nВремя работы скрипта: {time.monotonic() - t} с.')


if __name__ == "__main__":
    main()

Теперь давайте проверим скорость работы получившегося «франкенштейна» и сравним ее со скоростью работы скриптов, которые мы написали в предыдущих статьях.

001.png


  • Итак, как мы видим, на первом месте по-прежнему скрипт, который использует для получения данных библиотеку winreg и читает ее из реестра;
  • На втором расположился, как это ни странно, текущий «франкенштейн»;
  • Третье место – библиотека subprocess и утилита wmic;
  • Четвертое, почетное место – библиотека wmi.

Таким образом, у нас определились явные победители данного «соревнования». Но, сборный скрипт я буду составлять из библиотек, которые идут в python «из коробки». Даже, если они используют стороннюю утилиту для сбора информации.

Для сборки составного скрипта за основу я решил взять тот, что использует модуль winreg. И, несмотря на то, что информация, которую получает данный модуль, не является полной, он все же показывает самую большую скорость работы. А дополнять его я буду функциями из скрипта, который использует subprocess и утилиту командной строки wmic, потому, что кроме «франкенштейна», у него неплохая скорость работы.

А добавим мы функцию для получения информации об оперативной памяти. Потому как я не нашел веток в реестре, где можно было бы почерпнуть данную информацию. Хотя, они наверняка есть. А также заменим функции для получения данных о HDD/SSD и CD/DVD-ROM, так как функции из скрипта использующего subprocess предоставляют больше информации.

Расписывать создание составного скрипта не имеет большого смысла. Вот, что у меня получилось в итоге:

Python:
# pip install python-docx windows-tools

import time
from datetime import datetime as dt, timedelta
from platform import node
from struct import unpack
from winreg import OpenKeyEx, QueryValueEx, HKEY_LOCAL_MACHINE, QueryInfoKey, EnumKey, KEY_READ
from subprocess import check_output
from wmi import WMI

from docx import Document
from windows_tools import product_key


def get_size(bts: int, ending='iB') -> str:
    size = 1024
    for item in ["", "K", "M", "G", "T", "P"]:
        if bts < size:
            return f"{bts:.2f} {item}{ending}" if bts > 0 else f"{bts:.2f} {item}B"
        bts /= size


# Узнаем версию ОС
def winreg_os() -> (dict, bool):
    try:
        win_info = dict()
        if comp_info := OpenKeyEx(HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName"):
            win_info.update({'ComputerName': QueryValueEx(comp_info, 'ComputerName')[0]})
        if comp_shutdown := OpenKeyEx(HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\Windows"):
            shutdown_time_bin = QueryValueEx(comp_shutdown, 'ShutdownTime')[0]
            shutdown_time = (dt(1601, 1, 1) + timedelta(microseconds=float(unpack("<Q", shutdown_time_bin)[0]) / 10)). \
                strftime('%Y-%m-%d %H:%M:%S')
            win_info.update({'ShutdownTime': shutdown_time})
        if win_ver := OpenKeyEx(HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion"):
            for key in ["ProductName", "EditionID", "DisplayVersion", "CurrentBuild", "UBR", "InstallDate",
                        "RegisteredOwner"]:
                try:
                    if key == "InstallDate":
                        win_info.update({key: str(dt.fromtimestamp(QueryValueEx(win_ver, f'{key}')[0]))})
                    else:
                        win_info.update({key: QueryValueEx(win_ver, f'{key}')[0]})
                except FileNotFoundError:
                    continue
        if tz_key := OpenKeyEx(HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"):
            win_info.update({"TimeZone": QueryValueEx(tz_key, 'TimeZoneKeyName')[0]})
        if pkey := product_key.get_windows_product_key_from_reg():
            win_info.update({"ActivateKey": pkey})
        elif pkey := product_key.get_windows_product_key_from_wmi():
            win_info.update({"ActivateKey": pkey})
        else:
            win_info.update({"ActivateKey": "No Key"})
        return win_info if win_info else False
    except Exception:
        return False


# OS
def wmic_os() -> (dict, bool):
    os_info = dict()
    try:
        os_i = check_output("wmic OS get Caption, InstallDate, Version, WindowsDirectory, LastBootUpTime /value",
                            shell=True).decode().strip()
    except UnicodeDecodeError:
        os_i = check_output("wmic OS get Caption, InstallDate, Version, WindowsDirectory, LastBootUpTime /value",
                            shell=True).decode("cp866").strip()
    if os_i:
        out = [{x.strip().split("=")[0]: x.strip().split("=")[1]} for x in os_i.splitlines() if x.strip()]
        if comp_name := check_output("wmic computersystem get name /value", shell=True).decode().strip():
            os_info.update({"ComputerName": comp_name.split("=")[1].strip()})
        for item in out:
            for it in item:
                if item[it]:
                    if it == "InstallDate":
                        date = dt.strptime(item[it][:len(item[it]) - 4], '%Y%m%d%H%M%S.%f').strftime(
                            "%Y-%m-%d %H:%M:%S")
                        item = {"InstallDate": date}
                    if it == "LastBootUpTime":
                        date = dt.strptime(item[it][:len(item[it]) - 4], '%Y%m%d%H%M%S.%f').strftime(
                            "%Y-%m-%d %H:%M:%S")
                        item = {"LastBootUpTime": date}
                    os_info.update(item)
    if tz_get := check_output("wmic TIMEZONE get Caption /value", shell=True).decode().strip():
        tz = [{"TimeZone": x.strip().split("=")[1]} for x in tz_get.splitlines() if x.strip()]
        os_info.update(tz[0])
    if user_get := check_output('wmic USERACCOUNT Where (Status="OK") get Name /value', shell=True).decode().strip():
        user = [{"UserName": x.strip().split("=")[1]} for x in user_get.splitlines() if x.strip()]
        os_info.update(user[0])
    return os_info if os_info else False


# BIOS
def bios_winreg() -> (dict, bool):
    md_dict = dict()
    if sbv := OpenKeyEx(HKEY_LOCAL_MACHINE, r"HARDWARE\DESCRIPTION\System"):
        md_dict.update({"SystemBiosVersion": QueryValueEx(sbv, "SystemBiosVersion")[0][0]})
    for key in ["BIOSVendor", "BIOSVersion", "BIOSReleaseDate"]:
        if bios := OpenKeyEx(HKEY_LOCAL_MACHINE, r"HARDWARE\DESCRIPTION\System\BIOS"):
            try:
                md_dict.update({key: QueryValueEx(bios, key)[0]})
            except FileNotFoundError:
                continue
        else:
            return False
    return md_dict if md_dict else False


# BIOS
def bios_wmic() -> (dict, bool):
    bios_info = dict()
    if bios := check_output("wmic BIOS get Version, Manufacturer, Name /value", shell=True).decode(). \
            strip():
        out = [{f'{x.strip().split("=")[0]}': x.strip().split("=")[1]} for x in bios.splitlines() if x.strip()]
        for item in out:
            bios_info.update(item)
        return bios_info if bios_info else False
    return False


# Материнская плата
def motherboard_winreg() -> (dict, bool):
    md_dict = dict()
    if mb_info := OpenKeyEx(HKEY_LOCAL_MACHINE, r"SYSTEM\CurrentControlSet\Control\SystemInformation"):
        md_dict.update({'SystemManufacturer': QueryValueEx(mb_info, 'SystemManufacturer')[0]})
        md_dict.update({'SystemProductName': QueryValueEx(mb_info, 'SystemProductName')[0]})
        return md_dict if md_dict else False
    return False


# Motherboard
def motherboard_wmic() -> (dict, bool):
    mb_info = dict()
    if mb_get := check_output("wmic baseboard get Product, Manufacturer /value", shell=True).decode().strip():
        out = [{f'{x.strip().split("=")[0]}': x.strip().split("=")[1]} for x in mb_get.splitlines() if x.strip()]
        for item in out:
            mb_info.update(item)
        return mb_info if mb_info else False
    return False


# Memory
def memory_wmic() -> (dict, bool):
    memory_info = dict()
    if total_memory_get := check_output("wmic COMPUTERSYSTEM get TotalPhysicalMemory /value",
                                        shell=True).decode().strip():
        total_memory = [{x.strip().split("=")[0]: get_size(int(x.strip().split("=")[1]))}
                        for x in total_memory_get.splitlines() if x.strip()]
        memory_info.update(total_memory[0])
    if memory_tag_get := check_output("wmic MEMORYCHIP get Tag /value", shell=True).decode().strip():
        memory_tag = [x.strip().split("=")[1] for x in memory_tag_get.splitlines() if x.strip()]
        for tag in memory_tag:
            info_get = check_output(f'wmic MEMORYCHIP Where (Tag="{tag}") get Capacity, ConfiguredClockSpeed, '
                                    f'Manufacturer, PartNumber, SerialNumber /value', shell=True).decode().strip()
            memory_info[tag.strip()] = dict()
            for x in info_get.splitlines():
                if x.strip():
                    if x.strip().split("=")[0] == "Capacity" and x.strip().split("=")[1]:
                        memory_info[tag.strip()].update({
                            x.strip().split("=")[0].strip(): get_size(int(x.strip().split("=")[1])).strip()
                        })
                    else:
                        memory_info[tag.strip()].update({
                            x.strip().split("=")[0].strip(): x.strip().split("=")[1].strip()
                        })
    return memory_info if memory_info else False


# Memory
def memory_wmi() -> (dict, bool):
    memory_dict = dict()
    wmi_obj = WMI()
    if memory_data := wmi_obj.Win32_PhysicalMemory():
        memory_dict.update({"TotalPhysicalMemory": get_size(sum([int(mem.Capacity) for mem in memory_data]))})

        for i, mem in enumerate(memory_data):
            memory_dict[f"Physical Memory {i}"] = dict()
            memory_dict[f"Physical Memory {i}"].update({
                "Capacity": get_size(int(mem.Capacity)),
                "ConfiguredClockSpeed": mem.Speed,
                "Manufacturer": mem.Manufacturer,
                "PartNumber": mem.PartNumber,
                "SerialNumber": mem.SerialNumber
            })
    return memory_dict if memory_dict else False


# CPU
def cpu_winreg():
    try:
        proc_info = dict()
        loc = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor"
        with OpenKeyEx(HKEY_LOCAL_MACHINE, loc) as h_apps:
            if QueryInfoKey(h_apps)[0]:
                proc_info.update({"CoreCount": QueryInfoKey(h_apps)[0]})
                try:
                    core = OpenKeyEx(h_apps, EnumKey(h_apps, 0))
                    proc_info.update({
                        "ProcessorNameString": QueryValueEx(core, 'ProcessorNameString')[0].strip(),
                        "Identifier": QueryValueEx(core, 'Identifier')[0].strip(),
                        "VendorIdentifier": QueryValueEx(core, 'VendorIdentifier')[0].strip(),
                        "~MHz": QueryValueEx(core, '~MHz')[0]
                    })
                except FileNotFoundError:
                    return False
        return proc_info if proc_info else False
    except Exception:
        return False


# CPU
def cpu_wmic() -> (dict, bool):
    mb_info = dict()
    if mb_get := check_output("wmic cpu get Name, Caption, Manufacturer, SocketDesignation, MaxClockSpeed /value",
                              shell=True).decode().strip():
        out = [{f'{x.strip().split("=")[0]}': x.strip().split("=")[1]} for x in mb_get.splitlines() if x.strip()]
        for item in out:
            mb_info.update(item)
    if core_all := check_output("wmic COMPUTERSYSTEM get NumberOfLogicalProcessors /value",
                                shell=True).decode().strip():
        mb_info.update({'NumberOfPhysicalProcessors': str(int(int(core_all.split("=")[1].strip()) / 2)),
                        f'{core_all.split("=")[0].strip()}': core_all.split("=")[1].strip()})
    return mb_info if mb_info else False


# GPU
def gpu_wmic() -> (dict, bool):
    gpu = dict()
    if output := check_output('wmic path win32_VideoController get Name, AdapterRAM, VideoProcessor, '
                              'CurrentHorizontalResolution, CurrentVerticalResolution, CurrentRefreshRate /value',
                              shell=True).decode().strip():
        out = [{x.strip().split("=")[0]: x.strip().split("=")[1]} for x in output.splitlines() if x.strip()]
        res = ""
        for vrm in out:
            for vr in vrm:
                if vr == 'AdapterRAM':
                    gpu.update({"AdapterRAM": get_size(int(vrm[vr]))})
                    continue
                if vr == 'CurrentHorizontalResolution':
                    res += f'{vrm[vr]}x'
                    continue
                if vr == 'CurrentVerticalResolution':
                    res += str(vrm[vr])
                    gpu.update({"Resolution": res})
                    continue
                gpu.update(vrm)
        return gpu if gpu else False
    return False


# GPU
def gpu_wmi() -> (dict, bool):
    gpu = dict()
    if vc := WMI().Win32_VideoController()[0]:
        gpu.update({
            "Name": vc.Description,
            "AdapterRAM": get_size(abs(vc.AdapterRAM)),
            "Resolution": f'{vc.CurrentHorizontalResolution}x{vc.CurrentVerticalResolution}',
            "CurrentRefreshRate": f'{vc.CurrentRefreshRate} Гц',
            "VideoProcessor": vc.VideoProcessor
        })
    return gpu if gpu else False


# HDD, SSD
def hdd_ssd_wmic() -> (dict, bool):
    disk_info = dict()
    if caption_get := check_output("wmic diskdrive get Caption /value", shell=True).decode().strip():
        caption = [x.strip().split("=")[1] for x in caption_get.splitlines() if x.strip()]
        for num, cap in enumerate(caption):
            if info_get := check_output(
                    f'wmic diskdrive Where (Caption="{cap}") get DeviceID, FirmwareRevision, MediaType, '
                    f'Partitions, SerialNumber, Size /value', shell=True).decode().strip():
                disk_info[f'{cap} {num}'] = dict()
                disk_info[f'{cap} {num}'].update({"Product": cap})
                for x in info_get.splitlines():
                    if x.strip():
                        if x.strip().split("=")[0] == "Size" and x.strip().split("=")[1]:
                            disk_info[f'{cap} {num}'].update({
                                f'{x.strip().split("=")[0].strip()}': get_size(int(x.strip().split("=")[1].strip()))
                            })
                        else:
                            disk_info[f'{cap} {num}'].update({
                                f'{x.strip().split("=")[0].strip()}': x.strip().split("=")[1].strip()
                            })
    return disk_info if disk_info else False


# HDD, SSD
def hdd_ssd_wmi() -> (dict, bool):
    disk_info = dict()
    c = WMI()
    if disks := c.Win32_DiskDrive():
        for disk in disks:
            disk_info[disk.DeviceID] = {
                'Caption': disk.Model,
                'MediaType': disk.InterfaceType,
                'Capacity': get_size(int(disk.Size))
            }
    return disk_info if disk_info else False


# CD-ROM
def cdrom_wmic() -> (dict, bool):
    cdrom_info = dict()
    if caption_get := check_output("wmic CDROM get Caption /value", shell=True).decode().strip():
        caption = [x.strip().split("=")[1] for x in caption_get.splitlines() if x.strip()]
        for num, cap in enumerate(caption):
            if info_get := check_output(
                    f'wmic CDROM Where (Caption="{cap}") get Drive, VolumeName, VolumeSerialNumber, Size '
                    f'/value', shell=True).decode().strip():
                cdrom_info[cap] = dict()
                cdrom_info[cap].update({"Product": cap})
                for x in info_get.splitlines():
                    if x.strip():
                        if x.strip().split("=")[0].strip() == "Size" and x.strip().split("=")[1].strip():
                            cdrom_info[cap].update({
                                f'{x.strip().split("=")[0].strip()}': get_size(int(x.strip().split("=")[1].strip()))
                            })
                        cdrom_info[cap].update({
                            f'{x.strip().split("=")[0].strip()}': x.strip().split("=")[1].strip()
                        })
    return cdrom_info if cdrom_info else False


# CD-ROM
def cdrom_wmi() -> (dict, bool):
    cdrom_info = dict()
    c = WMI()
    if cdroms := c.Win32_CDROMDrive():
        for cdrom in cdroms:
            cdrom_info[cdrom.Caption] = dict()
            cdrom_info[cdrom.Caption].update({
                'Drive': cdrom.Caption,
                'MediaType': cdrom.MediaType,
                'Status': cdrom.Status,
                'SerialNumber': cdrom.SerialNumber,
                'Manufacturer': cdrom.Manufacturer
            })
    return cdrom_info if cdrom_info else False


# Network Interface
def nic_winreg():
    try:
        nic = dict()
        loc = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards'
        desc = []
        if adapt_name := OpenKeyEx(HKEY_LOCAL_MACHINE, loc):
            for idx in range(QueryInfoKey(adapt_name)[0]):
                adapter = OpenKeyEx(adapt_name, EnumKey(adapt_name, idx))
                nic[QueryValueEx(adapter, 'ServiceName')[0]] = dict()
                nic[QueryValueEx(adapter, 'ServiceName')[0]].update({
                    "Description": QueryValueEx(adapter, 'Description')[0]
                })
                desc.append(QueryValueEx(adapter, 'Description')[0])
                loc_adapt = r'SYSTEM\ControlSet001\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}'
                cfg = []
                if adapt := OpenKeyEx(HKEY_LOCAL_MACHINE, loc_adapt):
                    for idc in range(QueryInfoKey(adapt)[0]):
                        try:
                            adpt = OpenKeyEx(adapt, EnumKey(adapt, idc))
                            if QueryValueEx(adpt, 'DriverDesc')[0] in desc:
                                nic[QueryValueEx(adpt, 'NetCfgInstanceId')[0]].update({
                                    "Description": QueryValueEx(adpt, 'DriverDesc')[0]
                                })
                                cfg.append(QueryValueEx(adpt, 'NetCfgInstanceId')[0])
                        except (FileNotFoundError, PermissionError):
                            continue
                inter = r'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces'
                if inter_cfg := OpenKeyEx(HKEY_LOCAL_MACHINE, inter):
                    for idb in range(QueryInfoKey(inter_cfg)[0]):
                        if EnumKey(inter_cfg, idb).upper() in cfg:
                            nic[EnumKey(inter_cfg, idb).upper()].update({
                                "NetCfgInstanceId": EnumKey(inter_cfg, idb).upper()})
                            intr = OpenKeyEx(inter_cfg, EnumKey(inter_cfg, idb))
                            try:
                                nic[EnumKey(inter_cfg, idb).upper()].update({
                                    "DhcpDefaultGateway": QueryValueEx(intr, 'DhcpDefaultGateway')[0]})
                            except FileNotFoundError:
                                pass
                            try:
                                nic[EnumKey(inter_cfg, idb).upper()].update({
                                    "DhcpIPAddress": QueryValueEx(intr, 'DhcpIPAddress')[0]})
                            except FileNotFoundError:
                                pass
                            try:
                                nic[EnumKey(inter_cfg, idb).upper()].update({
                                    "DhcpIPAddress": QueryValueEx(intr, 'DhcpIPAddress')[0]})
                            except FileNotFoundError:
                                pass
                            netw = r'SYSTEM\ControlSet001\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}' + '\\' + \
                                   EnumKey(inter_cfg, idb).upper() + '\\' + 'Connection'
                            if netw_cfg := OpenKeyEx(HKEY_LOCAL_MACHINE, netw):
                                nic[EnumKey(inter_cfg, idb).upper()].update({
                                    "Name": QueryValueEx(netw_cfg, 'Name')[0]})
        return nic if nic else False
    except Exception:
        return False


# Network Interface
def nic_wmic() -> (dict, bool):
    nic_info = dict()
    if description_get := check_output('wmic NIC Where (PhysicalAdapter="TRUE") get Description /value', shell=True). \
            decode().strip():
        description = [x.strip().split("=")[1] for x in description_get.splitlines() if x.strip()]
        for nic in description:
            try:
                nic_d = check_output(
                    f'wmic NIC Where (Description="{nic}") get MACAddress, Manufacturer, NetConnectionID'
                    f' /value', shell=True).decode().strip()
            except UnicodeDecodeError:
                nic_d = check_output(
                    f'wmic NIC Where (Description="{nic}") get MACAddress, Manufacturer, NetConnectionID'
                    f' /value', shell=True).decode("cp866").strip()
            try:
                nicconfig_d = check_output(
                    f'wmic NICCONFIG Where (Description="{nic}") get DHCPServer, IPAddress /value',
                    shell=True).decode().strip()
            except UnicodeDecodeError:
                nicconfig_d = check_output(
                    f'wmic NICCONFIG Where (Description="{nic}") get DHCPServer, IPAddress /value',
                    shell=True).decode("cp866").strip()
            nic_info[nic.strip()] = dict()
            nic_info[nic.strip()].update({"Product": nic.strip()})
            if nic_d:
                for x in nic_d.splitlines():
                    if x.strip():
                        nic_info[nic.strip()].update({
                            x.strip().split("=")[0].strip(): x.strip().split("=")[1].strip()
                        })
            if nicconfig_d:
                for x in nicconfig_d.splitlines():
                    if x.strip():
                        nic_info[nic.strip()].update({
                            x.strip().split("=")[0].strip(): x.strip().split("=")[1].strip()
                        })
    return nic_info if nic_info else False


wmic_info = ""


def print_wmic(part, dict_info):
    global wmic_info
    synonyms = {"ComputerName": "Имя компьютера", "Caption": "Название", "InstallDate": "Дата установки",
                "LastBootUpTime": "Время последней загрузки", "Version": "Версия",
                "WindowsDirectory": "Директория Windows", "TimeZone": "Часовой пояс", "UserName": "Имя пользователя",
                "Manufacturer": "Производитель", "Name": "Название", "Product": "Изделие",
                "MaxClockSpeed": "Максимальная тактовая частота", "SocketDesignation": "Название сокета",
                "NumberOfPhysicalProcessors": "Количество физических процессоров", "VideoProcessor": "Видеопроцессор",
                "NumberOfLogicalProcessors": "Количество логических процессоров", "Capacity": "Емкость",
                "AdapterRAM": "Оперативная память адаптера", "CurrentRefreshRate": "Текущая частота обновления",
                "Resolution": "Разрешение", "TotalPhysicalMemory": "Общий объем физической памяти", "Socket": "Сокет",
                "ConfiguredClockSpeed": "Настроенная тактовая частота", "PartNumber": "Номер партии",
                "SerialNumber": "Серийный номер", "DeviceID": "Идентификатор устройства", "MediaType": "Тип носителя",
                "FirmwareRevision": "Ревизия прошивки", "Partitions": "Разделы", "Size": "Объем", "Drive": "Диск",
                "VolumeName": "Имя тома", "VolumeSerialNumber": "Серийный номер тома", "MACAddress": "MAC-адрес",
                "NetConnectionID": "Идентификатор сетевого подключения", "DHCPServer": "DHCP-сервер",
                "IPAddress": "IP-адрес", "BuildNumber": "Номер сборки", "ID": "Идентификатор", "Status": "Статус",
                "DefaultIPGateway": "IP-адрес шлюза по-умолчанию", "DNSHostName": "DNS Имя хоста",
                "IPv4Address": "IPv4-адрес", "IPv6Address": "IPv6-адрес", "IPSubnet": "Маска подсети",
                "ServiceName": "Название службы", "CurrentBuild": "Текущая сборка", "UBR": "Номер версии",
                "RegisteredOwner": "Имя пользователя", "ActivateKey": "Ключ активации",
                "SystemBiosVersion": "Версия Bios системы", "BIOSVendor": "Производитель", "BIOSVersion": "Версия",
                "BIOSReleaseDate": "Дата выпуска релиза", "ShutdownTime": "Время выключения", "ProductName": "Название",
                "EditionID": "Идентификатор редакции", "DisplayVersion": "Версия для отображения",
                "SystemManufacturer": "Производитель", "SystemProductName": "Название сокета",
                "CoreCount": "Количество ядер", "ProcessorNameString": "Название", "Identifier": "Идентификатор",
                "VendorIdentifier": "Производитель", "~MHz": "Тактовая частота", "Vendor": "Производитель",
                "Model": "Модель", "Revision": "Ревизия", "Description": "Название",
                "NetCfgInstanceId": "Идентификатор", "DhcpDefaultGateway": "Шлюз по-умолчанию",
                "DhcpIPAddress": "IP-адрес"}
    part += f'{"-" * 50}\n'
    for key in dict_info:
        if type(dict_info[key]) == dict:
            for item in dict_info[key]:
                part += f'{synonyms[item]}: {dict_info[key][item]}\n'
            part += "\n"
        else:
            part += f'{synonyms[key]}: {dict_info[key]}\n'
    print(part)
    wmic_info += f'{part}\n'


def main():
    global wmic_info
    t = time.monotonic()
    document = Document()
    document.add_heading(f'Сводная информация о компьютере: {node()}')

    if os_info := winreg_os():
        print_wmic("Информация об операционной системе\n", os_info)
    else:
        if os_wmic := wmic_os():
            print_wmic("Информация об операционной системе\n", os_wmic)
    if bios_info := bios_winreg():
        print_wmic("Информация о BIOS\n", bios_info)
    else:
        if wmic_bios := bios_wmic():
            print_wmic("Информация о BIOS\n", wmic_bios)
    if mb_info := motherboard_winreg():
        print_wmic("Информация о материнской плате\n", mb_info)
    else:
        if wmic_mb := motherboard_wmic():
            print_wmic("Информация о материнской плате\n", wmic_mb)
    if memory_info := memory_wmic():
        print_wmic("Информация об оперативной памяти\n", memory_info)
    else:
        if mem_wmi := memory_wmi():
            print_wmic("Информация об оперативной памяти\n", mem_wmi)
    if cpu_info := cpu_winreg():
        print_wmic("Информация о процессоре\n", cpu_info)
    else:
        if wmic_cpu := cpu_wmic():
            print_wmic("Информация о процессоре\n", wmic_cpu)
    if gpu_info := gpu_wmic():
        print_wmic("Информация о видеокарте\n", gpu_info)
    else:
        if wmi_gpu := gpu_wmi():
            print_wmic("Информация о видеокарте\n", wmi_gpu)
    if drive_info := hdd_ssd_wmic():
        print_wmic("Информация о HDD и SSD\n", drive_info)
    else:
        if wmi_drive := hdd_ssd_wmi():
            print_wmic("Информация о HDD и SSD\n", wmi_drive)
    if cd_rom_info := cdrom_wmic():
        print_wmic("Информация о CD/DVD-ROM\n", cd_rom_info)
    else:
        if wmi_cdrom := cdrom_wmi():
            print_wmic("Информация о CD/DVD-ROM\n", wmi_cdrom)
    if nic_info := nic_winreg():
        print_wmic("Информация о физических сетевых интерфейсах\n", nic_info)
    else:
        if wmic_nic := nic_wmic():
            print_wmic("Информация о физических сетевых интерфейсах\n", wmic_nic)

    document.add_paragraph(wmic_info)
    document.save(f'{node()}.docx')
    print(f"Собранная информация сохранена в файл: {node()}.docx")
    print(f'\nВремя работы скрипта: {time.monotonic() - t} с.')


if __name__ == "__main__":
    main()

А теперь, протестируем скорость его работы.

002.png


Что ж, скорость работы получилась удовлетворительной. Конечно, не так быстро, как чистый скрипт с winreg, но и гораздо быстрее, чем скрипты использующие другие библиотеки.

А на этом мы закончим статьи о получении информации об ОС и железе в Windows.

Спасибо за внимание. Надеюсь, данная информация будет вам полезна
 

Вложения

  • merge_sys_info.zip
    6 КБ · Просмотры: 102
  • other_win_merge.zip
    3,7 КБ · Просмотры: 99
Последнее редактирование модератором:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!