Продолжаю допиливать SCOM2012R2. На сей раз решил разобраться с периодически возникающим алёртом вида:
1 2 3 4 5 6 7 8 9 |
Alert: Operations Manager failed to start a process Source: ex1.domain.int Path: ex1.domain.int Last modified by: System Last modified time: 5/29/2014 11:31:50 AM Alert description: Процессу, запущенному в 11:30:51, не удалось создать System.PropertyBagData. В выходных данных обнаружены ошибки: C:\Program Files\Microsoft Monitoring Agent\Agent\Health Service State\Monitoring Host Temporary Files 36243\5059\HotFixValidation.vbs(117, 10) Microsoft VBScript runtime error: Subscript out of range: 'count' Выполненная команда: "C:\Windows\system32\cscript.exe" /nologo "HotFixValidation.vbs" Рабочий каталог: C:\Program Files\Microsoft Monitoring Agent\Agent\Health Service State\Monitoring Host Temporary Files 36243\5059\ Это затронуло один или несколько рабочих процессов. Имя рабочего процесса: ExchangeRequiredHotfixesNotInstalled Имя экземпляра: ex1.domain.int |
Алёрт этот генерируется правилом “Workflow Runtime: Failed to run a process or script” из пакета управления System Center Core Monitoring. Однако выключать правило не стоит. Оно просто реагирует на события, возникающие в логе “Operations Manager” при сбое выполнения скрипта. А вот сам скрипт вызывается монитором: “The required SCOM hotfixes for Exchange MP are not installed.” из пакета управления “Exchange Server 2010″.
Этот монитор проверяет, подходит ли версия агента SCOM, установленная на сервер Exchange для работы пакета управления Exchange MP. Дело в том, что ранние версии агентов глючили с этим пакетом управления.
Посмотрим, что там не ладно со скриптом.
Возьмём скрипт прямо из консоли оператора и скопируем в редактор с подсветкой синтаксиса.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
'==================================================================================================================== 'This file checks if the required SCOM hotfixes for Exchange MP are installed on the RMS Server and the Agents. '==================================================================================================================== Dim filesys, OpsMgrVersion, OpsMgrInstallDirectory, ScomHotFixStatus Dim strHealthServiceDll, strDataAccessDll,healthServiceVersion, dataAccessVersion, hotfixVersion Dim objMOMAPI, objBag, WshShell 'Set the desired hotfix version Const SP1FileVersion = "6.0.6278.100" Const R2FileVersion = "6.1.7221.2" ScomHotFixStatus = "GOOD" '================= 'Declare Constants '================= 'OpsMgr Event-related Constants Const EVENT_TYPE_ERROR = 1 Const EVENT_TYPE_WARNING = 2 Const EVENT_TYPE_INFORMATION = 4 '================================= 'Instantiate OpsMgr Scripting Runtime '================================= Set objMOMAPI = CreateObject("MOM.ScriptAPI") Set objBag = objMOMAPI.CreateTypedPropertyBag(0) Set filesys = CreateObject("Scripting.FileSystemObject") Set WshShell = WScript.CreateObject("WScript.Shell") OpsMgrVersion = WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup\CurrentVersion") OpsMgrInstallDirectory = WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup\InstallDirectory") strHealthServiceDll = OpsMgrInstallDirectory & "\HealthService.dll" strDataAccessDll = OpsMgrInstallDirectory & "\Microsoft.EnterpriseManagement.DataWarehouse.DataAccess.dll" If fileSys.FileExists(strHealthServiceDll) Then healthServiceVersion = filesys.GetFileVersion(strHealthServiceDll) Else healthServiceVersion = -1 End If If fileSys.FileExists(strDataAccessDll) Then dataAccessVersion = filesys.GetFileVersion(strDataAccessDll) Else dataAccessVersion = -1 End If 'SP1 version of SCOM starts with 6.0 and R2 starts with 6.1 If (Left(OpsMgrVersion,3) = "6.0") Then hotfixVersion = SP1FileVersion kbLink = "http://go.microsoft.com/fwlink/?LinkID=167911" ElseIf (Left(OpsMgrVersion,3) = "6.1") Then hotfixVersion = R2FileVersion kbLink = "http://go.microsoft.com/fwlink/?LinkID=167912" End If 'If versioncompare function returns 2, the hotfix version is higher than the installed version If healthServiceVersion <> "-1" Then If 2 = VersionCompare(healthServiceVersion,hotfixVersion) Then ScomHotFixStatus = "BAD" End If End If if dataAccessVersion <> "-1" Then If 2 = VersionCompare(dataAccessVersion,hotfixVersion) Then ScomHotFixStatus = "BAD" End If End If Call objBag.AddValue("State",ScomHotFixStatus) Call objBag.AddValue("KB Link",kbLink) Call objMOMAPI.Return(objBag) wscript.quit() 'Version Compare Function ' This function returns 0 if the versions are the same, ' 1 if version1 is greater and ' 2 if version2 is greater. Function VersionCompare(Version1, Version2) Dim v1Count, v2Count, v1Element, v2Element Dim v1Elements, v2Elements, smallerCount VersionCompare = 0 v1Elements = Split(Version1, ".") v2Elements = Split(Version2, ".") ' Determine number of version parts. v1Count = UBound(v1Elements) v2Count = UBound(v2Elements) ' Find which string has the fewest parts. If (v2Count < v1Count) Then smallerCount = v2Count Else smallerCount = v1Count End If 'Compare individual values of the version For count = 0 To smallerCount v1Element = CInt(v1Elements(count)) v2Element = CInt(v2Elements(count)) If v1Element > v2Element Then VersionCompare = 1 Exit Function ElseIf v1Element < v2Element Then VersionCompare = 2 Exit Function End If Next 'Versions are same. if(v1Count = v2Count) Then Exit Function Elseif (v1Count > v2Count) Then For count = v2Count To v1Count If CInt(v1Elements(count)) > 0 Then VersionCompare = 1 Exit Function End If Next Elseif (v2Count > v1Count) Then For count = v1Count To v2Count If CInt(v2Elements(count)) > 0 Then VersionCompare = 2 Exit Function End If Next End If End Function |
Судя по алёрту, скрипт вылетает на первой строке вот этой конструкции:
1 2 3 4 5 6 7 8 9 10 11 |
For count = 0 To smallerCount v1Element = CInt(v1Elements(count)) v2Element = CInt(v2Elements(count)) If v1Element > v2Element Then VersionCompare = 1 Exit Function ElseIf v1Element < v2Element Then VersionCompare = 2 Exit Function End If Next |
Запустим скрипт на сервере с установленным агентом SCOM, чтобы убедиться в этом.
C:\temp>cscript c:\temp\hotfix1.vbs //nologo
c:\temp\hotfix1.vbs(120, 10) Microsoft VBScript runtime error: Subscript out ofrange: ‘count’
Да, так и есть, ошибка именно в скрипте.
Давайте разберём скрипт до места вылета. Скрипт довольно простой. Правильными считаются версии SCOM старше “6.0.6278.100″ и “6.1.7221.2″. Точнее, скрипт берёт версию агента SCOM на сервере Exchange, и если она начинается с 6.0 (SCOM2007 и SCOM2007SP1), то эталонной будет версия “6.0.6278.100″, а если она начинается с 6.1 ((SCOM2007R2), то эталонной считается “6.1.7221.2″.
Дальше скрипт узнаёт версии библиотек HealthService.dll и Microsoft.EnterpriseManagement.DataWarehouse.DataAccess.dll и сравнивает их с эталонной. Если хотя бы одна из библиотек старая, то скрипт вернёт в монитор значение BAD, и монитор сгенерирует алёрт:
1 2 3 |
Critical hotfixes required for reliable operation of the Exchange Server 2010 and other management packs are not installed on this server. Please see the appropriate KB article for more information, and to download the required hotfix. For Operations Manager 2007 SP1, install KB 971541 (http://go.microsoft.com/fwlink/?LinkID=167911) For Operations Manager 2007 R2, install KB 974144 (http://go.microsoft.com/fwlink/?LinkID=167912) |
Если агент новее эталона, то алёрт сгенерирован не будет.
Итак, давайте пробежимся по скрипту с самого начала, чтобы понять, почему он останавливается по ошибке.
1 2 3 4 |
'Set the desired hotfix version Const SP1FileVersion = "6.0.6278.100" Const R2FileVersion = "6.1.7221.2" ScomHotFixStatus = "GOOD" |
Здесь задаются эталонные версии SCOM. И сразу видно потенциальную роблему. У меня развёрнут SCOM2012R2, версия агента: 7.1.10226.0. Не похоже, чтобы скрипт знал о существовании SCOM новее 2007R2.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
OpsMgrVersion = WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup\CurrentVersion") OpsMgrInstallDirectory = WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup\InstallDirectory") strHealthServiceDll = OpsMgrInstallDirectory & "\HealthService.dll" strDataAccessDll = OpsMgrInstallDirectory & "\Microsoft.EnterpriseManagement.DataWarehouse.DataAccess.dll" If fileSys.FileExists(strHealthServiceDll) Then healthServiceVersion = filesys.GetFileVersion(strHealthServiceDll) Else healthServiceVersion = -1 End If If fileSys.FileExists(strDataAccessDll) Then dataAccessVersion = filesys.GetFileVersion(strDataAccessDll) Else dataAccessVersion = -1 End If |
Здесь из значения реестра реестра “HKLM\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup\CurrentVersion” берётся версия SCOM. Также выясняются версии библиотек HealthService.dll и Microsoft.EnterpriseManagement.DataWarehouse.DataAccess.dll
1 2 3 4 5 6 7 8 |
'SP1 version of SCOM starts with 6.0 and R2 starts with 6.1 If (Left(OpsMgrVersion,3) = "6.0") Then hotfixVersion = SP1FileVersion kbLink = "http://go.microsoft.com/fwlink/?LinkID=167911" ElseIf (Left(OpsMgrVersion,3) = "6.1") Then hotfixVersion = R2FileVersion kbLink = "http://go.microsoft.com/fwlink/?LinkID=167912" End If |
Здесь из двух эталонных версий выбирается одна. Если версия агента начинается с 6.0 – агент SCOM2007 и SCOM2007SP1, то за эталон принимается “6.0.6278.100″, если версия агента начинается с 6.1 = агент SCOM2007R2, то эталон – “6.1.7221.2″.
У нас версия агента начинается с 7.1. Значит, переменная hotfixVersion останется пустой, нехорошо как-то получается.
1 2 3 4 5 6 7 8 9 10 11 |
'If versioncompare function returns 2, the hotfix version is higher than the installed version If healthServiceVersion <> "-1" Then If 2 = VersionCompare(healthServiceVersion,hotfixVersion) Then ScomHotFixStatus = "BAD" End If End If if dataAccessVersion <> "-1" Then If 2 = VersionCompare(dataAccessVersion,hotfixVersion) Then ScomHotFixStatus = "BAD" End If End If |
Здесь версии библиотек сравниваются с эталоном. В нашем случае они сравниваются с пустым значением – ой не к добру это. Посмотрим, как происходит сравнение версий.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Function VersionCompare(Version1, Version2) Dim v1Count, v2Count, v1Element, v2Element Dim v1Elements, v2Elements, smallerCount VersionCompare = 0 v1Elements = Split(Version1, ".") v2Elements = Split(Version2, ".") ' Determine number of version parts. v1Count = UBound(v1Elements) v2Count = UBound(v2Elements) ' Find which string has the fewest parts. If (v2Count < v1Count) Then smallerCount = v2Count Else smallerCount = v1Count End If 'Compare individual values of the version For count = 0 To smallerCount |
Проверяемая и эталонная версии разбиваются на массивы по разделительным точкам. Дальше вычисляются длины двух полученных массивов, берётся меньшая и идёт сравнение версия по числам слева направо.
К примеру, если бы у нас был агент версии “6.1.7555″, то скрипт получал бы 2 массива:
эталон: 6, 1, 7221, 2 – длина массива – 4
текущая версия: 6, 1, 7555 – длина массива – 3
Дальше было бы сравнение первых трёх элементов массива
6 = 6,
1 = 1,
7221 < 7555
Текущая версия больше эталонной, значит всё в порядке.
В нашем же случае текущая версия – 7.1.10226.0. А эталон вообще пустой. Длина массива добывается функцией UBound. Для пустого массива она возвращает -1 (минус один). Из двух длин берётся меньшая. Минус один меньше чем длина массива (7.1.10226.0). Значит, переменной smallerCount приравнивается значение -1. А дальше у нас идёт строка, на которой вылетает скрипт.
For count = 0 To smallerCount
Всё правильно, цикл от 0 до -1 не возможен в VBS. Поэтому и происходит ошибка. Починить скрипт довольно просто. Нужно поменять всего одну строку.
Было:
ElseIf (Left(OpsMgrVersion,3) = “6.1″) Then
Стало:
ElseIf ((Left(OpsMgrVersion,3) = “6.1″) or CInt (Left(OpsMgrVersion,1) >= 7)) Then
Что мы изменили? Теперь все версии SCOM 2012 и новее будут сравниваться с эталоном “6.1.7221.2″. Запустим изменённый скрипт на сервере с установленным агентом SCOM, чтобы убедиться, что всё починилось.
C:\temp>cscript c:\temp\hotfix.vbs //nologo
<DataItem type=”System.PropertyBagData” time=”2014-05-30T10:46:47.2619294+04:00″ sourceHealthServiceId=”1D90D936-892E-0F5E-E342-150FAA500F42″><ConversionType>Alert</ConversionType><Property Name=”State” VariantType=”8″>GOOD</Property><Property Name=”KB Link” VariantType=”8″>http://go.microsoft.com/fwlink/?LinkID=167912</Property></DataItem>
Как видим, скрипт больше не вылетает по ошибке. К тому же он возвращает значение GOOD, то есть правильно определяет, что версия агента новее эталонной. Остались мелочи – экспортировать пакет управления, изменить скрипт и импортировать пакет управления обратно. Как это сделать, я описывал в предыдущих статьях.
Можно поступить проще. У нас используется SCOM2012, он заведомо новее эталонной версии, так что данный монитор для нас бесполезен. Давайте просто выключим его с помощью переопределения.
Оставить комментарий или два