Обновление утилиты CheckBootSpeed до версии 2.0 было в немалой степени обусловлено желанием собрать сведения о дефрагментации SSD на ПК с Windows 8. Чтобы понять, есть ли в системе твердотельный накопитель, я на скорую руку добавил в скрипт сбора информации такой фрагмент:
foreach ($d in Get-Partition) {$d.AccessPaths, $d.DiskId, ""}
Один из путей доступа выводилmv букву диска, а его идентификатор позволял определить модель (в крайнем случае, с помощью поисковиков).
C:\ \\?\Volume{f2d14198-3e1e-11e3-824e-806e6f6e6963}\ \\?\scsi#disk&ven_samsung&prod_ssd_840_pro_seri#4&1a6bca51&0&000000#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
Выглядит результат некрасиво, и я давно хотел доработать скрипт.
Толчком же к этому стала подготовка серии материалов к публикации – мне снова нужна информация о ваших ПК! :) Поэтому сегодня я сначала покажу разные командлеты PowerShell и общие приемы работы с этой консолью, которые я использовал для предлагаемого вам скрипта. Но прежде я хочу сделать небольшое отступление.
Созданный мной скрипт решал поставленную задачу и отлично работал. Но я все же слабо владею PowerShell, и поэтому попросил посмотреть свой код эксперта по этому скриптовому языку – Вадимса Поданса. Он внес в него ряд изменений, после которых я бы сформулировал разницу между пользователем и экспертом так: оба могут решить поставленную задачу, но эксперт сделает это грамотнее, надежнее и быстрее.
Ниже вы увидите несколько подтверждений этому тезису. Теперь к делу!
[+] Сегодня в программе
- Информация о дисках и разделах
- Выбор отображаемых свойств
- Перебор объектов
- Изменение заголовков столбцов таблицы
- Преобразование и подсчет свойств (калькулятор)
- Классы WMI
- Подсчет объектов
- Цикл
- Определение версии операционной системы
- Определение изготовителя ПК
- Выполнение скриптов PowerShell
- Нужна ваша помощь!
Информация о дисках и разделах
Командлеты: Get-PhysicalDisk, Get-Disk, Get-Partition
Эти командлеты модуля Storage работают только в Windows 8 и более новых ОС (решение для Windows 7 будет ниже в статье). Их названия говорят сами за себя, но я все же считаю нужным напомнить общую информацию о дисках и разделах, а также прояснить некоторые моменты.
- Get-PhysicalDisk позволяет получить информацию о физических дисках, т.е. характеристики устройств.
- Get-Disk выводит сведения о дисках на логическом уровне с точки зрения операционной системы.
- Get-Partition отображает информацию о разделах на всех дисках.
Разницу между первыми двумя командлетами проще всего объяснить на примере моего ПК. У меня два внешних USB-диска объединены в дисковое пространство. Get-PhysicalDisk показывает два физических диска, а Get-Disk – один (как и файловый менеджер). На рисунке ниже эти диски выделены желтым.
Информации вроде много, no подана она не очень удачно. Давайте посмотрим, что можно улучшить:
- Убрать лишние сведения и добавить нужные (тип накопителя и разметки дисков, наличие загрузочных файлов на разделе).
- Изменить названия заголовков таблицы и ширину столбцов (например, у номеров и букв разделов слишком широкие столбцы).
- Отразить четкую связь между диском и его разделами.
Дальше я буду разбирать именно эти три командлета, а владельцы Windows 7 могут попробовать те же приемы на dir.
Выбор отображаемых свойств
Командлеты: Format-List, Format-Table и Sort-Object
Выполнение любого командлета без параметров позволяет увидеть лишь некоторые свойства. Их полный список можно вывести, перенаправив вывод по конвейеру в командлет Format-List.
Get-PhysicalDisk | fl *
Любое свойство можно вывести в таблице с помощью командлета Format-Table, выровняв столбцы по ширине содержимого. Давайте отобразим нужное и уберем лишнее:
Get-PhysicalDisk | ft -AutoSize DeviceId,Model,MediaType,BusType,Size
В PowerShell Windows 8 обнаружилось решение задачи, которое я безуспешно искал со времен Windows 7 для утилиты CheckBootSpeed. Теперь с помощью командлета Get-PhysicalDisk можно определить тип накопителя – SSD или HDD!
DeviceId Model MediaType BusType Size -------- ----- --------- ------- ---- 2 TOSHIBA MK7559GSXP HDD SATA 750156374016 0 Samsung SSD 840 PRO Series SSD SATA 256060514304 1 KINGSTON SH103S3120G SSD SATA 120034123776 4 Transcend UnSpecified USB 319169757184 3 SNA-DC/U UnSpecified USB 249376538624
В комментариях Александр Сентюрин подметил, что диски идут не по порядку, и посоветовал отсортировать их. Это делается с помощью командлета Sort-Object — после сортировки по свойству DeviceID диски выстроятся в таблице начиная с нулевого.
Get-PhysicalDisk | sort DeviceId | ft -AutoSize DeviceId,Model,MediaType,BusType,Size
Я не случайно вывел в результатах BusType — тип шины! Основным диском в моем планшете служит eMMC SSD, и по сути – это карта памяти (вторая вставлена в слот для увеличения дискового пространства).
DeviceId Model MediaType BusType Size -------- ----- --------- ------- ---- 0 MBG4GA SSD SD 31226593280 1 SD SSD SD 31611420672
Я уже писал об этом в обзоре платформы Clover Trail и даже показывал там, что диспетчер задач Windows 8 в курсе типа накопителя. Любопытно, что в Windows 8.1 он уже показывает модель диска, что более конкретно, но в то же время скрывает истинную натуру SSD. PowerShell же срывает покровы :)
Кстати, размер дисков получился в байтах, но к этому я вернусь чуть позже. Аналогичные команды для Get-Disk и Get-Partition попробуйте самостоятельно или смотрите, какие свойства выбрал я.
Перебор объектов
Командлет: ForEach-Object
В данном случае объекты — это диски. Задача формулируется примерно так: отобразить сведения о диске, затем информацию о его разделах, и так для каждого диска.
Get-Disk | ForEach-Object { $_ | Format-Table -AutoSize Number,FriendlyName,Size,PartitionStyle Get-Partition -DiskNumber $_.number | Format-Table -AutoSize ` PartitionNumber,DriveLetter,Size,Offset,IsBoot,IsSystem,Type }
Этот код собирает информацию о всех дисках с помощью Get-Disk и перенаправляет ее командлету ForEach-Object для перебора. Для текущего объекта $_ выводится информация о дисках, а затем — о разделах с помощью Disk-Partition. У него параметр -Number принимает свойство $_.Number, т.е. номер текущего диска.
Number FriendlyName Size PartitionStyle ------ ------------ ---- -------------- 0 Samsung SSD 840 PRO Series 256060514304 MBR PartitionNumber DriveLetter Size Offset IsBoot IsSystem Type --------------- ----------- ---- ------ ------ -------- ---- 1 367001600 1048576 False True IFS 2 C 230084837376 368050176 True False IFS
Результат уже похож на правду, но надо сделать понятные заголовки столбцов!
Изменение заголовков столбцов таблицы
Хеш-таблицы | Выражения
Понимая, что цели можно достичь разными способами, я сразу попросил Вадимса подсказать самый короткий. Он навел меня на хеш-таблицы и выражения. В хеш-таблицу заносится пара «свойство – значение», но вместо стандартного имени свойства подставляется выражение, в котором задается нужное имя.
Например, переименование столбцов для первых трех свойств диска делается так:
Get-Disk -Number 0 | ft –AutoSize ` @{Expression={$_.Number};Label="Диск"}, ` @{Expression={$_.FriendlyName};Label="Название"}, ` @{Expression={$_.Size};Label="Размер"}
Здесь $_ обозначает текущий объект, т.е. диск с номером 0, свойства которого мы разбираем. Поэтому $_.Number выводит его номер. Аналогично можно поступить и с другими столбцами, но я остановлюсь на размере.
Преобразование и подсчет свойств (калькулятор)
Тип данных: [int] | Оператор: /
Без параметров командлет Get-Disk отображает столбец Total Size и размер в гигабайтах, но в списке свойств есть только Size в байтах. Дело в том, что PowerShell динамически интерпретирует размер в зависимости от величины, следуя предустановленным правилам форматирования. Можно в них поковыряться, но я покажу, как срезать путь :)
PowerShell может работать калькулятором, причем вполне интеллектуальным. Допустим, переменная $a задает размер в байтах. Это значение можно поделить на 1GB и округлить до целого с помощью типа данных [int]. В примере ниже результатом будет 128.
$a=137438956596 [int]($a/1gb)
Это можно использовать в выражении, указав единицу измерения в столбце. Полный фрагмент скрипта:
Get-Disk -Number 0 | ft –AutoSize ` @{Expression={$_.Number};Label="Диск"}, ` @{Expression={$_.FriendlyName};Label="Название"}, ` @{Expression = {[int]($_.Size/1GB)}; Label = "Размер (GB)"}, @{Expression={$_.PartitionStyle};Label="Разметка"}
Результат выглядит так:
Диск Название Размер (GB) Разметка ---- -------- ----------- -------- 0 Samsung SSD 840 PRO Series 238 MBR
Аналогично можно преобразовать таблицу командлета Get-Partition.
Показанные выше командлеты работают в Windows 8 и более новых ОС, но надо решить задачу и для Windows 7.
Классы WMI
Командлет: Get-WmiObject | Классы Win32: Win32_DiskDrive и Win32_DiskPartition
В Windows 7 нет таких удобных командлетов, как в Windows 8, поэтому точно такого же представления информации не достичь. Но с помощью командлета Get-WmiObject можно извлечь большинство сведений из классов WMI, и в первую очередь нас интересуют указанные в подзаголовке.
Посмотреть свойства каждого класса вы можете самостоятельно. К сожалению, они не позволяют сопоставить разделы с буквами дисков. Поэтому буквы придется выводить отдельно с помощью класса Win32_Volume и ориентироваться на размер томов.
Давайте посмотрим, как это работает.
Подсчет объектов
Командлет: Measure-Object
Для начала нужно определить число дисков в системе, перенаправив информацию о дисках командлету Measure-Object.
(Get-WmiObject Win32_DiskDrive | Measure-Object).count-1
Тонкость в том, что нумерация дисков начинается с нуля, поэтому для перебора нужно отнять от их числа единицу. Чуть ниже вы увидите еще один способ.
Цикл
Командлет: For
Число дисков можно задать в цикле перебора с помощью for, и у меня получилась такая вполне рабочая конструкция.
$Drives = Get-WmiObject Win32_DiskDrive $DiskInfo = for ($i = 0; $i -le (($Drives | Measure-Object).count-1); $i++) { $Drives | Where-Object {$_.Index -eq $i} | ft -AutoSize Index,Caption,Size Get-WmiObject Win32_DiskPartition | Where-Object {$_.DiskIndex -eq $i} | ft -AutoSize ` Index,Size,StartingOffset,BootPartition,Type } $DiskInfo
Номер диска у классов Win32_DiskDrive и Win32_DiskPartition обозначается разными свойствами — Index и DiskIndex соответственно. А остальное читается легко. Сначала выбирается диск 0 и выводится информация по нему, а затем – по его разделам.
Увидев этот код Вадимс сначала посоветовал работать с классом напрямую, чтобы использовать фильтр вместо Where-Object.
Get-WmiObject Win32_DiskPartition -Filter "DiskIndex = '$i'"
Этот подход надежнее и позволяет избежать лишнего этапа на конвейере. Но он работает только при обращении к классу напрямую, как в случае с разделами, но не проходит, если класс уже помещен в переменную ($DiskDrive). Можно избавиться от нее, но тогда получается два запроса к Win32_DiskDrive, что неэффективно с точки зрения производительности.
В результате Вадимс показал мне решение, вокруг да около которого я очень долго ходил. Он элегантно поместил класс WMI в массив (первая строка) и воспользовался его свойством Count для подсчета дисков.
$DiskDrive = @(Get-WmiObject Win32_DiskDrive) $DiskInfo = for ($index = 0; $index -lt $DiskDrive.Count; $index++) { $DiskDrive | Where-Object {$_.index -eq $index} | Format-Table -AutoSize ` Index,Caption,Size Get-WmiObject Win32_DiskPartition -Filter "DiskIndex = '$index'" | Format-Table -AutoSize ` PartitionNumber,Size,StartingOffset,BootPartition,Type } $DiskInfo
Определение версии операционной системы
Класс .NET: [environment] | Тип данных: [double]
Windows 7 и Windows 8 – это маркетинговые версии ОС, а «техническую» можно посмотреть, набрав в консоли winver.
В PowerShell ее можно извлечь массой способов, и самый распространенный:
(Get-WmiObject Win32_OperatingSystem).Version
Задача сводится к превращению текстовой строки 6.3.9600 в дробное число вида 6.3. Я понятия не имел, как это сделать, и нагуглил решение, показывать которое я не буду :) Да, оно работало, но Вадимс посоветовал не использовать WMI для таких задач, а обратиться к классу Environment в .NET Framework, на котором построен PowerShell.
[environment]::osversion.Version Major Minor Build Revision ----- ----- ----- -------- 6 3 9600 0
Вадимс объяснил, что такой подход значительно ускоряет запрос, потому что при запуске PowerShell эти классы уже загружены. В подтверждение тезиса он сравнил время выполнения команд с помощью командлета Measure-Command. Получилось в сто раз быстрее!
PS C:\> 1..5 | %{(measure-command {(Get-WmiObject Win32_OperatingSystem).OSVersion}).TotalMilliseconds} 45,5833 35,9619 25,5198 35,6166 16,0488 PS C:\> 1..5 | %{(measure-command {[environment]::osversion.version}).TotalMilliseconds} 0,7387 0,0717 0,0675 0,064 0,0354
В десятичную дробь с одним знаком после запятой (6.3) это превращается так:
[double][environment]::osversion.version.tostring(2)
Две цифры отсекаются с помощью tostring, а преобразовать в дробное число помогает тип данных [double].
Определение изготовителя ПК
Командлет: Get-WmiObject | Класс: Win32_ComputerSystem
Наберите в консоли msinfo32. Это, кстати, еще один способ посмотреть версию ОС :)
Эти сведения закладываются в BIOS изготовителем устройства, поэтому YMMV. Они должны быть на планшетах и ноутбуках, которые меня интересуют в первую очередь.
$PC = Get-WmiObject Win32_ComputerSystem if ($PC.Manufacturer.Contains("filled") -or $PC.Manufacturer.Contains("manufacturer")) { $PCInfo = "Модель ПК не определена" } else { $PCInfo = $PC.manufacturer,$PC.model } $PCInfo
Выполнение скриптов PowerShell
Если «батник» запустит даже самый неопытный пользователь, то с выполнением скриптов PowerShell в Windows все намного строже. Да, можно снять ограничения политики:
Set-ExecutionPolicy Bypass
Но в консоли все равно придется запускать скрипты так:
.\Script.ps1
Однако можно пойти другим путем:
powershell.exe -ExecutionPolicy Bypass -file Script.ps1
Этот способ работает в консоли PowerShell, командной строке, командных файлах, планировщике заданий и т.д. Именно его я задействовал для своего скрипта, который предлагаю вам запустить.
Нужна ваша помощь!
Как я сказал в начале статьи, мне нужно собрать сведения о различных ПК, но не со всех подряд. Необходимо выполнение двух условий:
- Windows была предустановлена на ПК изготовителем. В большинстве случаев — это ноутбук или планшет.
- С основного диска не удалялись служебные разделы. Если вы изменяли разделы с данными – ок. Но если вы удалили, например, раздел с резервным образом или вообще отформатировали диск – информация для меня бесполезна.
Если ваш ПК соответствует этим критериям:
- Скачайте архив и распакуйте его в любую папку.
- Щелкните правой кнопкой мыши на файле start.cmd и выберите Запуск от имени администратора. По окончании работы скрипта результаты сохранятся в той же папке в текстовом файле, который откроется в блокноте.
- Скопируйте весь текст и вставьте в комментарий!
Жду ваших результатов :) Спасибо!
Если у вас есть вопросы по скрипту, я попробую ответить в комментариях. А что вы в последний раз автоматизировали скриптом дома или по работе?
Алексей Г
Ноутбук DELL — оригинал.
Раздел Буква Размер (MB) Смещение (KB) Установлена ОС Файлы загрузки Тип
—— —— ———— ————- ————— ————— —
1 500 1024 False True System
2 40 513024 False False Unknown
3 128 553984 False False Reserved
4 490 685056 False False Recovery
5 C 468369 1186816 True False Basic
6 7411 480796672 False False Recovery
Назначение раздело 1 и 3 — понятно. Раздел 2 определяется в оснастке Управление дисками на раздел OEM. Он пустой) На разделе 4 — среда WinRE — модифицированная с «штучками» от DELL (в виде мастеров). На разделе 6 хранится образ предустановленной системе (зарегистрированный в среде WINRE — видно по reagentc /info ). Образа для Восстановления без удаления файлов (recimg) нет.
Vadim Sterkin
Алексей, фабричный образ д.б. связан с refresh/reset, но если сделать образ recimg, будет связан он.
Алексей
Здравствуйте, Вадим! В скаченном файле start.cmd вот такая строка — echo ‘Ў®а ᢥ¤ҐЁ©…
Это так и должно быть?
Vadim Sterkin
Алексей, кодировку DOS поставьте… в WordPad.
sell panic
LENOVO
20266
Майкрософт Windows 8.1 для одного языка
Андрей Войтюк
Dell Inc.
Inspiron 3521
Майкрософт Windows 10 Корпоративная