Upload
andrey-markin
View
1.211
Download
9
Embed Size (px)
DESCRIPTION
Citation preview
Оглавление
Введение......................................................................................................................................2
Часть 1. Получаем статус служб................................................................................................2
Часть 2. Остановка, запуск и пауза..........................................................................................15
Часть 3. Конфигурируем службы с помощью WMI и CIM.......................................................26
Часть 4. Изменение служб с помощью WMI............................................................................33
Часть 5. CIM-командлеты..........................................................................................................38
Часть 6. Служебные учетные записи.......................................................................................44
Введение
Джефри Хикс, гуру PowerShell, затеял как-то серию статей на сайте 4 sysops . com , в которых рассмотрел основные аспекты управления службами Windows с помощью PowerShell. В после внимания автора оказалось не только использование командлетов PowerShell 2.0, но и новых командлетов из PowerShell 3.0, которые значительно упрощают работу с Windows Server 2012. Я готовил перевод этих статей и выкладывал в блог на Хабрахабре. Здесь же я решил объединить все материалы в один документ, который можно скачать и фактически использовать как книжку. Приятного и полезного чтения.
Часть 1. Получаем статус служб
В первой части мы рассмотрим следующие вопросы управления службами Windows:● Получаем статус службы на локальном компьютере
● Получаем статус службы на удаленном компьютере
● Осуществляем фильтрацию служб (например, остановленные службы)
● Зависимые службы
Обозначим начальные условия: Вы работаете под Windows 7 и выше и у Вас имеются права
администратора. Все команды рекомендуются выполнять в лабораторной или виртуальной среде,
перед тем, как применять в “полевых условиях”.
ПОЛУЧАЕМ СТАТУС СЛУЖБЫ
Давайте начнем с того, что просто получим статус всех служб, запущенных на локальном
компьютере. Используем для этого командлет Get-Service.
PS C:\> get-service
PowerShell, как правило, не чувствителен к регистру. Вывод приведен на скриншоте ниже.
Каждая строка представляет собой объект службы (service object).Каждый сервисный объект, как
правило, имеет свои свойства. Вы можете открыть их, просто передав эти объекты в другую
команду, Get-Member.
PS C:\> get-service | get-member
Результаты приведены на скриншоте ниже.
Параметр Typename сверху говорит о том, что за объект перед нами; в данном случае это
System.ServiceProcess.ServiceController. На скриншоте также обведены свойства объекта. Это
атрибуты, которые описывают этот тип объекта. Хотя большинство из них не используются при
отображении по умолчанию, вы можете использовать их, если вы их знаете.
Например, нам интересно посмотреть информацию только о Windows Update. Через Get-Service
получим информацию только о некоторых ее свойствах.
PS C:\> get-service wuauserv | select Displayname,Status,Can*
DisplayName : Windows Update
Status : Stopped
CanPauseAndContinue : False
CanShutdown : False
CanStop : False
Как я узнал, что могу напечатать имя службы? Посмотрел с помощью Get-Service.
PS C:\> help get-service
Вы можете получить полную справочную информацию, напечатав:
PS C:\> help get-service –full
Информацию о службе можно получить по ее имени или даже начальным буквам имени.
PS C:\> get-service wi*
Status Name DisplayName
------ ---- -----------
Stopped WiaRpc Still Image Acquisition Events
Running WinDefend Windows Defender Service
Running WinHttpAutoProx... WinHTTP Web Proxy Auto-Discovery Se...
Running Winmgmt Windows Management Instrumentation
Running WinRM Windows Remote Management (WS-Manag...
Или если вам удобнее работать с отображаемыми именами, используйте параметр –Displayname.
PS C:\> get-service -DisplayName "windows a*"
Status Name DisplayName
------ ---- -----------
Stopped AllUserInstallA... Windows All-User Install Agent
Running AudioEndpointBu... Windows Audio Endpoint Builder
Running Audiosrv Windows Audio
Я должен использовать имя параметра, чтобы PowerShell воспринимал значения в качестве
отображаемого имени, а не фактического имени службы. Команда будет выглядеть так:
PS C:\> get-service "windows a*"
Параметр –Name можно не печатать.
ПОЛУЧАЕМ СТАТУС СЛУЖБЫ НА УДАЛЕННЫХ КОМПЬЮТЕРАХ
До этого нас интересовало получение информации о статусе служб на локальном компьютере.
Однако управление службами осуществляется на удаленных компьютерах. Если посмотреть
справку по Get-Service, то можно увидеть наличие у этого командлета параметра –
Computername. В данном случае подключение к удаленным компьютерам осуществляется без
включения функции удаленного управления PowerShell. Если вы можете управлять службами,
используя инструменты командной строки (sc.exe или консоль управления Service Manager), вы
можете использовать PowerShell. Давайте взглянем на пример:
PS C:\> get-service spooler -ComputerName novo8
Status Name DisplayName
------ ---- -----------
Running spooler Print Spooler
Любая команда, которую я демонстрировал, можно использовать для передачи удаленному
компьютеру. Даже нескольким компьютерам, если у вас есть соответствующие права на
удаленном компьютере. Если вы используете PowerShell v3, то можно легко выбрать одну службу
на множестве компьютеров.
PS C:\> get-service wuauserv -ComputerName chi-dc01,chi-dc02,chi-dc03
Status Name DisplayName
------ ---- -----------
Running wuauserv Windows Update
Stopped wuauserv Windows Update
Running wuauserv Windows Update
Для наглядности представления отформатируем вывод.
PS C:\> get-service wuauserv -ComputerName chi-dc01,chi-dc02,chi-dc03 | format-table
Name,Status,Machinename -autosize
Name Status MachineName
---- ------ -----------
wuauserv Running chi-dc03
wuauserv Stopped chi-dc02
wuauserv Running chi-dc01
Тот же самый результат, но в PowerShell v2.
PS C:\> 'chi-dc01','chi-dc02','chi-dc03'| foreach {get-service wuauserv -computername $_} |
Format-Table Name,Status,Machinename -AutoSize
Name Status MachineName
---- ------ -----------
wuauserv Running chi-dc01
wuauserv Stopped chi-dc02
wuauserv Running chi-dc03
ОСУЩЕСТВЛЯЕМ ФИЛЬТРАЦИЮ (ИСПОЛЬЗУЯ WHERE-OBJECT)
Фильтрация служб осуществляется с помощью командлета Where-Object (where – сокращение
для командлета). Все, что нам нужно от PowerShell в этом случае, так это получить только те
службы, у которых статус равен “stopped”.
PS C:\> get-service | where {$_.status -eq 'stopped'}
PowerShell получает информацию обо всех службах и передает их (с помощью “|”) в следующую
команду, которая осуществляет просмотр каждого объекта. Если свойство статуса объекта равно
“stopped”, она остается в конвейере (pipeline), в противном случае она из него исключается. В
конце выражение PowerShell отображает те объекты, которые остались в конвейере.
Результаты приведены ниже.
Теперь давайте попробуем найти одну службу на нескольких машинах. Вывод отформатируем в
таблицу.
PS C:\> get-service -computername @('chi-dc01','chi-dc02','chi-dc03') | where {$_.name -eq
'wuauserv'} | format-table Name,Status,Machinename -autosize
Name Status MachineName
---- ------ -----------
wuauserv Running chi-dc02
wuauserv Running chi-dc01
wuauserv Running chi-dc03
Мы даже можем комбинировать запрос отдельных служб с их фильтрацией.
PS C:\> get-service "win*" -comp chi-dc03 | where {$_.status -eq 'running'}
Status Name DisplayName
------ ---- -----------
Running Winmgmt Windows Management Instrumentation
Running WinRM Windows Remote Management (WS-Manag...
Эта команда находит все службы на компьютере CHI-DC03, которые начинаются с ‘WIN’, но
отображает только те, которые запущены.
Также можно сгруппировать объекты по свойству статуса (status property).
PS C:\> $dc03 = get-service -computername chi-dc03 | Group-Object -Property Status
Переменная $dc03 является объектом GroupInfo.
PS C:\> $dc03
Count Name Group
----- ---- -----
64 Running {System.ServiceProcess.ServiceController, Sy...
79 Stopped {System.ServiceProcess.ServiceController, Sy...
Свойство Group представляет собой коллекцию связанных служб.
PS C:\> $dc03.Get(0).group
Написанное выше проще понять, если взглянуть на скриншот.
Что касается меня, то я бы предпочел использовать хеш-таблицу.
PS C:\> $hash = get-service -computername chi-dc03 | Group-Object -Property Status -AsHashTable
PS C:\> $hash
Name Value
---- -----
Running {System.ServiceProcess.ServiceController, Sys...
Stopped {System.ServiceProcess.ServiceController, Sys...
Теперь каждое имя представляет собой свойство в хеш-таблице. Если у вас имеется опыт работы
с PoweShell, вы, возможно, подумываете сделать сделующее:
PS C:\> $hash.running.count
Однако ничего не произойдет. Потому что свойство Status является просто перечислением
(enumeration) для [System.ServiceProcess.ServiceControllerStatus] .NET клас и такие свойства, как
Running и Stopped представляют собой целые числа. PowerShell осуществляет конвертацию, чтобы
представить в более наглядной форме.
PS C:\> $hash = get-service -computername chi-dc03 | Group-Object -Property Status –AsHashTable –
AsString
В чем суть параметра –AsString, на мой взгляд, достаточно очевидно. Теперь работать с хеш-
таблицей стало проще.
PS C:\> $hash.running.count
62
PS C:\> $hash.running[0..3]
Status Name DisplayName
------ ---- -----------
Running ADWS Active Directory Web Services
Running AppHostSvc Application Host Helper Service
Running BFE Base Filtering Engine
Running BrokerInfrastru... Background Tasks Infrastructure Ser...
Следующей задачей на повестке дня является проверка зависимостей сервера (server
dependencies).
Требуемые службы
PowerShell позволяет просто получить статус всех служб, которые требуется для данной службы,
даже на удаленном компьютере.
PS C:\> get-service dns -ComputerName chi-dc03 –RequiredServices
Status Name DisplayName
------ ---- -----------
Running Afd Ancillary Function Driver for Winsock
Running Tcpip TCP/IP Protocol Driver
Running RpcSs Remote Procedure Call (RPC)
Running NTDS Active Directory Domain Services
Параметр –RequiredServices передаст объект в конвейер для каждой требуемой службы. Вы
можете даже пойти дальше и проверить требуемые службы для работы данной службы.
PS C:\> get-service dns -ComputerName chi-dc03 -RequiredServices | select
name,@{name="computername";expression={$_.machinename}} | get-service -RequiredServices
Status Name DisplayName
------ ---- -----------
Running RpcEptMapper RPC Endpoint Mapper
Running DcomLaunch DCOM Server Process Launcher
Параметр –Computername командлета Get-Service возьмет вывод, но только для тех объектов, у
которых есть объект свойство Computername – именно поэтому я использую хеш-таблицу с Select-
Object. Как мы видим проблем со службой DNS на компьютере CHI-DC03 нет.
ЗАВИСИМЫЕ СЛУЖБЫ
Мы можем сделать то же самое с зависимыми службами. Если таковых не имеется, в конвейер
ничего передано не будет.
PS C:\> get-service dns -ComputerName chi-dc03 -DependentServices
PS C:\> get-service lanmanworkstation -ComputerName chi-dc03 -DependentServices
Status Name DisplayName
------ ---- -----------
Stopped SessionEnv Remote Desktop Configuration
Running Netlogon Netlogon
Running Dfs DFS Namespace
Running Browser Computer Browser
Требуемые и зависимые службы также являются частью каждого объекта службы.
PS C:\> get-service rpcss | Select *services
RequiredServices DependentServices
---------------- -----------------
{RpcEptMapper, DcomLaunch} {WwanSvc, wuauserv, WSearch, wscsvc...}
А пока Вы можете получить все зависимости для всех служб, следующая команда
PS C:\> get-service –DependentServices
Это не даст вам особо полезную информацию, поэтому я рекомендую осуществлять запрос по
конкретным службам. Команда работает гораздо лучше PowerShell v3.
PS C:\> get-service dns -comp chi-dc01,chi-dc03 -RequiredServices | Sort Machinename,Name |
Format-table -GroupBy machinename
Результаты видны на скриншоте ниже.
Чтобы получить подобные результаты в PowerShell v2, вам придется передать имена компьютеров
(computernames) в Get-Service.
PS C:\> "chi-dc01","chi-dc03" | foreach { get-service dns -comp $_ -RequiredServices} | Sort
Machinename,Name | format-table -GroupBy machinename
Часть 2. Остановка, запуск и пауза
В этой части будут рассмотрены такие такие действия как:
1 Остановка службы
2 Запуск службы
3 Перезапуск службы
4 Приостановка и возобновление работы
5 Управление удаленными службами
6 Настраиваем автозагрузку службы
Мы уделим большее внимание разбору команд в PowerShell для осуществления выше
перечисленного на локальном компьютере. В разделе “управление службами удаленных
компьютерах” мы рассмотрим, ограничения работы в PowerShell v2 и v3.
PS C:\> get-service bits
Status Name DisplayName
------ ---- -----------
Running bits Background Intelligent Transfer Ser...
Так как команда для получения статуса службы называется Get-Service, догадаться о том, как
пишутся другие команды не составит труда. На худой конец мы можем спросить у PowerShell обо
всех командах, так или иначе относящихся к работе со службами. Обратите внимание, что мы
использовали параметр –noun для получения всех команд, связанных со службами.
Взглянем на эти команды внимательнее.
STOP-SERVICE
Чтобы остановить службу, мы должны уточнить ее имя.
PS C:\> stop-service wuauserv
Однако в конвейер ничего не будет передано. Некоторые командлеты, такие как Stop-Service,
созданы таким образом, что по умолчанию они не записывают объект в конвейер. Мы же заставим
это сделать, использовав параметр –Passthru.
PS C:\> stop-service bits -PassThru
Status Name DisplayName
------ ---- -----------
Stopped bits Background Intelligent Transfer Ser...
Если служба не запущена, то командлет ничего не выведет, равно как и не выдаст никакой
ошибки. Поэтому иногда лучше передать объект в Stop-Service (естественно использовав при
этом параметр –whatif).
PS C:\> get-service browser | stop-service -WhatIf
What if: Performing operation “Stop-Service” on Target “Computer Browser (browser)”.
Параметр –WhatIf был добавлен для того, чтобы мы посмотрели, что будет, если командлет будет
запущен. Когда я удостоверюсь, что это именно та служба, которая меня интересует, я просто
удалю -Whatif и остановлю службу.
PS C:\> get-service browser | stop-service
Как я уже упомянул выше, если служба уже остановлена, то командлет ничего не сделает. И
использование Stop-Service в этом случае никому не навредит. Однако я все же предпочитают
более цивилизованный подход, а именно:
PS C:\> get-service bits | where {$_.status -eq 'running'} | stop-service -pass
Status Name DisplayName
------ ---- -----------
Stopped bits Background Intelligent Transfer Ser...
Если служба запущена, то объект передается в конвейер и отправляется в Stop-Service. Ниже
приведен вариант с остановкой нескольких служб.
PS C:\> get-service bits,wsearch,winrm,spooler | where {$_.status -eq 'running'} | stop-service -
whatif
What if: Performing operation "Stop-Service" on Target "Print Spooler (spooler)".
What if: Performing operation "Stop-Service" on Target "Windows Remote Management (WS-Management)
(winrm)".
What if: Performing operation "Stop-Service" on Target "Windows Search (wsearch)".
Некоторые службы не захотят останавливаться – в силу наличия зависимых служб – что мы и
видим на скриншоте ниже.
В таком случае используем параметр –Force. В большинстве случаев это работает, но без “защиты
от дурака”. Помните, что команда также остановит зависимые службы.
PS C:\> stop-service lanmanserver -force –PassThru
Status Name DisplayName
------ ---- -----------
Stopped Browser Computer Browser
Stopped lanmanserver Server
START-SERVICE
Запуск службы осуществляется аналогичным образом. Он поддерживает параметр –Whatif, и вам
придется использовать –Passthru, чтобы увидеть объекты.
PS C:\> start-service wuauserv -PassThru
Status Name DisplayName
------ ---- -----------
Running wuauserv Windows Update
И снова: если служба уже запущена, командлет ничего не сделает. Однако вы можете попытаться
запустить службу и получите такую ошибку.
Причиной тому в большинстве случаев является выключенные службы. Как конфигурировать
настройки службы, я расскажу в следующей статье.
Если вы хотите запустить службы и все службы, зависимые от нее, используйте следующее
выражение:
PS C:\> get-service lanmanserver | Foreach { start-service $_.name -passthru; start-service
$_.DependentServices -passthru}
Status Name DisplayName
------ ---- -----------
Running lanmanserver Server
Running Browser Computer Browser
Мы должны явно получить зависимые службы, потому что Start-Service не запустит
автоматически их.
RESTART-SERVICE
Вы удивитесь, но перезапуск службы работает также как два предыдущих примера. Используйте
–Passthru, если хотите убедиться, что служба запущена.
PS C:\> restart-service spooler -PassThru
Status Name DisplayName
------ ---- -----------
Running spooler Print Spooler
Так как мы осуществляем остановку службы, нам может понадобиться параметр –Force.
ПРИОСТАНОВКА И ВОЗОБНОВЛЕНИЕ РАБОТЫ
Работа некоторых служб может быть приостановлена на некоторое время, а затем возобновлена,
и мы можем это сделать через PowerShell. Однако если служба не удовлетворяет требованиям, мы
получим такие ошибки. (на примере показано, что мы пытались приостановить службу bits)
В чем же проблема? Смотрим на объект (используя Get-Service).
PS C:\> get-service bits | select *
Name : bits
RequiredServices : {RpcSs, EventSystem}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
DisplayName : Background Intelligent Transfer Service
DependentServices : {}
MachineName : .
ServiceName : bits
ServicesDependedOn : {RpcSs, EventSystem}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
Site :
Container :
Если значение свойства CanPauseAndContinue равно True, значит мы можем приостанавливать
и возобновлять работу службы. Найдем такие службы:
PS C:\> get-service | where {$_.CanPauseandContinue}
Status Name DisplayName
------ ---- -----------
Running LanmanServer Server
Running LanmanWorkstation Workstation
Running MSSQLSERVER SQL Server (MSSQLSERVER)
Running O2FLASH O2FLASH
Running stisvc Windows Image Acquisition (WIA)
Running Winmgmt Windows Management Instrumentation
Как мы видим, не так много служб удовлетворяют этому требованию.
PS C:\> suspend-service o2flash -PassThru
Status Name DisplayName
------ ---- -----------
Paused O2FLASH o2flash
Готовы возобновить работу службы? Используйте следующее выражение:
PS C:\> resume-service o2flash -PassThru
Status Name DisplayName
------ ---- -----------
Running O2FLASH o2flash
Оба командлета также поддерживают –Whatif.
УДАЛЕННЫЕ СЛУЖБЫ
Как вы могли обратить внимание, все примере выше мы демонстрировали на локальном машине.
И это неслучайно. К сожалению даже в PowerShell v3, ни у одного из этих командлетов нет
параметра, который позволял бы управлять службой на удаленном компьютере. Get-Service,
конечно, поддерживает параметр –Computername, но не более. Службу лицезреть вы сможете, а
что-либо с ней сделать не получится. Нет, можно, конечно, если удаленный компьютер работает с
PS v2 и включен PowerShell Remoting. Тогда мы можете использовать все выше приведенные
команды, используя Invoke-Commandдля удаленного компьютера или PSSession. С другой
стороны, проще управлять одной службой на нескольких серверах.
PS C:\> Invoke-Command {restart-service dns –passthru} –comp chi-dc03,chi-dc02,chi-dc01
Управление службами на удаленных компьютерах не ограничивается вышеперечисленным, но это
уже будет предмет рассмотрения последующих статей.
Все эти командлеты могут быть использованы в конвейерном выражении и зачастую это лучший
вариант. ИспользованиеGet-Service для получения объектов и последующая передача их в
подходящий командлет.
УСТАНАВЛИВАЕМ УДАЛЕННЫЙ СТАТУС
Итак, мы выяснили, что у командлета Stop-Service отсутствует такой полезный параметр как –
Computername. Мы можете использовать эти команды в удаленной сессии, обратившись к
командлету Invoke-Command, что уже само по себе продуктивно, если вы работаете со службой
на нескольких компьютерах. Одно можно запускать, останавливать, перезапускать, ставить на
паузу и запускать заново, используя Set-Service.
PS C:\> set-service wuauserv -ComputerName chi-dc03 -Status stopped -WhatIf
What if: Performing operation "Set-Service" on Target "Windows Update (wuauserv)".
Эта команда поддерживает параметр –WhatIf. Вы также должны использовать –Passthru для
передачи объектов в конвейер.
PS C:\> set-service bits -ComputerName chi-dc03 -Status running -PassThru
Status Name DisplayName
------ ---- -----------
Running bits Background Intelligent Transfer Ser...
Валидными значениям для параметра –Status являются “запущена” (running), “остановлена”
(stopped) и “на паузе” (paused). Помните, что у службы есть зависимые службы, мы не сможете
изменять ее, что и продемонстрировано на скриншоте ниже.
К сожалению, у Set-Service отсутствует параметр –Force, поэтому придется вернуться к
использованию PowerShell remoting и Invoke-Command. Если вы хотите перезапустить удаленную
службу, используйте следующую команду:
PS C:\> set-service w32time -ComputerName chi-dc03 -Status Stopped -PassThru | set-service -
PassThru -Status Running
Status Name DisplayName
------ ---- -----------
Running w32time Windows Time
Не забудьте использовать –Passthru, в противном случае вторая команда Set-Service ничего не
осуществит.
Что по мне, так я предпочитаю работать сразу с несколькими службами, которые я не могу
удаленно остановить, используя Set-Service, хотя их запуск проблем составляет. Я использую
Invoke-Command. Но помните, что используя параметр –Computername PowerShell осуществляет
подключение, используя RPC и DCOM, что может привести к проблемам с файрволом. Invoke-
Command использует PowerShell remoting, который мы может быть еще не настроили или не
включили.
УСТАНАВЛИВАЕМ ТИП АВТОЗАПУСКА СЛУЖБЫ
Set-Service полезнен, когда вы хотите включить или отключить службу, используя параметр –
StartupType. Если Вы настроили службу, используя значения Automatic, Manual or Disabled. К
сожалению, не существует варианта для Automatic (Delayed).
PS C:\> set-service remoteregistry -StartupType Manual -WhatIf
What if: Performing operation "Set-Service" on Target "Remote Registry (remoteregistry)".
PS C:\> set-service remoteregistry -StartupType Manual -PassThru
Status Name DisplayName
------ ---- -----------
Stopped remoteregistry Remote Registry
Однако, просто взглянув на объект, мы не сможем сказать, к какому типу автозагрузки он
относится.
PS C:\> get-service remoteregistry | select *
Name : remoteregistry
RequiredServices : {RPCSS}
CanPauseAndContinue : False
CanShutdown : False
CanStop : False
DisplayName : Remote Registry
DependentServices : {}
MachineName : .
ServiceName : remoteregistry
ServicesDependedOn : {RPCSS}
ServiceHandle : SafeServiceHandle
Status : Stopped
ServiceType : Win32ShareProcess
Site :
Container :
Как это сделать – одна из тем следующей статьи.
Помните, что изменение типа автозагрузки не повлияет на текущий статус службы.
PS C:\> set-service remoteregistry -StartupType Disabled -PassThru
Status Name DisplayName
------ ---- -----------
Running remoteregistry Remote Registry
Так что если вы хотите выключить и остановить (или включить и запустить) службу, передайте
объект в подходящий командлет.
PS C:\> set-service remoteregistry -StartupType Disabled -PassThru | Stop-Service -PassThru
Status Name DisplayName
------ ---- -----------
Stopped remoteregistry Remote Registry
Технически, Set-Service позволяет вам изменить отображаемое имя службы и описание, но лично
мне никогда не приходилось использовать в своей работе. Я использую Set-Service для
включения и выключения служб. Если необходимо управлять службами удаленно, то я использую
Invoke-Command.
Все, что я продемонстрировал в предыдущих частях, было связано с использованием специфических типов объектов службы, которые, как вы могли заметить, имеют некоторые ограничения. В следующей части мы рассмотрим другие возможности по управлению службами, которые призваны обойти эти ограничения.
Часть 3. Конфигурируем службы с помощью WMI и CIMВ этой части будет рассказано, как использовать WMI и CIM для целей конфигурирования служб
на удаленных компьютерах.
В предудущей части я показал пару примеров использования Set-Service для конфигурирования
служб. Однако здесь имеются некоторые ограничения, особенно когда мы работаем со службами
на удаленных машинах. Частично это обусловлено тем, что такие командлеты как Get-Service и
Set-Service предназначены для работы с объектом службы, который выражен через .NET
Framework — System.ServiceProcess.ServiceController. С позиций администратора в таком
определении объекта отсутствует ряд полезной информации, например, под какой учетной
записью запущена служба. К счастью, здесь нам на помощь приходит Windows Management
Instrumentation (WMI).
Используем WMI
Мы можем использовать Get-WmiObject для извлечения экземпляра объекта службы. Я
продемонстрирую в PS 3.0 на Windows 8, но та же самая команда должна работать и PS 2.0.
Найдем те службы, у которых класс — Win32_Service.
PS C:\> get-wmiobject win32_service | format-table
Я отформатировал вывод команды, чтобы его было легче читать. А теперь давайте взглянем на
отдельную службу.
PS C:\> get-wmiobject win32_service -filter "name='bits'"
ExitCode : 0
Name : BITS
ProcessId : 876
StartMode : Auto
State : Running
Status : OK
Чтобы получить другие свойства, используем следующую команду.
PS C:\> get-wmiobject win32_service -filter "name='bits'" | Select *
Вывод показан на скриншоте.
Теперь вы знаете свойства службы, и можете создавать уточняющие запросы, используя
параметр–Filter.
Получаем тип автозагрузки
Свойство StartMode показывает, стартует ли служба автоматически или должна запускаться
вручную. Когда вы это узнаете, то можете использовать следующие команды:
PS C:\> get-wmiobject win32_service -filter "StartMode <>'disabled'" | sort StartMode | format-
table -GroupBy StartMode -Property Name,State,PathName -AutoSize
Команда выведет нам таблицу, сгруппированную по типу загрузки с новыми ключевыми
свойствами. Запустите ее самостоятельно и посмотрите на результат.
PS C:\> get-wmiobject win32_service -filter "startmode='auto' AND state<>'Running'" | Select
Name,State
Name State
---- -----
MMCSS Stopped
RemoteRegistry Stopped
sppsvc Stopped
wuauserv Stopped
Я запрашиваю информацию о локальных службах, но то же самое можно сделать и на удаленных
машинах
PS C:\> get-wmiobject win32_service -filter "startmode='auto' AND state<>'Running'" -computername
chi-dc01,chi-dc02,chi-dc03 | Select Name,State,Systemname
Name State Systemname
---- ----- ----------
sppsvc Stopped CHI-DC01
sppsvc Stopped CHI-DC02
VMTools Stopped CHI-DC02
RemoteRegistry Stopped CHI-DC03
ShellHWDetection Stopped CHI-DC03
sppsvc Stopped CHI-DC03
wuauserv Stopped CHI-DC03
Получаем учетную запись, под которой запущена служба
Также с помощью WMI вы можете получить учетную запись, под которой запущена служба. В WMI
таковым является свойство Startname.
PS C:\> get-wmiobject win32_service -comp chi-ex01 | group startname
Count Name Group
----- ---- -----
95 localSystem {\\CHI-EX01\root\cimv2:Win32_Service.Name="AeLook...
36 NT AUTHORITY\LocalService {\\CHI-EX01\root\cimv2:Win32_Service.Name="ALG", ...
24 NT AUTHORITY\NetworkSe... {\\CHI-EX01\root\cimv2:Win32_Service.Name="aspnet...
И конечно, вы можете осуществить фильтрацию по этому свойству.
Это очень удобно, если вы ищете службы, запущенные под определенной учетной записью,
например, доменного администратора.
PS C:\> get-wmiobject win32_service -computer $computers -filter "startname like '%administrator
%'"| Select Name,startmode,state,startname,systemname
Name : BITS
startmode : Manual
state : Stopped
startname : .\Administrator
systemname : CHI-EX01
Name : PeerDistSvc
startmode : Manual
state : Stopped
startname : [email protected]
systemname : CHI-WIN8-01
С помощью одной простой команды я нашел те службы, которые запущены под определенной
учетной записью администратора.
Используем CIM
В PowerShell 3.0 вы можете использовать командлеты CIM, чтобы осуществлять те же самые
запросы. Преимущества CIM связаны с удаленной работой с PowerShell.
PS C:\> get-ciminstance win32_service -comp chi-dc01
Фильтры работают аналогичным образом.
PS C:\> get-ciminstance win32_service -filter "startmode='auto' AND state<>'Running'" -comp chi-
ex01 | Select Name,State,Systemname
Name State Systemname
---- ----- ----------
clr_optimization_v4.0.30319_32 Stopped CHI-EX01
clr_optimization_v4.0.30319_64 Stopped CHI-EX01
MSExchangeProtectedServiceHost Stopped CHI-EX01
MSExchangeRPC Stopped CHI-EX01
MSExchangeSA Stopped CHI-EX01
MSExchangeServiceHost Stopped CHI-EX01
ShellHWDetection Stopped CHI-EX01
sppsvc Stopped CHI-EX01
Как можно видеть в выводе, имеются некоторые проблемы с Exchange. С ними и ими подобными
мы будем разбираться в следующей части.
Итог
Использование WMI или CIM – хороший способ получить отчеты о конфигурации служб в вашей
среде. Класс Win32_Service содержит в себе много полезной информации. Плюс Вы можете
запускать длительные запросы (long running queries) с параметром –Asjob или использовать
альтернативные учетные данные. Вы всегда можете это сделать с помощью Get-Service, но это
отнимает много времени. В следующей статье мы рассмотрим, как менять службы с помощью WMI
и CIM.
Часть 4. Изменение служб с помощью WMI
Запуск и остановка
Как известно, командлеты для управления, которые были бы ориентированы на использование
WMI, отсутствуют, так что мы должны использовать методы объекта службы.
PS C:\> get-wmiobject win32_service -filter "name='lanmanserver'" | get-member -MemberType Method
| Select name
Name
—-
Change
ChangeStartMode
Delete
GetSecurityDescriptor
InterrogateService
PauseService
ResumeService
SetSecurityDescriptor
StartService
StopService
UserControlService
Мы можем также получить ссылку на определенный объект службы и затем непосредственно
вызвать метод (directly invoke a method).
PS C:\> $service = get-wmiobject win32_service -filter "name='spooler'"
PS C:\> $service.state
Running
PS C:\> $service.StopService()
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
Я прямо вызываю метод StopService() для объекта службы Spooler. Возвращенное значение (“0”)
означает успех. Любое другое значение означает ошибку, посмотрите документацию на MSDN,
посвященную классу Win32_Service.
Недостатком этого метода является то, что у него отсутствует параметр –Whatif. Поэтому я
рекомендую использовать командлет Invoke-WmiMethod. Мы получаем WMI объект и передаем
его в Invoke-WmiMethod.
PS C:\> get-wmiobject win32_service -filter "name='spooler'" | Invoke-WmiMethod
-Name StartService -WhatIf
What if: Performing operation "Invoke-WmiMethod" on Target "Win32_Service
(StartService)".
PS C:\> get-wmiobject win32_service -filter "name='spooler'" | Invoke-WmiMethod
-Name StartService
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
В предыдущей частия искал те службы, для которых был задан автозапуск, но которые по какой-
то причине не были запущены. Теперь я могу слегка изменить это выражение и произвести запуск
службы.
PS C:\> get-wmiobject win32_service -filter "startmode='auto' AND state<>'Running'" -comp chi-dc03
| invoke-wmimethod -Name StartService
Недостатком этого является то, что объект результата только показывает возвращенное
значение. Если здесь отсутствуют множественные службы, я не могу узнать, какой результат у
определенной службы. Чтобы решить эту проблему, используем вот такой вариант:
PS C:\> get-wmiobject win32_service -filter "startmode='auto' AND state<>'Running'"
-comp chi-dc01,chi-dc02,chi-dc03 | foreach { $svc = $_ ; $_ | Invoke-WmiMethod -Name
StartService | Select @{Name="Name";Expression={$svc.name}},@{Name="DisplayName";
Expression={$svc.Displayname}},ReturnValue,@{Name="Computername";Expression={
$svc.Systemname}}}
Name DisplayName ReturnValue Computername
---- ----------- ----------- ------------
sppsvc Software Protection 0 CHI-DC01
sppsvc Software Protection 0 CHI-DC02
VMTools VMware Tools Service 7 CHI-DC02
ShellHWDetection Shell Hardware Detection 0 CHI-DC03
К блоке ForEach я сохранил входной объект как переменную ($svc), так что я могу снова
использовать ее в качестве части хеш-таблицы, определяющей кастомные свойства. Как вы
можете видеть имеется одна ошибка для той службы, которую, как я думал, я удалил.
Меняем режим запуска
Вы также можете менять режим запуска службы. Опции таковы: Automatic, Disabled или
Manual. С помощью WMI невозможно установить значения запуска службы Automatic (Delayed).
PS C:\> get-wmiobject win32_service -filter "name='spooler'" | Invoke-WmiMethod -Name
ChangeStartMode -ArgumentList "Manual" | Select ReturnValue
ReturnValue
-----------
0
Параметр ArgumentList показывает какое значение следует использовать. Запуск команды
осуществляется с правами администратора.
Устанавливаем свойства службы
У объекта службы не так много свойств, которые вы можете менять. Некоторые WMI объекты
могут быть изменены с помощью Set-WmiInstance. Но в случае с объектами служб, для объекта
вам необходимо использовать метод Change(). Единственная проблема заключается в том, что у
этого метода много параметров.
Change(
string DisplayName,
string PathName,
uint32 ServiceType,
uint32 ErrorControl,
string StartMode,
boolean DesktopInteract,
string StartName,
string StartPassword,
string LoadOrderGroup,
string LoadOrderGroupDependencies,
string ServiceDependencies
)
Вы должны включить эти параметры в метод до того, который вы хотите использовать последним.
Используйте значение$Null для тех параметров, которые вы хотите пропустить. Например:
скажем, я хочу изменить свойство ErrorControl службы Spooler с Normal на Ignore. Исследовав
свойство класса, я обнаруживаю, что Normal соответствует значение 1, а Ignore 0. Теперь давайте
поработаем с PowerShell.
PS C:\> Get-WmiObject win32_service -filter "Name='Spooler'" | Invoke-WmiMethod
-Name Change -ArgumentList @($null,$null,$null,0) | Select ReturnValue
ReturnValue
-----------
0
Выглядит так, будто все работает, проверим.
PS C:\> get-wmiobject win32_service -filter "Name='spooler'" | select
name,errorcontrol
name errorcontrol
---- ------------
Spooler Normal
Ан нет! Так вышло, что у PowerShell есть небольшая “причуда”, о которой вы должны знать. Даже
хотя WMI метод ожидает параметров в заданном порядке, ErrorControl должен быть на
четвертом месте, когда используете Invoke-WmiMethod, порядок по алфавиту. И не
спрашивайте почему. Вот что я делаю, чтобы определить “правильный” порядок.
PS C:\> $svc = Get-WmiObject win32_service -filter "name='spooler'"
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 11
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
DesktopInteract :
DisplayName :
ErrorControl :
LoadOrderGroup :
LoadOrderGroupDependencies :
PathName :
ServiceDependencies :
ServiceType :
StartMode :
StartName :
StartPassword :
PSComputerName :
В этом списке ErrorControl находится на 3 месте, так что я могу заново запустить изменённое
выражение Invoke-WmiMethod.
PS C:\> Get-WmiObject win32_service -filter "Name='Spooler'" | Invoke-WmiMethod -Name Change -
ArgumentList @($null,$null,0)
Проверим еще раз и получим желаемый результат.
PS C:\> get-wmiobject win32_service -filter "Name='spooler'" | select
name,errorcontrol
name errorcontrol
---- ------------
Spooler Ignore
Помните, что в список аргументов необходимо включить $null для тех свойств, которые вы хотите
пропустить. В следующей статье мы заострим внимание на работе со служебными учетными
записями, так как наверняка вы будете работать с ними с помощью PowerShell.
Итог
Использование WMI для управления службами в вашей среде довольно полезно, особенно для тех ситуаций, когда единственный вариант – WMI. Но если вы работаете с PowerShell 3.0, вы также можете использовать CIM командлеты, которые я рассмотрю в следующей статье.
Часть 5. CIM-командлеты
Если вы работаете с PowerShell 3.0, то вам доступны новые CIM-командлеты. Работать с ними
проще — и в этом посте мы узнаем почему.
Остановка и запуск служб с помощью CIM командлетов
Одним из важных отличий CIM-объекта от “чистого” WMI является то, что результирующий объект
(resultant object) не имеет методов. А это значит, что вы не можете непосредственно извлекать
(invoke) метод, например, StopService(). Вместо этого используйте командлет Invoke-
CimMethod. Рассмотрим пример для службы spooler на локальном компьютере.
PS C:\> get-ciminstance win32_service -filter "Name='spooler'"
ProcessId Name StartMode State Status ExitCode
--------- ---- --------- ----- ------ --------
0 Spooler Manual Stopped OK 1077
Как в случае с WMI, проще всего передать объект в командлет Invoke-CimMethod.
PS C:\> get-ciminstance win32_service -filter "Name='spooler'" | Invoke-CimMethod
-Name StartService
ReturnValue PSComputerName
----------- --------------
0
Работа этого командлета во много схода с Invoke-WmiMethod. Возвращенное значение, равное 0,
обозначает успех. Давайте теперь рассмотрим предыдущий запрос, в котором требовалось найти
все службы с автостартом, но которые не были запущены.
PS C:\> get-ciminstance win32_service -filter "startmode='auto' and state<>'running'" -computer
$computers | Invoke-CimMethod -Name StartService –WhatIf
Переменная $computers включает в себя список всех интересующих нас компьютеров.
Используйте -Whatif.
Чтобы внести изменения, запустим команду, но уже без –WhatIf.
PS C:\> get-ciminstance win32_service -filter "startmode='auto' and state<>'running'" -computer
$computers | Invoke-CimMethod -Name StartService
На скриншоте можно видеть, что проблема имеется у компьютера chi-dc02 (ReturnValue
отличается от 0).
Давайте поработаем с тем, что я делал в предыдущей статье, используя Invoke-WmiMethod.
Сейчас я работаю в PowerShell 3.0, так что можно взять каждый объект службы, запустить его и
создать кастомный объект для выведения результатов.
get-ciminstance win32_service -filter "startmode='auto' and state<>'running'"
-computer $computers |
foreach {
$result = $_ | Invoke-CimMethod -Name StartService
#create a custom object
[pscustomobject]@{
Result=$Result.ReturnValue
Name=$_.Name
DisplayName=$_.Displayname
Computername=$Result.PSComputername
}
} | Sort Computername,Name
Стало проще, не так ли?
Можно добавить и другие кастомные свойства, например дату и время. Чтобы вывести только
ошибки, слегка изменим правила сортировки.
... | Sort Computername,Name | Where {$_.result -gt 0}
Result Name DisplayName Computername
------ ---- ----------- ------------
7 VMTools VMware Tools Service chi-dc02
2 gpsvc Group Policy Client chi-win8-01
Меняем режим запуска (StartMode)
Поменять свойство службы (например, Startmode) также просто. Например, мне не нужно, чтобы
служба Remote Access Connection Manager была запущена в сети. Так что я собираюсь отключить
ее везде.
PS C:\> get-ciminstance win32_service -filter "name='rasman'" -comp $computers |
Invoke-CimMethod -methodname ChangeStartmode -Arguments @{startmode='Disabled'}
ReturnValue PSComputerName
----------- --------------
0 chi-win8-01
0 chi-dc03
0 chi-db01
0 chi-ex01
Небольшое отличие от Invoke-WmiMethod – список аргументов должен быть в виде объекта
словаря (dictionary object). Сложность здесь заключается в определении ключа, которым в данном
случае является StartMode. Лучше обратиться к документации для метода WMI и посмотреть имя
параметра. Внимательный читатель обратил внимание на то, что я использовал –MethodName
вместо привычного (и использовавшегося ранее) параметра –Name. –Name – это
недокументированное сокращение для параметра –MethodName.
Так как мы используется объект словаря (dictionary object) для параметров метода, проще извлечь
Change метод для объекта службы. В предыдущей статье для службы Spooler мы установили
значение свойства ErrorControl равным Ignore. Давайте вернем его значение в Normal, используя
теперь CIM командлеты.
PS C:\> get-ciminstance win32_service -filter "name='spooler'" | Invoke-CimMethod
-MethodName Change -Arguments @{ErrorControl=1}
ReturnValue PSComputerName
----------- --------------
0
Это гораздо проще. Не нужно вычислять позиции и добавлять пустые ($Null) значения. Выберите
метод параметра и с делом покончено.
Итог
Почему стоит использовать CIM командлеты: более простое удаленное управление и “дружеские
отношения” с файрволом. Конечно, требуется PowerShell 3.0. Все, что вы можете сделать для
управления службами с помощью WMI, можно сделать и с помощью CIM командлетов, зачастую
требуется меньших усилий для этого.
Я также наткнулся на одну особенность CIM командлетов. В нормальных условиях удаленный
компьютер должен также работать c PowerShell 3.0. Это справедливо, когда вы передаете все
экземпляры заданного класса. Но когда вы используете фильтр, как я часто делаю в этой статье,
то я могу делать запрос с использованием Get-CimInstance даже если на удаленном компьютере
работает PowerShell 2.0! Я до сих пор выясняю, почему так. В любом случае, напоминаю, что нужно
тестировать все, что мы рассматриваем в лабораторной среде.
В следующей части мы посмотрим на управление учетными данными (credentials), под которыми запущена служба.
Часть 6. Служебные учетные записи
В этой части мы рассмотрим, как осуществлять управление служебными учетными записями с
помощью WMI- и CIM-командлетов.
Используем WMI
Чтобы изменить пароль служебной учетной записи, нам нужна ссылка на объект службы. И я
предполагаю, что это служба с учетной записью пользователя.
PS C:\> get-wmiobject win32_service -filter "name='yammmsvc'" | Select name,startname
name startname
---- ---------
YammmSvc .\Jeff
В предыдущих статьях мы рассматривали, что для этих целей можно использовать метод Change()
для изменения пароля служебной учетной записи. Также помним, что параметры Invoke-
WmiMethod не следует задокументированному на MSDN порядку.
PS C:\> $svc = get-wmiobject win32_service -filter "name='yammmsvc'"
PS C:\> $svc.GetMethodParameters("change")
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 11
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
DesktopInteract :
DisplayName :
ErrorControl :
LoadOrderGroup :
LoadOrderGroupDependencies :
PathName :
ServiceDependencies :
ServiceType :
StartMode :
StartName :
StartPassword :
PSComputerName :
Пароль находится на 11 месте. А это значит, что нам необходимо вставить пустые значения для
10 предыдущих параметров, которые не меняются.
PS C:\> $svc | Invoke-WmiMethod -Name Change -ArgumentList
@($null,$null,$null,$null,$null,$null,$null,$null,$null,$null,"P@ssw0rd")
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
PSComputerName :
0 в качестве возвращенного значения означает успешность нашего действия. Но помните, что
изменение не вступит в силу, пока мы не перезапустим службы.
Если вы хотите изменить имя учетной записи, необходимо уточнить его в предыдущем параметре.
PS C:\> $svc | Invoke-WmiMethod -Name Change -ArgumentList @($null,$null,$null,$null,$null,$null,
$null,$null,$null,"LocalSystem","P@ssw0rd")
Также нам необходимо установить первоначальный пароль для системных учетных записей.
Используем CIM
Однако гораздо проще использовать CIM-командлеты для решения подобных задач. Еще раз
поменяем учетную запись и пароль для службы.
PS C:\> Get-CimInstance win32_service -filter "name='yammmsvc'" | Invoke-CimMethod -Name Change -
Arguments @{StartName=".\Jeff";StartPassword="P@ssw0rd"}
И снова возращенное значение должно быть равно 0. Введите startname в формате MACHINE\
USERNAME или DOMAIN\USERNAME. В моем случае, Jeff – это локальная учетная запись. Если Вы
хотите только изменить пароль, вам необходимо лишь откорректировать аргумент в хеш-таблице.
Отметим, что вы можете выполнить запрос и изменить его с помощью Invoke-CimMethod. Объект
в него передавать не надо.
PS C:\> Invoke-CimMethod -Name Change -Arguments {StartName=".\Jeff";StartPassword="P@ssw0rd"} -
Query "Select * from Win32_Service where name='yammmsvc'" –Computername JeffPC
Хотя запустить команду можно было и локально, я решил показать ее запуск на удаленном
компьютере. Ниже приведен пример для изменения службы на нескольких компьютерах.
PS C:\> Invoke-CimMethod -Name Change -Arguments @{StartPassword="P@ssw0rd"} -Query "Select * from
Win32_service where name='MyCustomService'" –computername $computers | out-file c:\work\
results.txt
Как вы видите, я сбросил пароль для службы MyCustomService запущенной на всех компьютерах,
перечисленных в переменной $computers. Результаты сохраняются в текстовый файл, в котором
указаны имя компьютера и возращенное значение. Конечно, службы нужно перезапустить, чтобы
изменения вступили в силу.
Подводим итоги
Если вам необходимо осуществлять управление служебной учетной записью, то вам потребуется использовать WMI – через WMI- или CIM-командлеты. Последние гораздо проще в использовании.