Le blog technique

Toutes les astuces #tech des collaborateurs de PI Services.

#openblogPI

Retrouvez les articles à la une

SCOM – Création et peuplement dynamique de groupes à partir d’une clé de registre (le retour en mieux)

J’avais publié il y a quelques années un article montrant comment créer et peupler automatiquement des groupes à partir d’une clé de registre, à l’aide d’un script vbs : Création et peuplement dynamique de groupes à partir d’une clé de registre.

J’ai récemment rencontré un besoin similaire, et j’ai cette fois voulu expérimenter une technique différente et que je considère comme plus élégante, car elle ne se base que sur l’utilisation standard de deux modules natifs, sans faire appel au moindre bout de script.

Je ne reviendrai pas ici sur la nécessité de déclarer une classe unhosted, non singleton et avec un attribut clé pour le groupe : tout cela est détaillé dans l’article précédent.

Entrons donc directement dans le vif du sujet !

Comme je viens de le rappeler, un groupe est l’instance d’une classe. Les objets membres de ce groupe sont eux aussi des instances de différentes classe et ils sont rattachés au groupe à l’aide d’une relation de containment.

Notre objectif est donc de créer des instances de la classe du groupe ainsi que des relations de containment entre ces instances et les objets qui vont venir peupler les groupes.

Et pour ce faire, sans utiliser aucun script, il existe un module parfaitement adapté : System.Discovery.FilteredClassAndRelationshipSnapshotDataMapper.

clip_image002

Ce module va tout simplement créer une instance de la classe que vous lui indiquerez, avec les propriétés que vous lui indiquerez ; ainsi qu’une instance de la relation de votre choix, entre les instances indiquées.

Bien entendu, il n’est pas question ici de remplir les champs de manière statique : ce module sera intégré dans votre workflow de découverte et récupérera donc toutes les informations dont il a besoin depuis les modules précédents.

Dans cet exemple, nous souhaitons peupler les groupes à partir d’une clé de registre : nous devrions donc créer notre datasourcemoduletype avec le très classique module Microsoft.Windows.Discovery.RegistryProvider comme datasource, puisque son rôle est justement d’aller lire dans la base de registre.

Mais il existe une solution encore plus simple : un module natif combinant RegistryProvider et SnapshotDataMapper existe déjà ! Il s’agit du module Microsoft.Windows.FilteredRegistryClassAndRelationshipDiscoveryProvider.

Une fois ces éléments mis bout à bout, on arrive au fragment suivant qu’il suffit de modifier en y indiquant la clé de registre qui vous intéresse :

<pre class="wp-block-syntaxhighlighter-code"><ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="Test.My.Computers.Group" Accessibility="Public" Abstract="false" Base="MSIL!Microsoft.SystemCenter.InstanceGroup" Hosted="false" Singleton="false" Extension="false" >
          <Property ID="RegistryValue" Type="string" AutoIncrement="false" Key="true" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
        </ClassType>
        
      </ClassTypes>
    </EntityTypes>
  </TypeDefinitions>
  <Monitoring>
    <Discoveries>
      <Discovery ID="Test.My.Computers.Group.Discovery" Enabled="true" Target="Windows!Microsoft.Windows.OperatingSystem" ConfirmDelivery="false" Remotable="true" Priority="Normal">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryClass TypeID="Test.My.Computers.Group">
            <Property TypeID="Test.My.Computers.Group" PropertyID="RegistryValue" />
          </DiscoveryClass>
        </DiscoveryTypes>
        <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.FilteredRegistryClassAndRelationshipDiscoveryProvider">
          <ComputerName>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</ComputerName>
          <RegistryAttributeDefinitions>
            <RegistryAttributeDefinition>
              <AttributeName>RegistryValueExists</AttributeName>
              <Path>SOFTWARE\Test\RegistryValue</Path>
              <PathType>1</PathType>
              <!-- 0=regKey 1=regValue -->
              <AttributeType>0</AttributeType>
              <!-- 0=CheckIfExists (Boolean) 1=treat data as (String) 2=treat data as (Integer) -->
            </RegistryAttributeDefinition>
            <RegistryAttributeDefinition>
              <AttributeName>RegistryValue</AttributeName>
              <Path>SOFTWARE\Test\RegistryValue</Path>
              <PathType>1</PathType>
              <!-- 0=regKey 1=regValue -->
              <AttributeType>1</AttributeType>
              <!-- 0=CheckIfExists (Boolean) 1=treat data as (String) 2=treat data as (Integer) -->
            </RegistryAttributeDefinition>
          </RegistryAttributeDefinitions>
          <Frequency>14400</Frequency>
          <ClassId>$MPElement[Name="Test.My.Computers.Group"]$</ClassId>
          <ClassInstanceSettings>
            <Settings>
              <Setting>
                <Name>$MPElement[Name='System!System.Entity']/DisplayName$</Name>
                <Value>Test My Group - $Data/Values/RegistryValue$</Value>
              </Setting>
              <Setting>
                <Name>$MPElement[Name='Test.My.Computers.Group']/RegistryValue$</Name>
                <Value>$Data/Values/RegistryValue$</Value>
              </Setting>
            </Settings>
          </ClassInstanceSettings>
          <RelationshipId>$MPElement[Name="MSIL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipId>
          <SourceTypeId>$MPElement[Name="Test.My.Computers.Group"]$</SourceTypeId>
          <SourceRoleSettings>
            <Settings>
              <Setting>
                <Name>$MPElement[Name='Test.My.Computers.Group']/RegistryValue$</Name>
                <Value>$Data/Values/RegistryValue$</Value>
              </Setting>
            </Settings>
          </SourceRoleSettings>
          <TargetTypeId>$MPElement[Name="Windows!Microsoft.Windows.Computer"]$</TargetTypeId>
          <TargetRoleSettings>
            <Settings>
              <Setting>
                <Name>$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$</Name>
                <Value>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
              </Setting>
            </Settings>
          </TargetRoleSettings>
          <Expression>
            <SimpleExpression>
              <ValueExpression>
                <XPathQuery Type="Boolean">Values/RegistryValueExists</XPathQuery>  
              </ValueExpression>
              <Operator>Equal</Operator> 
              <ValueExpression>
                <Value Type="Boolean">true</Value> 
              </ValueExpression>
            </SimpleExpression>
          </Expression>
        </DataSource>
      </Discovery>
    </Discoveries>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="Test.My.Computers.Group">
          <Name>Test Computers Group</Name>
        </DisplayString>
        <DisplayString ElementID="Test.My.Computers.Group.Discovery">
          <Name>Test Computers Group Discovery</Name>
          <Description>This discovery rule creates and populates groups of Windows Computer Objects that contain a registry key, based on this key's value</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment></pre>

 

ZABBIX – Script – Tout les hosts, leur status et leurs templates liés

Le script ci-dessous affiche tout les hosts avec leur status et les templates associés

 

GetZabbixAlIHostsAndTemplates(Native_API).ps1 (2,46 kb)

 

### GET ALL ZABBIX HOSTS WITH THEIR STATUS AND TEMPLATES LINKED


Param(
[Parameter(Mandatory=$false)] $baseurl='https://MyZabbixSrv.My.domain/zabbix',
$credential = (Get-Credential -Credential "MyAccount"),
)

 
$global:JsonParams = @{}
     
# 
Function ConnectZabbix($cred,$baseurl)
{
$JsonParams.body =  @{
        "jsonrpc"= "2.0"
        "method"= "user.login"
        "params"= @{
            "user"= $cred.UserName
            "password"= $cred.GetNetworkCredential().Password
        }
        "id"= 1
        "auth"= $null
    } | ConvertTo-Json
    $JsonParams.uri = "$baseurl/api_jsonrpc.php"
    $JsonParams.headers = @{"Content-Type" = "application/json"}
    $JsonParams.method = "Post"
 
 
[System.Net.ServicePointManager]::SecurityProtocol = 'tls12'
[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
 
$global:Connresult = Invoke-WebRequest @JsonParams -UseBasicParsing
 
}
 
# Invoke ConnectZabbix
ConnectZabbix -cred $credential -baseurl $baseurl
 
 
 
## GET HOSTS ##
$JsonParams.body = @{
    "jsonrpc"= "2.0"
    "method"= "host.get"
    "params"= @{
        output = "hostid","name","available","status"
        selectParentTemplates = "templateid","name"
        }

    auth = ($Connresult.Content | ConvertFrom-Json).result
    id = 2
} | ConvertTo-Json

$ZabbixHosts = Invoke-WebRequest @JsonParams -UseBasicParsing
$ZabbixHosts = $ZabbixHosts.Content | ConvertFrom-Json



## CREATE EMPTY TABLEAU THAT WILL STORE HOSTS AND TEMPLATES
$HostsAndTemp = @()

foreach ($Zabbhost in $ZabbixHosts.result)
{

$obj = New-Object psobject

$obj | Add-Member -Name "HOSTNAME" -membertype Noteproperty -Value $Zabbhost.name
$obj | Add-Member -Name "ZBX AGENT STATUS" -membertype Noteproperty -Value `
    $( 
      switch ($Zabbhost.status)
      {
      0 {"ENABLED"}
      1 {"DISABLED"}
      }
     )

$obj | Add-Member -Name "ZBX AGENT AVAILABLE" -membertype Noteproperty -Value `
    $( 
      switch ($Zabbhost.available)
      {
      1 {"AVAILABLE"}
      2 {"UNAVAILABLE"}
      0 {"UNKNOWN"}
      }
     )

$obj | Add-Member -Name "ZABBIX TEMPLATES LINKED" -membertype Noteproperty -Value $Zabbhost.parentTemplates.name


$HostsAndTemp += $obj

}


# TABLEAU FINAL
write-host "`n---- $($ZabbixHosts.result.Count) HOSTS ---`n"
write-host "HOSTNAME - ZBX AGENT STATUS - ZBX AGENT AVAILABLE - ZABBIX TEMPLATES LINKED`n"


$HostsAndTemp | sort hostname | ft -AutoSize


 

Zabbix – Supervision basique d’une URL

Zabbix propose plusieurs manière de superviser des URL. L’exemple ci-dessous propose d’utiliser un ‘Web Scenario’ pour la supervision d’une URL simple (ici www.google.fr).

on commence par créer un template vide qui contiendra la configuration:

image

image

image

NB: Le nom du Host group associé est arbitraire.

Cliquer Add.

image

Le template vide est crée.

image

Cliquer “Create Web Scenario”

image

Name: Check Google

Agent: On positionne Zabbix. ce champs permet de selectionner plusieurs type de client http/navigateur.

Cliquer Steps.


image

Dans la zone Steps, cliquer sur Add.

image

name: Google base page

URL: http://www.google.fr

Required Status codes: 200

image

image

Cliquer Add

image

Le Web scenario est crée.

image

On applique (Link) le template au host devant effectuer le check de supervision.

image

image

Apres quelques minutes les données remonte dans la liste des “Latest data” du host concerné. on voit ici que le code HTTP renvoyé est bien 200 (OK)

On crée a présent un trigger (alerte) en charge declencher une alerte sur le cas ou le code HTTP serait different de 200.

image

image

Dans les propriétés du template, cliquer Triggers

image

cliquer en haut a droite Create Trigger

image

Name: Google Site KO

Clquer sur Add a coté de la zone Expression pour construire la condition de declenchement.

image

Cliquer sur Select pour aller rechercher l’item crée precedemment.

image

Selectionner “Response code for step “Google base page”…”

image

Laisser selectionné la fonction “last()”.

Result: <> 200

cliquer Insert.

image

A titre d’indication ajouter le nom de l’url surveillée dans le champ URL.

Cliquer Add.

image

Le trigger est maintenant actif.