Some time you need to rename items in sealed management pack. For unsealed it’s can be done easily: export, change the value and import again, instead of sealed MPs, which we can’t change and reimport to SCSM. But management pack engine is pretty well then we talk about localization. Let’s see how to implement this.
Before, lets list that exactly we can change using this approach:
- Display Name for any component – class, property, type projection and so on.
- Display Name for folders and view
- String inside forms
As you can see this’s almost all items from SCSM.
Localization in SCSM
Firstly, some piece of theory. All components from SCSM’s management pack has the ID attribute – string identification. For example, ID of instance class – System.WorkItem.Incident. Also each management pack has LanguagePacks section. That section store the localized string for all component inside management pack. See code snippet below for example of LanguagePacks section for Incident class:
<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>
Each LanguagePack section has ID attribute. This attribute must contains three-letter code define in ISO 639. Each LanguagePack section contains list of DisplayString elements. The ElementID attribute is a link to existing element’s ID, the SubElementID attribute is a link to some additional subcomponent, if exist (class property, type projection component and so on). As example, let’s se at DisplayString element for the Source property of the Incident class:
<DisplayString ElementID="System.WorkItem.Incident" SubElementID="Source"> <Name>Источник</Name> <Description>Источник</Description> </DisplayString>
Then we talk about forms it’s little bit complicated. For standard item like classes, properties, relationships and so on used same string as appropriated item. As result, if we change dispay name for this item it’s also will change in a form. But many strings are not part of some item, and they stored separately. Then the form are defined inside management pack it can (as usual do) contains FormStrings section:
<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> <!-- обрезано -->
The value of the FormString element is a link to StringResource section inside current (or another sealed) management pack. There is also a DisplayString for each StringResource inside appropriated LanguagePacks:
<!-- cut --> <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> <!-- cut --> <DisplayString ElementID="Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl.Label_hours"> <Name>hours</Name> <Description>hours</Description> </DisplayString> <!-- cut --> <LanguagePack ID="RUS" IsDefault="false"> <DisplayStrings> <!-- cut --> <DisplayString ElementID="Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl.Label_hours"> <Name>часы</Name> <Description>часы</Description> </DisplayString> <!-- cut -->
More information about this you can read here.
Then we import the management pack with DisplayString inside to SCSM all DisplayString saved to LocalizedText table of the main SCSM database. SDK service use that table then someone request the localized string for item. The SDK service used for all types of connection to SCSM: console, PowerShell, SDK.
Change item’s display name
Now we are ready to rename any item. To do that we must create new unsealed management pack and add reference to the management pack contained the item’s definition. After that we can use link to necessary element at the ElementID attribute as:
alias – alias name from the References section of the current management
id – element ID from sealed management pack
For example, to get a link to the System.WorkItem.Incident class we must add reference to the System.WorkItem.Incident.Library management pack cause this MP contains definition of the Incident class:
<Reference Alias="CoreIncident"> <ID>System.WorkItem.Incident.Library</ID> <Version>7.0.6555.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference>
Now we can use that alias to create link:
After that you must create new DisplayString section and insert that link as ElementID attribute’s value. Inside created section you must set <name> element to string that you want to display at SCSM. And after all then you import your MP to SCSM your display string will change.
This approach has one disadvantage – you can revert changed value until you change it un your MP. Another word, deletion of your customized MP don’t restore original values cause LocalizedText updated only then MP was imported.
Another note. Direct changes in the LocalizedText table are NOT SUPPORTED!
First of all, you must read this article which give you some useful information about how to search elements inside management packs. The most simple way to search item is a use the like operator. Note that each string surrounded by <Name> tag.
First example is a “most wanted“ feature for SCSM: rename the urgency and\or impact enum values. Let’s find “Medium” string inside all management pack with next query:
SELECT [MPIsSealed] ,[MPName] ,[MPFriendlyName] ,convert(xml, [MPXML]) FROM [dbo].[ManagementPack] where MPXML like '%<Name>Medium</Name>%'
Note to the convert function – this avoid us to export each management pack from SCSM. We can read management pack as XML text directly from SQL Server Management Studio (click field to open new window).
As result of prevision query you must get something like that:
As we already know we must search only sealed MPs and only one MP meet to this criteria: System.WorkItem.Library. Click to it and find text:
Look at ElementID and save it – this is ID we are looking for. Stay current windows opened, little bit later we will return to it.
At the next step we need to create the new empty management pack. Simplest way – use the Authoring Tool. Then we must add reference to management pack early found. To do that just copy-paste any existing Reference element and change ID attribute to System.WorkItem.Library (just copy it from SQL Server Management Studio, you can find ID at the beginning of MP). The Version element set to same or less as System.WorkItem.Library. The PublicKeyToken elemnt set to 31bf3856ad364e35 (this value must be set for all management pack from MSFT). The Alias attribute can be any. Look at this screenshot to better understand which value you must copy (right side is a sealed MP opened in SQL Server Management Studio):
After that we must add new DisplayString section inside LanguagePack section. The ElementID attribute value must be set to element ID from unsealed management with link to this MP (WorkItem!):
<DisplayString ElementID="WorkItem!System.WorkItem.TroubleTicket.ImpactEnum.Medium"> <Name>2 - Medium</Name> </DisplayString>
After that you can import management pack to SCSM and check the result:
Next example show how to change string on form. By default, all comments added to incident marked as Public. But that if you want to change default value to Private? Generally, by default this checkbox has no affect until you not created workflow to send email to the enduser. but then you create this workflow you can use this value as you wish: send then it’s True or then it’s False. So, we just rename the label on form and all done:
- Change criteria to <Name>private</Name>. Run the query.
- The query return two MPs – System.WorkItem.Library and ServiceManager.IncidentManagement.Library. First contains display string for the class property, second for the checkbox. Will be good if we change both.
- Add to the References section reference to both MPs (note: if you use same MP as for first example then the WorkItem Mp already been added)
- Add to the LanguagePack section the DisplayString elements
As result you must write something like that:
<DisplayString ElementID="IncidentManagement!Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl.CheckBox_Private"> <Name>Save as public</Name> <Description>Public (changed!)</Description> </DisplayString> <DisplayString ElementID="WorkItem!System.WorkItem.TroubleTicket.AnalystCommentLog" SubElementID="IsPrivate"> <Name>Pubic</Name> <Description>Public (changed!)</Description> </DisplayString>
Don’t be scared – that process look like something complicated but after several attempt you figure out that this is easy. Some useful information:
- Use your lab before implement any changes in the production.
- Take care about reference with same alias and\or MP ID – that raise error then import to SCSM
- Don’t forget add LINK! before element ID
- Some time you must restart console to see the changes
Sample management pack you can download here (right click and Save As…).