PI Services

Le blog des collaborateurs de PI Services

SCOM - Moniteur de performance multi-instances

Lors de la création d’un moniteur de performance, il peut arriver qu’il soit nécessaire de superviser plusieurs instances du compteur et d’alerter lorsque n’importe laquelle de ces instances dépasse le seuil paramétré.

La solution qui vient alors immédiatement à l’esprit est alors d’utiliser les wildcard (jokers) dans le nom de l’instance :

clip_image002

Malheureusement, voici ce qui se produit dans ce cas :

clip_image004

clip_image006

Le moniteur détecte bien que l’instance w3wp dépasse le seuil paramétré et passe donc en Critical, mais instantanément après le moniteur détecte que l’instance w3wp#10 est elle toujours sous le seuil et il repasse donc en Healthy : la vérification se fait pour chaque instance du compteur l’une après l’autre, et si un seul d’entre eux n’est pas en critical, le moniteur repasse en vert immédiatement.

Et ce manège recommence à chaque exécution du moniteur…

Une première bonne solution consiste alors à utiliser une variable à la place d’un wildcard en tant qu’Instance.

Prenons l’exemple d’un moniteur de performance qui serait ciblé sur la classe Logical Disk.

Cette classe dispose de propriétés, dont plusieurs correspondent au nom des instances de compteurs :

clip_image007

On peut alors réutiliser une de ces variable dans le champ Instance de l’assistant de création du moniteur, à l’aide de la petite flèche située à sa droite :

clip_image008

On aura donc un moniteur pour chaque instance SCOM de la classe logical disk, ciblé uniquement sur l’instance du compteur de performance qui lui correspond.

Il arrive cependant qu’aucune classe SCOM ne dispose de propriétés utilisables en tant que variable,  typiquement en reprenant le premier exemple du process w3wp.exe.

Dans ce cas, une autre solution existe : le module de détection de condition (condition detection module) System.LogicalSet.ExpressionFilter introduit dans SCOM 2007 R2 permet de déterminer quand arrêter le traitement des données provenant d’une datasource lorsque celle-ci renvoie plusieurs résultats (ce qui est le cas quand un System.Performance.DataProvider est ciblé sur plusieurs instances d’un compteur perfmon).

Autrement dit, en utilisant ce module, les valeurs de chaque instance du compteur sont analysées l’une après l’autre. Dès qu’une de ces instances dépasse le seuil défini, le moniteur passe en Critical et s’arrête sans analyser les instances suivantes, empêchant donc le moniteur de repasser en Healthy.

L’utilisation de ce module n’est toutefois pas possible directement depuis la console SCOM et nécessite de créer son propre MonitorType :

<TypeDefinitions>

<MonitorTypes>

<UnitMonitorType ID="MultipleInstance.Perf.MonitorType" Accessibility="Public">

<MonitorTypeStates>

<MonitorTypeState ID="AboveThreshold" NoDetection="false" />

<MonitorTypeState ID="BelowThreshold" NoDetection="false" />

</MonitorTypeStates>

<Configuration>

<xsd:element name="ComputerName" type="xsd:string" />

<xsd:element name="CounterName" type="xsd:string" />

<xsd:element name="ObjectName" type="xsd:string" />

<xsd:element name="InstanceName" type="xsd:string" />

<xsd:element name="AllInstances" type="xsd:boolean" />

<xsd:element name="Frequency" type="xsd:unsignedInt" />

<xsd:element name="Threshold" type="xsd:double" />

</Configuration>

<OverrideableParameters>

<OverrideableParameter ID="Frequency" Selector="$Config/Frequency$" ParameterType="int" />

<OverrideableParameter ID="Threshold" Selector="$Config/Threshold$" ParameterType="double" />

</OverrideableParameters>

<MonitorImplementation>

<MemberModules>

<DataSource ID="DS_PerfData" TypeID="Performance!System.Performance.DataProvider">

<ComputerName>$Config/ComputerName$</ComputerName>

<CounterName>$Config/CounterName$</CounterName>

<ObjectName>$Config/ObjectName$</ObjectName>

<InstanceName>$Config/InstanceName$</InstanceName>

<AllInstances>$Config/AllInstances$</AllInstances>

<Frequency>$Config/Frequency$</Frequency>

</DataSource>

<ConditionDetection ID="BelowThresholdDetection" TypeID="SystemLibrary7585010!System.LogicalSet.ExpressionFilter">

<Expression>

<SimpleExpression>

<ValueExpression>

<XPathQuery Type="Double">Value</XPathQuery>

</ValueExpression>

<Operator>LessEqual</Operator>

<ValueExpression>

<Value Type="Double">$Config/Threshold$</Value>

</ValueExpression>

</SimpleExpression>

</Expression>

<EmptySet>Passthrough</EmptySet>

<SetEvaluation>All</SetEvaluation>

</ConditionDetection>

<ConditionDetection ID="AboveThresholdDetection" TypeID="SystemLibrary7585010!System.LogicalSet.ExpressionFilter">

<Expression>

<SimpleExpression>

<ValueExpression>

<XPathQuery Type="Double">Value</XPathQuery>

</ValueExpression>

<Operator>Greater</Operator>

<ValueExpression>

<Value Type="Double">$Config/Threshold$</Value>

</ValueExpression>

</SimpleExpression>

</Expression>

<EmptySet>Block</EmptySet>

<SetEvaluation>Any</SetEvaluation>

</ConditionDetection>

</MemberModules>

<RegularDetections>

<RegularDetection MonitorTypeStateID="BelowThreshold">

<Node ID="BelowThresholdDetection">

<Node ID="DS_PerfData" />

</Node>

</RegularDetection>

<RegularDetection MonitorTypeStateID="AboveThreshold">

<Node ID="AboveThresholdDetection">

<Node ID="DS_PerfData" />

</Node>

</RegularDetection>

</RegularDetections>

</MonitorImplementation>

</UnitMonitorType>

</MonitorTypes>

</TypeDefinitions>

On constate que ce module se configure très simplement à l’aide de deux balises xml : EmptySet et SetEvaluation.

EmptySet indique le traitement à appliquer : Passthrough (on continue le traitement des données vers les modules suivants dans le workflow, c’est le mode par défaut) ou Block (qui arrête le traitement du wokflow).

SetEvaluation indique si les données de chaque instance doivent correspondre (All), ou si une seule suffit (Any).

Dans l’exemple ci-dessus, on demande donc d’arrêter le traitement (Block) dès que n’importe quelle instance du compteur (Any) passe au dessus du seuil défini.

Ne reste alors plus qu’à implémenter le Moniteur à proprement parler :

<UnitMonitor ID="w3wp.process.privatebytes.monitor" Accessibility="Public" Enabled="false" Target="SharePoint2!Microsoft.SharePoint.2013.SPServiceInstance.Excel" ParentMonitorID="Health!System.Health.AvailabilityState" Remotable="true" Priority="Normal" TypeID="MultipleInstance.Perf.MonitorType" ConfirmDelivery="true">

<Category>PerformanceHealth</Category>

<AlertSettings AlertMessage="w3wp.process.privatebytes.monitor_AlertMessageResourceID">

<AlertOnState>Error</AlertOnState>

<AutoResolve>true</AutoResolve>

<AlertPriority>Normal</AlertPriority>

<AlertSeverity>Error</AlertSeverity>

</AlertSettings>

<OperationalStates>

<OperationalState ID="AboveThreshold" MonitorTypeStateID="AboveThreshold" HealthState="Error" />

<OperationalState ID="BelowThreshold" MonitorTypeStateID="BelowThreshold" HealthState="Success" />

</OperationalStates>

<Configuration>

<ComputerName>$Target/Host/Property[Type="MicrosoftWindowsLibrary7585010!Microsoft.Windows.Computer"]/NetworkName$</ComputerName>

<CounterName>Private Bytes</CounterName>

<ObjectName>Process</ObjectName>

<InstanceName>w3wp*</InstanceName>

<AllInstances>false</AllInstances>

<Frequency>300</Frequency>

<Threshold>2000000000</Threshold>

</Configuration>

</UnitMonitor>

Et cette fois-ci le moniteur ne bagotte plus, tant que n’importe laquelle des instances du compteur sera au dessus du seuil, le moniteur restera en Critical :

clip_image009

Pour aller plus loin : https://msdn.microsoft.com/en-us/library/hh442318.aspx?f=255&MSPPError=-2147217396

SCCM 2012 – Un déploiement s’exécute en boucle / L’agent se réinstalle toutes les 5h

 

Après le déploiement d’une tâche de reboot via SCCM (un simple de shutdown /r à intervalle planifiée sur une collection de serveurs), je me suis rendu compte que quelques serveurs rebootaient en boucle toutes les 5h.

Après mal de questionnement et d’analyse de log, je me suis aperçu que l’agent SCCM se réinstallait à la même fréquence, ce qui expliquait la répétition de la tâche de reboot étant donné son paramétrage assez « souple » (pas de maintenance window…).

Restait à identifier la raison de cette réinstallation… Ni les logs, ni la console SCCM ne contenaient d’information utile.

Pire, même en désactivant le service de l’agent (bloquant ainsi toute communication avec le serveur), il continuait à se réinstaller (et donc à se réactiver) !

La solution est finalement venue comme souvent d’une recherche sur internet, après avoir trouvé les bons mots-clés… Et le coupable s’avère être une tâche planifiée créée par CCMSETUP lors du premier déploiement de l’agent SCCM, dans le dossier Microsoft/Configuration Manager/Microsoft/Configuration Manager (oui, deux fois !) :

clip_image001

Cette dernière est paramétrée pour se relancer toutes les 5h et sert normalement lorsque CCMSETUP n’arrive pas à contacter le serveur SCCM, afin de reprendre le déploiement de l’agent ultérieurement.

Sauf que pour une raison quelconque (la répétition de l’arborescence Microsoft/Configuration Manager) peut faire penser à un bug qui créerait la tâche au mauvais endroit), il arrive que cette tâche planifiée ne soit jamais supprimée, et l’agent se réinstalle donc en boucle indéfiniment…

La solution est alors toute trouvée : il suffit de supprimer (ou au minimum de désactiver) cette tâche planifiée et tout rentre dans l’ordre!

SCOM – Alertes Failed to Access the Windows Event Log Veeam Vmware

 

Des alertes « Operations Manager Failed to Access the Windows Event Log” concernant des journaux d’événements Veeam Vmware (nWorks) et provenant de serveurs de management (MS) apparaissent :

clip_image002

Elles sont complétées par des événements 26604 récurrents (toutes les 12 minutes) dans les Event Log de ces serveurs :

clip_image004

The Windows Event Log Provider is still unable to open the Veeam VMware event log on computer 'SRV0'. The Provider has been unable to open the Veeam VMware event log for 1440 seconds.

Most recent error details: The specified channel could not be found. Check channel configuration.

One or more workflows were affected by this.

Workflow name: Veeam.Virt.Extensions.VMware.VMGUEST.CollectEvents

Veeam a publié une KB concernant ce problème : http://www.veeam.com/kb1496#/kb1496

Les causes indiquées dans cette dernière ne semblent pas correspondre au contexte rencontré dans mon cas (les alertes apparaissaient sur deux nouveau MS physiques fraichement ajoutés), mais la solution proposée fonctionne malgré tout :

Dans la console Veeam, exécuter une reconstruction de la topologie Rebuild Full Topology :

clip_image006

Rien n’indiquera que la reconstruction est terminée, mais cela peut prendre plusieurs dizaines de minutes voire plusieurs heures selon la taille de votre infrastructure, mais lorsque cela sera bon les événements 26004 ne doivent plus revenir dans l’Event Log.

Il restera enfin à réinitialiser manuellement les moniteurs en erreur :

clip_image008

Orchestrator 2012 – Récupérer le JobID du runbook en cours

 

D’origine, il est possible via les common Published Data de récupérer dans n’importe quel runbook Orchestrator l’ID d’une activité ou d’un process :

clip_image002

On peut même récupérer l’ID de l’instance en cours d’exécution (Job ID) d’un runbook enfant lorsqu’il est appelé via l’activité Invoke Runbook :

clip_image004

Par contre, il n’y a rien de prévu pour récupérer l’ID de l’instance en cours d’exécution du runbook courant.

Ce Job ID du runbook courant peut cependant avoir son utilité, par exemple à des fins de logging et debug. Dans mon cas, il s’agissait de récupérer le nom de la personne ayant démarré le runbook via le portail self-service EUPSCO.

Il est donc malgré tout possible de récupérer cet ID, en intégrant la requête SQL suivante dans une activité Query Database :

SELECT POLICYINSTANCES.JobID
FROM  POLICYINSTANCES INNER JOIN
ACTIONSERVERS ON POLICYINSTANCES.ActionServer = ACTIONSERVERS.UniqueID
WHERE     (POLICYINSTANCES.ProcessID = <Activity process ID from "Initialize Data">) AND (ACTIONSERVERS.Computer = '<Runbook Server name from "Initialize Data">') AND (POLICYINSTANCES.Status IS NULL)

clip_image006

Explication : cette requête interroge la base de données en lui fournissant l’Activity Process ID (qui est disponible nativement via les Common Published Data) afin de retrouver quel JobID contient cet Activity PRocess ID.

Il peut toutefois arriver que le Process ID soit présent plusieurs fois à l’identique dans la base, c’est pourquoi on filtre un peu plus en indiquant le nom du serveur qui exécute le runbook (Runbook Server Name dans les Common Published Data) et surtout en spécifiant le status « NULL », c’est-à-dire que l’on ne recherche que parmi les runbooks qui sont en cours d’exécution et qui n’ont donc pas encore un statut “success”, “warning” ou “failed”

Si tout s’est bien passé, le champ Full line as a string with fields separated by ‘ ;’ présent en sortie de l’activité Query Database devrait contenir le JobID de votre instance de runbook en cours d’exécution, à vous de le réutiliser à votre guise plus loin dans votre runbook !

SCOM 2012 – Erreur lors de l’installation du MP Lync/SFB 2015

 

Le MP Skype For Business (Lync) 2015 est sorti récemment, mais il ne dispose d’aucune documentation.

Son installation coté SCOM reste des plus classique (import de deux fichiers .mp, activation du mode proxy sur tous les agents de l’infrastructure SFB), mais un problème peut survenir sur les serveurs Edge :

image

[Skype] An internal exception has occurred during discovery.

Ce qui correspond à l’événement suivant :

image

An exception occurred during discovery script, Exception : Could not connect to SQL server : [Exception=System.Data.SqlClient.SqlException (0x80131904): Cannot open database "xds" requested by the login. The login failed.

Login failed for user 'NT AUTHORITY\NETWORK SERVICE'.

Cette erreur induit quelque peu en erreur car elle laisse à penser qu’il s’agit de permissions SQL à rajouter.

En réalité, pour résoudre ce problème, rajoutez simplement le compte Network Service aux groupes locaux RTC Component Local Group et RTC Local Administrators (vous pouvez d’ailleurs constater qu’il est normalement bien présent dans ces groupes sur les serveurs du réseau interne).

clip_image006

Enfin, redémarrez l’agent SCOM sur ces serveurs (service Microsoft Monitoring Agent).

SCOM – Des scripts n’arrivent pas à accéder aux cmdlet powershell SCOM

 

Il peut arriver que des scripts soient incapable d’appeler les cmdlet SCOM.

Dans mon cas, ce problème a été remarqué à cause du Management Pack Service Bus v1.1 et plus précisément à cause de la définition de son moniteur (UnitMonitorType) nommé Related Objects Health State, mais il aurait pu s’agir de n’importe quel script exécuté par un Management Pack ou non.

Il se traduisait ici par des évènements Error avec l’ID 4101 dans le journal d’évènements Operations Manager :

clip_image002

Managegement Group: xxx. Script: RelatedObjectsHealthStateMonitorScript\Main : Error occured during Related Objects Health State monitoring.

Computer:yyy

Reason: The term 'Get-SCOMRelationship' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Voyons comment fonctionne ce Monitor Type. Il est basé sur un script powershell qui commence par les commandes suivantes :

param($objectId, $relationshipId, $relatedObjectClassId, $relatedObjectMonitorId, $ignoreUnavailable, $ignoreInMaintenanceMode)
#TODO: Discuss event id
$SCRIPT_EVENT_ID = 4101 
#Event Severity values
$INFORMATION_EVENT_TYPE = 0
$ERROR_EVENT_TYPE = 1 
function GetRelatedObjectsHealthState7Version
{
param
(
$objectId,
$relationshipId,
$relatedObjectClassId,
$relatedObjectMonitorId,
[bool]$ignoreUnavailable,
[bool]$ignoreInMaintenanceMode
)
Import-Module -Name "OperationsManager"
$constUnintializedHealthState = "Uninitialized"
$constSuccessHealthState = "Success"
$constWarningHealthState = "Warning"
$constErrorHealthState = "Error"
#
# Get Relationship
#
$relationship = Get-SCOMRelationship -Id $relationshipId
if($relationship -eq $null)
{
$exceptionMsg = "Relationship with Id {0} not found." -f $relationshipId
$argumentException = New-Object System.ArgumentException -ArgumentList $exceptionMsg 
throw $argumentException
}

Les premières cmdlet SCOM réellement exécutées sont celles surlignées en jaune , les autres lignes ne sont que des définitions de variables ou des appels indépendants de SCOM.

Or, l’évènement indique un échec dès l’appel du cmdlet Get-SCOMRelationship : Reason: The term 'Get-SCOMRelationship' is not recognized as the name of a cmdlet, function, script file, or operable program.

On peut donc supposer qu’en réalité, le script n’a pas été en mesure de charger le module OperationsManager et qu’il ne reconnait donc pas le cmdlet.

On constate également que l’import manuel du module OperationsManager dans un shell PowerShell échoue.

Vérifions donc qu’il est bien présent sur le serveur où remonte l’alerte. Il doit se trouver dans le dossier d’installation de SCOM, sous-dossier Powershell > OperationsManager :

clip_image004

Le module existe bien.

Vérifions maintenant qu’il est bien enregistré dans la variable d’environnement $env:PSModulePath :

clip_image006

Manifestement, il est bien enregistré… Mais pas au bon endroit !

En effet, la variable d’environnement pointe vers C:\Program Files\System Center 2012\Operations Manager\Powershell\ alors que le module se trouve en réalité dans C:\Program Files\System Center 2012\Operations Manager\Powershell\OperationsManager !

La solution est alors toute trouvée : rajouter le bon chemin à la variable d’environnement à l’aide des commandes suivantes :

$originalpaths = (Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PSModulePath).PSModulePath

$newPath=$originalpaths+’;C:\Program Files\System Center 2012\Operations Manager\Powershell\OperationsManager\’

Set-ItemProperty –Path ‘Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment’ -Name PSModulePath –Value $newPath

Il ne reste plus qu’à redémarrer le serveur pour que la modification soit prise en compte et le problème résolu !

Orchestrator – Ajouter des images au corps du mail

 

Lors de l’envoi d’un email dans Orchestrator à l’aide de l’activité Send Email, il est possible de choisir entre de choisir entre le format texte brut et le format HTML pour le corps du mail, dans l’onglet Advanced :

clip_image002

Il devient alors tout naturel de vouloir y intégrer des images à l’aide de la balise HTML <img> , afin d’enrichir encore la mise en page.

Il est alors possible d’avoir recours à plusieurs méthodes : la plus classique consiste à stocker ces images à un endroit accessible par tous les destinataires du mail (site web, partage réseau…) ; mais cette technique présente différents inconvénients : les images sont inaccessibles si l’accès à la source n’est pas disponible au moment de la lecture du mail, la plupart des clients mail bloquent leur chargement par défaut…

Une autre solution consiste à intégrer directement ces images dans les pièces jointes, et à les appeler à l’aide d’un Content ID (CID) au lieu d’un lien réseau ou http, à l’aide de la syntaxe suivante : <img src=’’cid:nomdelimage.jpg’’ />

clip_image003

clip_image005

Et c’est tout, les images seront désormais visibles dans le corps du mail. Encore mieux : selon le client mail utilisé, elles n’apparaitront même pas dans les pièces jointes !

Assurez-vous toutefois bien que le serveur Orchestrator soit lui toujours en mesure d’accéder aux images, il les recharge à chaque appel de l’activité Send Email.

SCOM - Créer une vue avec un filtre « NOT »

 

Tout administrateur SCOM qui se respecte a déjà été amené à créer des vues d’alerte ou d’état spécifiques, ciblées sur une classe et filtrées en fonction d‘un niveau de résolution (resolution state), d’une criticité…

clip_image001

clip_image002

Une problématique revient cependant de temps en temps : comment créer une vue qui exclue spécifiquement certaines alertes en fonction de leur nom ?
Autrement dit, comment afficher toutes les alertes SAUF celles correspondant à un certain nom ?

Le filtre « with a specific name » ne permet à première vue pas de réaliser cette exclusion ; il semble plutôt prévu pour fonctionner en mode « inclusif » : seules les alertes répondant à la chaine de caractères entrée seront affichées :

clip_image004

Mais il est en réalité possible d’utiliser une expression d’exclusion dans ce champ, en plus des wildcards « SQL », à l’aide de la syntaxe suivante :

[^AlerteAExclure]

clip_image006

Voici le résultat obtenu :

clip_image008

Il est également possible de combiner plusieures exclusions à l’aide du symbole « pipe » :

[^(AlerteAExclure)|(TestAlert2)]

Attention toutefois, cette astuce exclut en réalité un groupe de caractères et ne supporte donc pas l’utilisation d’espaces.

SCOM - Création et peuplement dynamique de groupes à partir d’une clé de registre

 

Note : cet article est inspiré et enrichi de la solution proposée par Jan Van Meirvenne sur son blog.

Une pratique assez courante en entreprise consiste à publier des informations sur les serveurs (rôle, site géographique…) dans des clés de registre « fiches d’identité » créées à cette fin.

Il est alors pertinent de créer des groupes SCOM correspondant à ces clés, afin de pouvoir créer des overrides, de cibler des rôles… en fonction de l’organisation logique déjà en place.

La solution la plus évidente, supportée nativement et réalisable aisément via la console SCOM consiste à étendre la classe Windows Computer à l’aide d’attributs personnalisés, peuplés à partir des clés de registre ; puis à créer des groupes contenant des instances de cette nouvelle classe étendue en filtrant en fonction du contenu de l’attribut étendu.

Cette solution reste cependant fastidieuse : dans le cas d’un grand nombre d’informations différentes (nombreux sites géographiques ou rôles serveur), créer puis maintenir à jour des dizaines de groupes s’avère complexe et peu fiable.

C’est pourquoi il est très intéressant de créer et peupler ces groupes automatiquement.

Commençons par revenir sur ce qu’est un groupe « normal » dans le modèle SCOM : contrairement à la plupart des objets qui sont des instances de classe créées automatiquement par des règles de découverte et hébergées au niveau de l’agent exécuté sur le serveur où se trouve l’objet (par ex une instance de la classe serveur windows, site IIS etc. ), les groupes sont créés de manière unique lorsque vous utilisez l’assistant correspondant et sont hébergés par les Management Servers : ils ne sont pas découverts, ils « commencent à exister » une fois l’assistant terminé.

Ce fonctionnement est propre aux classes qui possèdent l’attribut « singleton », ce qui en fait des classes qui sont également des objets.

Revenons maintenant à notre problème : nous souhaitons créer des groupes basés sur une règle de découverte classique, avec de multiples instances découvertes : il s’agit donc simplement de créer une classe qui dérive de la classe Microsoft.SystemCenter.InstanceGroup (comme tous les groupes), mais qui n’aurait cette fois pas l’attribut singleton.

Il est également nécessaire d’ajouter une propriété clé (key property) à notre classe : cela permet de ne créer qu’une seule instance de la classe même si la propriété est découverte à l’identique sur plusieurs agents ; autrement dit dans notre cas de ne créer qu’un seul groupe correspondant à un attribut géographique même si cet attribut géographique est retrouvé sur de multiples serveurs.

<ClassType ID="TEST.DynamicGroups.Group" Accessibility="Public" Abstract="false" Base="GroupLib!Microsoft.SystemCenter.InstanceGroup" Hosted="false" Singleton="false" Extension="false">

<Property ID="Territory" Type="string" AutoIncrement="false" Key="true" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />

</ClassType>

Maintenant que la classe est définie, nous allons pouvoir nous pencher sur la découverte qui découvrira ses instances. Et tant qu’à faire, nous en profiterons pour découvrir également les objets Windows.Computer qui peupleront ces groupes ainsi que la relation qui liera les groupes aux ordinateurs.

La découverte se fera à l’aide d’un script VBS, la seule possibilité pour découvrir à la fois le groupe, l’ordinateur et la relation : évitez donc de définir un intervalle d’exécution trop court pour ne pas surcharger vos agents!

Notez que pour que cette découverte fonctionne, il sera nécessaire d’activer le mode proxy pour tous les serveurs qui seront concernés.

Pensez à modifier la partie en jaune, elle concerne la clé de registre à interroger pour récupérer la valeur qui déterminera le nom du groupe.

<Discovery ID="TEST.DynamicGroups.Group.Discovery" Enabled="true" Target="Windows!Microsoft.Windows.Computer" ConfirmDelivery="false" Remotable="true" Priority="Normal">

<Category>Discovery</Category>

<DiscoveryTypes>

<DiscoveryClass TypeID="TEST.DynamicGroups.Group" />

</DiscoveryTypes>

<DataSource ID="GroupDiscoveryDS" TypeID="Windows!Microsoft.Windows.TimedScript.DiscoveryProvider">

<IntervalSeconds>86400</IntervalSeconds>

<SyncTime />

<ScriptName>discoverdynamicgroups.vbs</ScriptName>

<Arguments>$MPElement$ $Target/Id$ $Target/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Arguments>

<ScriptBody>

SetLocale("en-us")

Dim oAPI
Set oAPI = CreateObject("MOM.ScriptAPI")

Dim oArgs
Set oArgs = WScript.Arguments

if oArgs.Count &lt; 3 Then

Call oAPI.LogScriptEvent("dynamicgroupdiscovery.vbs",101,1,"Script was called with fewer than three arguments and was not executed.")

Wscript.Quit -1

End If

Dim SourceID, ManagedEntityId, TargetComputer

SourceId = oArgs(0)

ManagedEntityId = oArgs(1)

TargetComputer = oArgs(2)

Dim oDiscoveryData, oInstManagedServer,oInstServerGroup,Territory,arrSubKeys

'Lecture de la clef d’identification dans la base de registre

Const HKEY_LOCAL_MACHINE = &amp;H80000002

Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\localhost\root\default:StdRegProv")

oReg.GetStringValue HKEY_LOCAL_MACHINE,"SOFTWARE\TEST\ID_CARD","Territory",Territory

'Construction du nom du groupe et attribution d’une valeur par defaut si clef vide

If IsNull (Territory) Then Territory = "NA"

GroupName = "TEST - TERRITORY - " &amp; Territory

'Ajout de l’instance de l’objet Computer au propertybag

Set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceID, ManagedEntityID)

set oInstManagedServer = oDiscoveryData.CreateClassInstance("$MPElement[Name='Windows!Microsoft.Windows.Computer']$")

call oInstManagedServer.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", TargetComputer)

call oDiscoveryData.AddInstance(oInstManagedServer)

'Ajout de l’instance de l’objet Group au propertybag

set oInstServerGroup = oDiscoveryData.CreateClassInstance("$MPElement[Name='TEST.DynamicGroups.Group']$")

call oInstServerGroup.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", GroupName)

call oInstServerGroup.AddProperty("$MPElement[Name='TEST.DynamicGroups.Group']/Territory$", Territory)

if Err.Number &lt;&gt; 0 Then

Call oAPI.LogScriptEvent("dynamicgroupdiscovery.vbs",104,1, "Script Error : Can't create ServerGroup (" &amp; Err.Number &amp; ") " &amp; Err.Description)

WScript.Quit -1

End If

call oDiscoveryData.AddInstance(oInstServerGroup)

'Ajout de la relation entre l’objet Computer et l’objet Group

Dim oInstWindowsComputer

set oInstWindowsComputer = oDiscoveryData.CreateClassInstance("$MPElement[Name='Windows!Microsoft.Windows.Computer']$")

call oInstWindowsComputer.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", TargetComputer)

call oDiscoveryData.AddInstance(oInstWindowsComputer)

Set oRelationship = oDiscoveryData.CreateRelationshipInstance("$MPElement[Name='GroupLib!Microsoft.SystemCenter.InstanceGroupContainsEntities']$")

oRelationship.Source = oInstServerGroup

oRelationship.Target = oInstWindowsComputer

Call oDiscoveryData.AddInstance(oRelationship)

if Err.Number &lt;&gt; 0 Then

Call oAPI.LogScriptEvent("dynamicgroupdiscovery.vbs",104,1, "Script Error : Can't create ServerGroup to Computer relationship (" &amp; Err.Number &amp; ") " &amp; Err.Description)

WScript.Quit -1

End If

call oAPI.Return(oDiscoveryData)

</ScriptBody>

<TimeoutSeconds>600</TimeoutSeconds>

</DataSource>

</Discovery>

Le gros de la problématique est maintenant couvert, il ne vous reste plus qu’à intégrer cela à vos propres management packs !

Une dernière note : vu l’utilisation qui sera en général faite de ce MP (overrides, délégations, ciblage pour des vues spécifiques…), il peut s’avérer judicieux de le sceller afin d’être en mesure d’y faire référence depuis d’autres MP.

SCOM - L’import d’un MP échoue avec une erreur vide

Lorsque l’on développe ses propres Management Packs, il arrive fréquemment que l’importe échoue pour des raisons diverses (bout de code oublié, mal placé, mauvaise référence…).

Dans ces cas, l’assistant d’importation des MP retourne normalement une erreur plus ou moins explicite qui permet, après un peu de déchiffrage et avec l’habitude, de localiser assez efficacement la cause du problème.

J’ai par contre été confronté aujourd’hui à un cas inhabituel : après l’ajout manuel (en modifiant le code XML directement à l’aide d’un éditeur de texte) d’une règle à un MP pré-existant, l’assistant a refusé l’import avec une erreur “vide” (ou pour ainsi dire sans erreur ) :

image

 

Après quelques heures de questionnements existentiels, de relecture de mon code, de tests en recréant la règle dans un autre MP (là, ca fonctionnait!), j’ai fini par mettre le doigt sur le problème :

La règle que j’avais ajouté contenait un Consolidator (d’où la création manuelle et pas via la console de SCOM), qui était appelé via la ligne

<ConditionDetection ID=”CD” TypeID=”System!System.ConsolidatorCondition”>

Alors que dans mes déclarations de références, le MP System.Library était déclaré avec l’alias SystemLibrary7585010 et non pas System.

Visiblement, l’assistant d’import de MP n’a pas su me signaler cette simple erreur de référence dans ce contexte précis, alors qu’il en est normalement parfaitement capable…

Une erreur bête qui m’aura tout de même fait perdre plusieurs heures!