Продолжаем публиковать переводы статей по управлению службами Windows, которые выходят на сайте 4sysops.com. В предыдущем посте было рассмотрено использование WMI для извлечения информации о службе. WMI объект службы предлагает новые свойства, которые отсутствуют в .NET объекте службы. И хотя мы можем использовать Set-Service для изменения объекта службы, есть такие ситуации, когда вам необходимо использовать WMI.
Под катом приведен перевод статьи с портала 4sysops.com Managing Services the PowerShell way – Part 6.
Запуск и остановка
Как известно, командлеты для управления, которые были бы ориентированы на использование 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 командлеты, которые я рассмотрю в следующей статье.
Автор: AMarkin