OM: Как закрыть активные алерты для здоровых мониторов

В Operations Manager иногда бывают ситуации, когда монитор переходит в здоровое состояние, но алерт продолжает висеть во вкладке активных алертов. В большинстве случаев это следствие ошибок оператора. Очень часто бывает, что система уже закрыла алерт, но оператор в это время заполняет поля алерта и возвращает ему прежнее состояние. Такой алерт самостоятельно уже не закроется. Чтобы не искать такие алерты вручную, можно воспользоваться следующим скриптом:

$Server = "ServerName"
$Credentials = Get-Credential
New-SCOMManagementGroupConnection -ComputerName $Server -Credential $Credentials
$ActiveAlerts = Get-SCOMAlert -Criteria "IsMonitorAlert = 1 AND ResolutionState < 255"
foreach ($Alert in $ActiveAlerts)
{
	$MonitoringRule = Get-SCOMMonitor -Id $Alert.MonitoringRuleId
	$MonitoringObject = Get-SCOMMonitoringObject -Id $Alert.MonitoringObjectId
	$MonitorList = New-Object System.Collections.Generic.List[Microsoft.EnterpriseManagement.Configuration.ManagementPackMonitor]
	$MonitorList.Add($MonitoringRule)
	$MonitoringState = $MonitoringObject.GetMonitoringStates($MonitorList)
	if ($MonitoringState.HealthState -eq [Microsoft.EnterpriseManagement.Configuration.HealthState]::Success)
	{
		$Alert
		$Alert | Resolve-SCOMAlert -Comment "The alert was manually closed because the monitor is in healthy state."
	}
}

Необходимо задать переменную $Server, указав имя сервера управления Operations Manager, после чего запустить скрипт.

OM: Windows Server Management Pack Mounted Point Bug

Внимание! В статье описана проблема, возникающая в пакетах управления Microsoft Windows Server 6.0.7292.0.

Буквально на днях обнаружил очень неприятный баг – в консоли SCOM по непонятной мне причине начали отображаться по два инстанса для каждого диска. Единственное, что их отличало друг от друга это наличие обратного слэша и описание устройства,- Logical Fixed Disk и Mounted Disk.

Logical Disc Bug

Это могло быть только одно – некорректно написанное правило обнаружения, возвращающее в качестве ключевого свойства DeviceID букву диска с обратным слешом. Итак, теперь нужно разобраться, что же это за правило.

Первое, что я сделал – это отобрал все инстансы класса Microsoft.Windows.LogicalDisk с обратным слэшом через PowerShell:

$baddisk = get-scomclass -name "Microsoft.Windows.LogicalDisk" | Get-SCOMClassInstance | ? {$_.DisplayName -match "\\$"}

Затем, берем любой элемент из массива, например, самый первый и смотрим его ID:

$baddisk[0].Id

В моем случае ID элемента «533a2b61-8852-d031-523a-76fb9a8d0ec3».

Дальше необходимо получить ID правила обнаружения, которое создало этот инстанс. Делаем это через SQL запрос в оперативной базе данных:

SELECT ds.DiscoveryRuleId
FROM [OperationsManager].[dbo].[DiscoverySourceToTypedManagedEntity] dstme
INNER JOIN [OperationsManager].[dbo].[DiscoverySource] ds
ON dstme.DiscoverySourceId = ds.DiscoverySourceId
WHERE dstme.TypedManagedEntityId = '533a2b61-8852-d031-523a-76fb9a8d0ec3'

Мой запрос выдал мне ID «0EBF5558-248D-0B05-51D1-27A126C8E994»

Возвращаемся в PowerShell и смотрим, что это за правило обнаружения:

PowerShell Discovery

Видим, что это правило обнаружения «Microsoft.Windows.Server.2008.MountPoint.Discovery»(Mount Point Discovery Rule). Дальше экспортируем пакет с помощью команды (в моем примере пакет будет экспортирован в корень диска C:):

Get-SCOMManagementPack -Name "Microsoft.Windows.Server.2008.Discovery" | Export-SCOMManagementPack -Path C:\

Открываем его и ищем правило с именем «Microsoft.Windows.Server.2008.MountPoint.Discovery»:

Discovery Rule

Видим, что в качестве источника для данного правила обнаружения используется Data Source модуль с именем «Microsoft.Windows.Server.2008.MountPointDiscovery.ModuleType». Находим его:

Data Source

Содержимое данного модуля – скрипт. Самое интересное находится внизу скрипта. Видим, что данный скрипт опрашивает класс WMI Win32_MountPoint, и выполняет запрос для каждой директории, сравнивая имя директории с именем буквы диска класса Win32_Volume, значения которого записываются в выходные данные обнаружения. НО! Как я уже писал выше, как раз этим скриптом и создаются неверные инстансы дисков – возвращается DeviceID, равное имени буквы диска с обратным слэшом. Если мы опросим класс WMI Win32_Volume и посмотрим скрипт, то увидим, что в строках возвращаются значения Name, которые являются буквой со слэшом.

Data Source Script

Что в данной ситуации нужно сделать? Необходимо создать переопределение (Override) для правила обнаружения «Mount Point Discovery Rule» — переключить флаг «Enabled» в «false» и выполнить команду Remove-SCOMDisabledClassInstance. На данный момент пока нет каких либо хотфиксов как, например, делает это Алексей Журавлев, а сам я его не пишу, т.к. не знаю, что в действительности должно возвращаться, поэтому нужно ждать, пока разработчики исправят эту досадную ошибку.

CM: Еще раз о членстве локальных групп

Давным-давно я (да и не только я) уже писал о том, как можно получить отчет по членам локальных групп. Сегодня, поковырявшись с WMI и оглядываясь назад, решил, что код выглядит достаточно некрасиво, да и сам по себе класс имеет некоторые недостатки. Так, например, если членом локальной группы будет локальный и доменный пользователь с одним и тем же именем, то объект создастся лишь для одной записи. В общем-то сам по себе скрипт поменялся не сильно, а вот класс Win32_LocalGroupMember, если вы уже его использовали, придется пересоздать, т.к. теперь ключевыми свойствами является SID группы и SID учетной записи, что даст абсолютную уникальность каждому объекту в WMI. Также по данному классу теперь можно узнать, является ли пользователь локальным или доменным (MemberLocalAccount), а также SID данного пользователя (MemberSID).

Собственно, сам скрипт:

Set oWMI = GetObject("winmgmts:root\cimv2")
iCimtypeString = 8
iCimtypeBoolean = 11

sClassName = "Win32_LocalGroupMember"
sLocalGroupQuery = "SELECT Domain, Name, SID FROM Win32_Group WHERE LocalAccount=TRUE"
sComputerSystemQuery = "SELECT DomainRole FROM Win32_ComputerSystem"

For Each oSubclass in oWMI.SubclassesOf()
    If oSubclass.Path_.Class = sClassName then oWMI.Get(sClassName).Delete_
Next

Set oClass = oWMI.Get()
oClass.Path_.Class = sClassName
Call oClass.Properties_.add("MemberName", iCimtypeString)
Call oClass.Properties_.add("MemberDomain", iCimtypeString)
Call oClass.Properties_.add("MemberType", iCimtypeString)
Call oClass.Properties_.add("MemberLocalAccount", iCimtypeBoolean)
Call oClass.Properties_.add("MemberSID", iCimtypeString)
Call oClass.Properties_.add("GroupName", iCimtypeString)
Call oClass.Properties_.add("GroupDomain", iCimtypeString)
Call oClass.Properties_.add("GroupSID", iCimtypeString)
Call oClass.Properties_("GroupSID").Qualifiers_.add("key", True)
Call oClass.Properties_("MemberSID").Qualifiers_.add("key", True)
Call oClass.Put_()

Set oClass = oWMI.Get(sClassName).SpawnInstance_

For Each oGroup in oWMI.ExecQuery(sLocalGroupQuery)
	sAssociatorsQuery = "ASSOCIATORS OF {Win32_Group.Domain='"&oGroup.Domain&"',Name='"&oGroup.Name&"'} WHERE Role=GroupComponent"
	For Each oAccount in oWMI.ExecQuery(sAssociatorsQuery)
		oClass.MemberName = oAccount.Name
		oClass.MemberDomain = oAccount.Domain
		oClass.MemberSID = oAccount.SID
		oClass.MemberType = Replace((oAccount.Path_.Class), "Win32_", "")
		oClass.MemberLocalAccount = oAccount.LocalAccount
		oClass.GroupName = oGroup.Name
		oClass.GroupDomain = oGroup.Domain
		oClass.GroupSID = oGroup.SID
		Call oClass.Put_()
	Next
Next

И сам MOF:

//**************************************************************************
//* Class: Win32_LocalGroupMember
//**************************************************************************
 
[ SMS_Report     (TRUE),
  SMS_Group_Name ("Local Group Member"),
  SMS_Class_ID   ("CUSTOM|LocalGroupMember|1.0") ]
class Win32_LocalGroupMember : SMS_Class_Template
{
    [SMS_Report (TRUE)      ] string MemberName;
    [SMS_Report (TRUE)      ] string MemberDomain;
    [SMS_Report (TRUE), key ] string MemberSID;
    [SMS_Report (TRUE)      ] string MemberType;
    [SMS_Report (TRUE)      ] boolean MemberLocalAccount;
    [SMS_Report (TRUE)      ] string GroupName;
    [SMS_Report (TRUE)      ] string GroupDomain;
    [SMS_Report (TRUE), key ] string GroupSID;
};

О том, как опубликовать и использовать в отчетах данный пример можно прочитать в предыдущей статье о членстве групп, все имена свойств класса остались прежними.
Во вложении к статье можно скачать сам скрипт и MOF файл. Не забудьте поменять расширение на .zip.

CM: Обновление клиента ConfigMgr. Какой способ выбрать?

С начала анонса Configuration Manager 2012 прошло достаточно времени, чтобы для него начали появляться обновления и заплатки. В 2012 версии появился такой функционал, как автоматическое обновление клиента… но что-то где-то не срослось. Хотя разработчики утверждали, что новый способ работает так, что версия клиента автоматически обновляется в установленные сроки до версии сайта, но на деле это просто не работает! Итак, подводя итоги, что нам доступно? Ниже я перечислю какие способы есть и постараюсь описать плюсы и минусы.

Способ 1. Обновление с помощью пакетов.

Данный способ является самым простым. При установке кумулятивных обновлений мастер установки предлагает автоматически создать пакеты, после чего мы их объявляем на коллекции. Такой способ тянется с самых ранних версий. А теперь о плюсах и минусах. Простота данного способа несомненно является плюсом. Минус данного способа – его ненадежность. В добавок, в отличие от ConfigMgr 2007, клиент 2012 имеет разрядность – для 32 и 64 битных систем, что в свою очередь требует настройки каждой программы, либо создание 2х коллекций соответственно.

Способ 2. Обновление с помощью приложений.

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

Способ 3. Push-Install.

Данный способ подходит только для ConfigMgr 2007. В 2012 про него можно забыть, т.к. клиент теперь имеет разрядность, соответственно, использовать параметр PATCH нет смысла. Также минусом данного способа является то, что для него требуется вызов удаленных процедур и общая папка. А как же брандмауэры, а как же DMZ, а как же интернет-клиенты? А никак… поэтому данный способ даже не следует рассматривать.

Способ 4. Windows Update.

Тут разработчикам можно поставить большой плюс, т.к. с установкой очередного обновления разворачивается каталог для System Center Updates Publisher в папке SCUP. Всё, что нужно сделать – это импортировать данный каталог в Updates Publisher, после чего уже распространять это обновление на клиенты. Т.е. в данном случае, плюсом является максимально быстрое развертывание с минимальными затратами времени, а также гарантированное обновление клиента до нужной версии. Минусами данного способа является то, что требуется инфраструктура WSUS, более того, крайне желательно использовать SUP в качестве источника обновлений.

Способ 5. Установка нового клиента при развертывании ОС.

Данный способ является вполне приемлемым. Но! В ConfigMgr 2012 невозможно установить обновления клиента через пакеты и приложения. В первом случае Вы получите ошибку 0x87d00215, которая говорит об остановке службы CcmExec, а во втором – зависший Task Sequence. Так что единственный способ – это использование параметра PATCH. Минусом данного способа является то, что командную строку придется менять во всех последовательностях задач при выходе новой заплатки, а также то, что данный способ не обновит существующие и переустановленные клиенты.

Способ 6. Использование папки ClientPatch.

ВНИМАНИЕ! Данный способ является неподдерживаемым!

Плюсом данного решения является то, что все заплатки находящиеся в данной папке будут применены как при использовании Push Install, так и при OSD. Минусом… Нет… МИНУСИЩЕМ данного способа является то, что начиная с версии 2007 данный способ не поддерживается Microsoft, хотя и работает даже в версии 2012, а также то, что данный способ не обновит существующие клиенты до тех пор, пока Вы не нажмете кнопку «Repair client».

Вполне возможно, что я упустил еще какие-то способы для обновления клиентов. Я умышленно не рассмотрел стартап-скрипты и прочие скрипты, т.к. это отдельная тема и данные способы, на мой взгляд, являются побочными. В следующих циклах статей я постараюсь более подробно (с картинками и примерами) описать каждый из вышеописанных способов, чтобы можно было составить для себя какое-то комплексное решение и оставить именно то, что нужно Вам.

CM: SCUP2011 — Verification of file signature failed

Совсем недавно развернул свежую инфраструктуру ConfigMgr 2012 Sp1, а заодно и System Center Updates Publisher 2011. Вроде бы всё делаю как обычно — установил SCUP, интегрировал в ConfigMgr, выписал с Enterprise CA сертификат с расширением «Code Signing» и импортировал его в SCUP. Вроде бы всё, можно приступать — писать свои или загружать 3rd party каталоги и распространять. Но… Сколько бы я не загружал, ни один пакет так и не загрузился. Сперва я грешил на интернет-канал, но когда я скачал файлы локально, то результат был тот же самый. В итоге, открыв логи, я увидел примерно следующее сообщение:

2013-07-08 07:10:03.238 UTC Error Scup2011.7 Publisher.PublishPackage PublishPackage(): Operation Failed with Error: Verification of file signature failed for file: \\Domain.local\configmgrdfsroot\wsus\UpdateServicesPackages\2d5208f4-7e9c-492f-894c-c338d6f795b3\c08eb883-55e6-4730-9c02-15434cc5f11f_1.cab

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

Cretificate Store

После этого я еще раз проверил загрузку обновлений и всё прошло успешно!

OM: Небольшой набор функций для работы с MonitoringClass

Это совсем небольшая статья с набором PowerShell скриптов, которые были написаны мной для удобства работы с Operations Manager 2007 R2.

Function Get-MonitoringClassKeyProperty {
	Param(
		[Parameter(Mandatory = $True, ValueFromPipeline = $True)]$MonitoringClass
		)
	Function Get-MonitoringClassKeyPropertyRecursively {
		Param(
			$MonitoringClass
		)
		$MonitoringClass | Get-MonitoringClassProperty | ? {$_.Key}
		If ($MonitoringClass.Hosted) {
			Get-MonitoringClassKeyPropertyRecursively -MonitoringClass $MonitoringClass.FindHostClass()
		}
		If ($MonitoringClass.Base) {
			Get-MonitoringClassKeyPropertyRecursively -MonitoringClass (Get-MonitoringClass -Id $MonitoringClass.Base.Id)
		}
	}
	Get-MonitoringClassKeyPropertyRecursively -MonitoringClass $MonitoringClass | Select-Object -Unique
}

Function Get-MonitoringClassAllProperty {
	Param(
		[Parameter(Mandatory = $True, ValueFromPipeline = $True)]$MonitoringClass
	)
	Function Get-MonitoringBaseClassPropertyRecursively {
		Param (
			$MonitoringClass
		)
		$MonitoringClass | Get-MonitoringClassProperty
		If ($MonitoringClass.Base) {
			Get-MonitoringBaseClassPropertyRecursively -MonitoringClass (Get-MonitoringClass -Id $MonitoringClass.Base.Id | Select-Object -Unique)
		}
	}
	[Array]$MonitoringProperty = Get-MonitoringBaseClassPropertyRecursively -MonitoringClass $MonitoringClass
	$MonitoringProperty += Get-MonitoringClassKeyProperty -MonitoringClass $MonitoringClass
	$MonitoringProperty | Select-Object -Unique
}

Команда Get-MonitoringClassKeyProperty возвращает все ключевые свойства класса.
Команда Get-MonitoringClassAllProperty возвращает все ключевые свойства и свойства родительских классов.

CM: Создание переменной TS — группа локальных администраторов

Совсем небольшой скрипт, который возвращает в переменную Task Sequence «OSDAdministratorsGroup» имя локальной группы администраторов:

Set oTaskSequence = CreateObject("Microsoft.SMS.TSEnvironment")
Set oWMIcimv2 = GetObject("winmgmts:root\cimv2")
Set oQuery = oWMIcimv2.execquery("Select Name from Win32_Group Where SID = 'S-1-5-32-544' and LocalAccount = 1")
For each oAdmGroup in oQuery
	oTaskSequence("OSDAdministratorsGroup") = replace(oAdmGroup.Name,"^.+\\","")
Next

Скопируйте данный код и назовите его, например OSDAdministratorsGroup.vbs и запустите его в одном из шагов Task Sequence.
Для чего нужен данный скрипт? Например, в ходе развертывания ОС вам нужно добавить локальных администраторов. Быстро это можно сделать средствами команды net localgroup, но не всегда известно имя группы администраторов. Самый распространенный случай — в русской версии Администраторы, в английской — Administrators. После того, как скрипт отработал, можно смело ввести команду, например

net localgroup %OSDAdministratorsGroup% /add CONTOSO\sccm_privaccount

и не беспокоиться о том, какая версия ОС у вас установлена.