В нескольких прошлых выпусках этой статьи я продемонстрировал различные приемы использования Windows PowerShell для сбора инвентаризационной информации о компьютерах. В этом выпуске я соберу все в готовое к применению средство, которое может собирать информацию любого рода от инструментария управления Windows (Windows Management Instrumentation – WMI).
И это средство будет разработано, чтобы работать либо с текстовым списком имен компьютеров, либо с именами компьютеров, запрошенными от Active Directory.
Изучение средства
Я начну с самого сценария (см. рис. 1), проходя через элементы структуры и смотря на некоторые из используемых в нем приемов. Некоторые из этих приемов могут показаться странными или неуместными, но я собираю их здесь, чтобы продемонстрировать весь спектр используемых интересных приемов.
Рис. 1. Сценарий
1. function Get-WmiInventory {
2. param (
3. $wmiclass = "Win32_OperatingSystem"
4. )
5. PROCESS {
6. $ErrorActionPreference = "SilentlyContinue"
7. $computer = $_
8. trap {
9. $computer | out-file c:\errors.txt -append
10. set-variable skip ($true) -scope 1
11. continue
12. }
13. $skip = $false
14. $wmi = Get-WmiObject -class $wmiclass -computer $computer -ea stop
15. if (-not $skip) {
16. foreach ($obj in $wmi) {
17. $obj | Add-Member NoteProperty ComputerName $computer
18. write $obj
19. }
20. }
21. }
22. }
В строке 1 можно увидеть, что функция именуется Get-WmiInventory. Прямо под этим я определяю входной параметр, именуемый $wmiclass, и даю ему значение по умолчанию "Win32_OperatingSystem". Блок сценария PROCESS указывает, что это функция фильтрации, разработанная для принятия коллекции имен компьютеров с конвейера – чуть ниже можно будет увидеть, как я передаю информацию функции.
Строка 6 отключает нормальное поведение сообщения об ошибках интерпретатора команд, поскольку я хочу предоставить мою собственную регистрацию ошибок. А строка 7 просто записывает текущее имя компьютера (как оно передано по конвейеру в функцию) в переменную $computer.
Вопросы и ответы по Windows PowerShell.
В. Могу ли я использовать Windows PowerShell для управления Windows Server 2008 Server Core?
О. Безусловно. Да, читатели, вероятно, слышали, что Windows PowerShell нельзя установить на Server Core, поскольку Server Core сейчас не поддерживает .NET Framework, требуемую интерпретатором команд. Но это не проблема. Многие разумные администраторы не устанавливают на своих серверах того, что устанавливать не обязательно, и Windows PowerShell – не исключение. Вместо этого можно установить Windows PowerShell на своем клиентском компьютере и использовать его для удаленного управления Server Core с помощью таких технологий, как инструментарий управления Windows (WMI), Active Directory и многих других. Например, можно легко управлять большинством аспектов Active Directory на контроллере доменов, основанном на Server Core, не вылезая из-за своего стола.
Теперь перейдем к строке 13, где я создал переменную, именуемую $skip, и установил ее на логическое значение False (подробнее об этом чуть позже). Затем в строке 14 я пытаюсь записать желаемую информацию WMI с текущего компьютера, используя командлет Get-WmiObject. Обратите внимание, что я указал параметр –ErrorAction (или –EA), который указывает интерпретатору команд создать исключение, если запись WMI заканчивается сбоем по какой бы то ни было причине.
В строке 15 проверяется, содержит ли еще False переменная $skip. Если да, то в строке 16 перечисляется то, что вернулось от WMI, и к каждому объекту WMI добавляется (в строке 17) свойство ComputerName. Таким образом, когда сценарий возвращает объекты WMI от нескольких компьютеров, каждый из них помечается именем родительского компьютера в подходящем свойстве. Строка 18 выдает каждый из объектов на конвейер, чтобы другой командлет мог разобраться с ними или чтобы подсистема форматирования интерпретатора команд могла принять управление для отображения некоторых из свойств объекта.
А если что-то пойдет не так? Поскольку я указал –EA Stop, интерпретатор команд исполнит ловушку в строке 8. Сперва он запишет имя компьютера в текстовый файл, чтобы у нас имелся журнал имен компьютеров, на которых инвентаризация закончилась сбоем. Затем в строке 10 переменная $skip установлена на логическое значение True («Истина»). Это предотвращает попытку сценария выдать что-нибудь в строке 15 – если бы я не сделал этого, то в каждом случае неудачной инвентаризации компьютера следовала бы попытка снова выдать информацию об инвентаризации предыдущего компьютера.
В строке 10 используется другой прием для установки переменной: сама ловушка – это область действия закрытой переменной, и она не содержит переменную $skip. Переменная $skip, которая мне нужна, происходит от родительской области действия ловушки, одним уровнем выше. Командлет Set-Variable позволяет мне изменить переменную, используя параметр -scope и указывая, что $skip, в которой я заинтересован, находится уровнем выше. Также обратите внимание, что при использовании Set-Variable в имени переменной отсутствует символ $ в начале.
Пробный прогон
Простым способом протестировать этот сценарий является простая передача имени одного компьютера следующим образом:
"localhost" | Get-WmiInventory
Поскольку я не указал имя класса WMI, используется значение по умолчанию Win32_OperatingSystem. Чтобы указать иной класс, сделайте следующее:
"localhost" | Get-WmiInventory "Win32_LogicalDisk"
Результаты показаны на рис. 2. А если нужно включить больше имен компьютеров, то просто делается их список с разделением запятыми, вот так:
"localhost","server2","client17" |
Get-WmiInventory "Win32_LogicalDisk"
Рис. 2. Результаты Get-WmiInventory
Компьютеры скопом
Указание имен отдельных компьютеров довольно утомительно, если список велик. При наличии списка имен компьютеров в текстовом файле (одно имя компьютера на строку) эти имена можно прямо передать функции инвентаризации, сделав следующее:
Get-Content c:\names.txt | Get-WmiInventory "Win32_Service"
В другом приеме используется командлет Get-QADComputer, который предоставляется как часть бесплатных командлетов Active Directory, доступных на quest.com/powershell. Здесь необходимо установить комадлеты Active Directory, откройте Windows PowerShell и выполните:
Add-PSSnapin Quest.ActiveRoles.ADManagement
Выполните Get-QADComputer, чтобы получить все компьютеры из Active Directory. Но учтите, что в большом домене на это может уйти немало времени! Можно запустить справку Get-QADComputer, чтобы увидеть некоторые из параметров, доступные для фильтрации списка компьютеров, такие как запись только тех компьютеров, которые находятся в конкретном структурном подразделении. Также необходимо внести небольшое изменение в сценарий, изменив строку 7:
$computer = $_
$computer = $_.Name
Это необходимо, поскольку объект, созданный Get-QADComputer, сохраняет имя компьютера в свойстве Name («Имя»), а не как простой строковый объект.
Что с ним делать?
Выдаваемые этим сценарием результаты по умолчанию будут принимать ту форму, которую подсистема форматирования Windows PowerShell создаст по умолчанию. Например, класс Win32_OperatingSystem – это небольшое подмножество (только шесть свойств) информации, реально доступной от этого класса. Результаты этого сценария можно передать любому стандартному командлету интерпретатора команд для их модификации. Так, для отображения номера сборки и информации о пакете обновления вместе с именами компьютеров сделайте следующее
Get-Content c:\names.txt | Get-WmiInventory |
Format-List BuildNumber,ServicePackMajorVersion,ComputerName
Если необходимо получить инвентаризацию установленных служб и создать таблицу HTML, сделайте следующее:
Get-Content c:\names.txt | Get-WmiInventory "Win32_Service" |
ConvertTo-HTML | Out-File c:\services_inventory.html
Ну а если необходимо получить полную инвентаризацию информации о логическом диске и записать ее в файл значений, разделенных запятыми (CSV), сделайте следующее:
Get-Content c:\names.txt |
Get-WmiInventory "Win32_LogicalDisk" | Export-CSV c:\disks.csv
Обратите внимание, что поскольку функция Get-WmiInventory создает объекты, а не простой текст, интерпретатор команд может сделать довольно многое, чтобы помочь в получении данных в той форме, в которой они нужны, идет ли речь о статистическом определении тенденций, отчетах по управлению или просто быстром просмотре ключевой информации.
Продвигаясь дальше
Слабостью в текущем сценарии является то, что он извлекает все объекты WMI из указанного класса. В случае некоторых классов данных может быть слишком много. Я, как правило, предпочитаю ограничить Win32_LogicalDisk, чтобы можно было извлечь только локальные диски, имеющие свойство DriveType, равное 3. Я могу легко изменить сценарий, чтобы он включал критерии фильтрации подобным образом – переделанный сценарий показан на рис. 3. Для вызова этого нового сценария я использую следующую команду:
Get-Content c:\names.txt |
Get-WmiInventory "Win32_LogicalDisk" "DriveType='3'"
Рис. 3. Переделанный сценарий для поддержки фильтрации
1. function Get-WmiInventory {
2. param (
3. $wmiclass = "Win32_OperatingSystem"
4. $filter = ""
5. )
6. PROCESS {
7. $ErrorActionPreference = "SilentlyContinue"
8. $computer = $_
9. trap {
10. $computer | out-file c:\errors.txt -append
11. set-variable skip ($true) -scope 1
12. continue
13. }
14. $skip = $false
15. $wmi = Get-WmiObject -class $wmiclass -computer $computer -ea stop –filter $filter
16. if (-not $skip) {
17. foreach ($obj in $wmi) {
18. $obj | Add-Member NoteProperty ComputerName $computer
19. write $obj
20. }
21. }
22. }
23. }
Изменения в строках 4 и 15 просто собирают новый параметр, именуемый $filter, и передают его параметру –filter объекта Get-WmiObject. При вызове функции параметр $filter является вторым, так что он передается как второе значение после имени класса WMI. Для подстройки данной функции под конкретную среду можно сделать еще многое, но некоторых вещей следует избегать:
- Не заставляйте функцию выдавать свои результаты куда-либо, кроме конвейера, что проделывается в строке 19 переделанного сценария. Другими словами, не заставляйте функцию выдавать информацию в файл. Вместо этого возьмите то, что функция выдала на конвейер, и отправьте это командлету, такому как Out-File, который перемещает результаты в файл или на иной носитель. Это гарантирует, что функция сохранит свою гибкость.
- Не отфильтровывайте информацию внутри функции – скажем, путем удаления свойств объектов WMI или выдачи только подмножества объектов. Это также уменьшит гибкость функции для будущих случаев использования. Вместо этого, если вся выдаваемая информация не нужна, передавайте ее командлету Format или Select-Object, чтобы можно было получить только информацию, необходимую текущей задаче.
- Не добавляйте дополнительные задачи к функции. Держите каждую функцию однозадачной вместо того, чтобы создавать суперфункции, которые делают много всего. При наличии сложного процесса выполняйте его, создавая каждую выделяющуюся задачу как отдельную функцию и передавая информацию между ними. Это оставляет каждую функцию более гибкой, простой в обслуживании и гораздо более простой в отладке.
Универсальные средства «сделай сам»
Хотя подобный сценарий не является заменой системы управления настройкой с широкими возможностями, такой как System Center Configuration Manager, он предоставляет простой способ инвентаризации избранной информации с набора удаленных компьютеров. Этот сценарий является хорошим примером одной из вещей, в которых Windows PowerShell идеален: предоставления быстрого, импровизированного решения для проблем, которые корпорация Майкрософт не предвидела при создании Windows или иного продукта, используемого пользователем.
Поскольку данный конкретный сценарий использует WMI, он работает с компьютерами под управлением систем вплоть до Windows NT 4.0 – хотя сам Windows PowerShell не может быть установлен на настолько старой системе! А поскольку многие продукты Майкрософт предоставляют информацию об управлении через WMI, то информацию можно собирать от нескольких продуктов. Мне нравится использовать средство проводника WMI (бесплатное средство такого рода можно найти на scriptinganswers.com в "Зоне средств") для просмотра информации WMI, доступной на компьютере, а затем сценарий, подобный показанному здесь, для сбора этой информации с нескольких компьютеров.