Иногда стандартный текст, используемый для элементов в SCSM, не всегда подходит. И если для объектов, которые хранятся в незапечатанных пакетах, это не проблема – мы можем изменить отображаемое имя как нам угодно, то вот для для объектах, хранящихся в запечатанных пакетах управления всё несколько сложнее. Но, как говориться, нет ничего невозможного.
Для начала давайте определимся, что же мы можем изменить:
- Отображаемое имя любого компонента SCSM – класса, отношения, свойства и так далее
- Отображаемое имя папок и представлений
- Элементы формы
Как вы видите, мы можем менять практически всё, что есть в SCSM.
Как осуществляется перевод в SCSM
Теперь немного теории. Если вы читали мою статью про OpsMgr, то должны знать, что все компоненты в пакете управления (напомню, структура пакетов управления OpsMgr и SCSM родственна) имеют ID – строковый идентификатор. К примеру, ID класса инцидента – System.WorkItem.Incident (надеюсь, что скоро будет закончена статья про пакеты управления в SCSM, где я постараюсь описать это чуть более подробно). Кроме этого, каждый пакет управления содержит специальную секцию LanguagePack, где для каждого поддерживаемого языка содержится отображаемое имя (Display Name) каждого элемента, который содержится в этом пакете управления. К примеру, ниже представлен часть пакета управления, где представлены строки для класса “Инцидент”:
<LanguagePacks> <LanguagePack ID="ENU" IsDefault="true"> <DisplayStrings> <DisplayString ElementID="System.WorkItem.Incident"> <Name>Incident</Name> <Description>Defines the basic properties of incidents</Description> </DisplayString> </DisplayStrings> </LanguagePack> <LanguagePack ID="RUS" IsDefault="false"> <DisplayStrings> <DisplayString ElementID="System.WorkItem.Incident"> <Name>Инцидент</Name> <Description>Определение основных свойств инцидентов</Description> </DisplayString> </DisplayStrings> </LanguagePack> </LanguagePacks>
LanguagePack имеет параметр ID, определяющий 3х буквенный код страны по стандарту ISO 639. Далее следует набор элементов DisplayString, в которых атрибут ElementID указывает, для какого элемента предназначена эта строка. Для подкомпонентов (таких как название свойств классов, компонентов type propjection) DispayString будет иметь дополнительный атрибут SubElementID. К примеру, вот описание свойства Источник класса Инцидент:
<DisplayString ElementID="System.WorkItem.Incident" SubElementID="Source"> <Name>Источник</Name> <Description>Источник</Description> </DisplayString>
С формами дело обстоит чуть сложнее. Для стандартных компонентов (название классов, отношений и пр.) используются те же строки, что и для самого класса. Т.е. если мы скажем сможем поменять отображаемое имя свойства Источник, то оно изменится также и на форме. Но некоторые строки форм не являются частью какого-либо компонента, и поэтому их необходимо хранить отдельно. Для этого при подключении формы мы можем указать элемент FormStrings, в котором перечислить все строки, которые есть на нашей форме. Вот пример заголовка для формы инцидента:
<Form ID="System.WorkItem.Incident.ConsoleForm" Accessibility="Public" Target="System.WorkItem.Incident.ProjectionType" Assembly="ServiceManager.Incident.Forms" TypeName="Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl"> <Category>Form</Category> <FormStrings> <FormString ID="Label_hours">$MPElement[Name="Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl.Label_hours"]$</FormString> <FormString ID="Label_minutes">$MPElement[Name="Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl.Label_minutes"]$</FormString> <!-- обрезано -->
Собственно, значением элемента FormString является ссылка на элемент StringResource в пакете управления, который в свою очередь имеет перевод в секции LanguagePacks:
<!-- обрезано --> <StringResources> <StringResource ID="Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl.Label_hours" /> <StringResource ID="Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.DCMIncidentFormControl.Label_hours" /> <!-- обрезано --> <LanguagePacks> <LanguagePack ID="ENU" IsDefault="true"> <DisplayStrings> <!-- обрезано --> <DisplayString ElementID="Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl.Label_hours"> <Name>hours</Name> <Description>hours</Description> </DisplayString> <!-- обрезано --> <LanguagePack ID="RUS" IsDefault="false"> <DisplayStrings> <!-- обрезано --> <DisplayString ElementID="Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl.Label_hours"> <Name>часы</Name> <Description>часы</Description> </DisplayString> <!-- обрезано -->
При загрузке пакета управления, все переведенные строки попадают в таблицу LocalizedText, формы (и вообще все компоненты SCSM, т.к. обращение идет через SDK, а он в свою очередь берет данные из таблицы) используют строки именно из этой таблицы.
Меняем отображаемое имя на своё
Итак, как вы знаете, менять значения в запечатанных пакетах управления напрямую мы не можем. Трюк состоит в том, что DisplayString в качестве значения атрибута ElementID может принимать ссылку на ID элемента в другом пакете управления. Ссылки на элементы в других запечатанных пакетах управления выглядят в пакете управления следующим образом:
“alias!id”, где:
alias – имя псевдонима для данного пакета, определенного в секции References текущего пакета управления
id – ID элемента в запечатанном пакете управления.
К примеру, чтобы получить ссылку на класс System.WorkItem.Incident, в своем пакет управления, необходимо в нем создать ссылку на пакет управления “System.WorkItem.Incident.Library” (именно в нем содержится определение класса):
<Reference Alias="CoreIncident"> <ID>System.WorkItem.Incident.Library</ID> <Version>7.0.6555.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference>
Теперь ссылка на класс будет выглядеть следующим образом:
”CoreIncident!System.WorkItem.Incident”
Вставьте такую ссылку в атрибут ElementID элемента DisplayString и укажите своё значение в подэлементе Name. После экспортирования своего пакета управления все названия класса будут изменены на ваше значение.
Такой способ имеет один серьезный минус – в большинстве случае вы не сможете вернуть все строки в первоначальное значение, кроме как установив их в своем пакете управления. Связано это с тем, что строки в таблице LocalizedText обновляются только при добавлении пакета управления, но не при удалении. Еще одно важное замечание – прямое редактирование таблицы LocalizedText НЕ ПОДДЕРЖИВАЕТСЯ!
Примеры
Несколько примеров, в которых я не только покажу как переименовать значение, но и как найти его в пакете управления. Самое частое, что просят переименовать – это влияние и приоритет в инцидентах и запросах на изменение, т.к. они как раз таки содержаться в запечатанном пакете управления. Для начала, нам нужно найти в каком пакете управления содержатся эти элементы. Самый простой способ – поиск по базе данных, т.к. все пакеты (даже запечатанные) хранятся в базе данных SCSM. Подробно как производить поиск по базе данных описано здесь.
Для поиска нужный строк очень удобно пользоваться запросом с условием like. Обратите внимание, что все строки находятся внутри элемента <Name>, поэтому чтобы найти к примеру пакет управления, где содержится перечисление с уровнями влияния “Средний”, можно воспользоваться вот таким запросом:
SELECT [MPIsSealed] ,[MPName] ,[MPFriendlyName] ,convert(xml, [MPXML]) FROM [dbo].[ManagementPack] where MPXML like '%<Name>Средний</Name>%'
Обратите внимание на функцию convert – она позволяет преобразовать текст в XML. Тип XML можно просматривать прямо из SQL Server Management Studio (поле открывается в новом окне). В результате выполнения мы получим следующую выборку:
Как мы уже знаем, значение хранится в запечатанном пакете управления, так что нам подходит всего один пакет управления — System.WorkItem.Library. Открываем его и находим вхождение в нем:
В итоге мы видим ID этого элемента (атрибут ElementID), запишем его, он нам потом потребуется. Не закрывайте окно с этим пакетом управления.
Следующим шагом нам надо создать пустой пакет управления, проще всего это сделать с помощью Authoring Tool. Далее, в этом созданном пакете управления необходимо добавить ссылку на пакет управления, в котором содержится наш элемент. Продублируйте любой элемент Reference в созданном пакете управления, и в качестве значение атрибута ID вставьте ID открытого в SQL Server Management Studio пакета управления (он находится в самом верху). Значение Version оставьте не меньше, чем в запечатанном пакете управления. Значение PublicKeyToken для всех пакетов управления Microsoft равно 31bf3856ad364e35. Alias можете указать любой. Для лучшего понимания ниже дана картинка что и куда копировать (справа запечатанный):
Теперь необходимо создать в LanguagePack новый элемент DisplayString, и указать в ElementID ID нужного нам элемента и нужное нам значение, не забыв добавить ссылку на пакет управления (WorkItem!):
<DisplayString ElementID="WorkItem!System.WorkItem.TroubleTicket.ImpactEnum.Medium"> <Name>2 - Среднее</Name> </DisplayString>
После импортирования пакета управления значение изменится в консоли SCSM:
Следующий пример показывает, как можно переименовать строку на форме, и даже добиться легкого изменения логики. По умолчанию, все комментарии, добавляемые в инцидент из консоли, являются публичными. Что, если хочется сделать их по умолчанию приватными? Если вы настраиваете процесс рассылки писем, вы можете установить условие как вам удобно: отправлять, когда флаг Public равнен False или True, это ваша воля. Но на форме будет висеть “галочка” Личное и сбивать ваших инженеров с толку.
Как мы уже знаем, мы можем легко переименовать этот элемент.
- Запустим запрос, указав в критерии поиск <Name>личное</Name>
- Запрос выдаст два похожих пакета управления — System.WorkItem.Library и ServiceManager.IncidentManagement.Library. Если вы посмотрите первый, то увидите, что в нем идет речь о свойстве, а вот во втором – о чекбоксе, в теории нам нужны оба, чтобы потом не путаться в других формах (н-р при настройке условий отбора). Записываем пакеты управления и ElementID обоих.
- Добавляем в наш пакет управления ссылки на эти ПУ (WorkItem уже был, так что нужна лишь одна ссылка)
- Добавляем в секцию LanguagePack элементы DisplayString
В итоге должно получится вот так:
<DisplayString ElementID="IncidentManagement!Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl.CheckBox_Private"> <Name>Общий</Name> <Description>Общий (изменено!)</Description> </DisplayString> <DisplayString ElementID="WorkItem!System.WorkItem.TroubleTicket.AnalystCommentLog" SubElementID="IsPrivate"> <Name>Общий</Name> <Description>Общий (изменено!)</Description> </DisplayString>
И как результат:
В качестве заключения
Не пугайтесь – в первый раз процесс кажется сложным, но на самом деле после небольшой тренировки вы поймете, что это всё довольно просто и быстро. Какие подводные камни следует избегать:
- Делайте всё сначала на стенде, потом только переносите в боевую среду.
- Следите, что бы в вашем пакете не было дублирований в секции Reference (иначе будет ошибка при импортировании пакет)
- Не забывайте добавлять ссылку на пакет управления
Круто! Давно об этом задумылвася, но ни кто не смог помочь! Спасибо, очень полезно!