PI Services

Le blog des collaborateurs de PI Services

SCOM : créer une découverte de registre pour la valeur Default

Dans SCOM, les découvertes basées sur une clé de registre sont les plus communes. Il existe des dizaines de guides et tutoriaux qui détaillent la marche à suivre, je ne reviendrai donc pas sur les fondamentaux mais je me contenterai du rappel suivant : comme le montre l’extrait de code suivant, cette découverte nécessite la définition du chemin de la clé de registre à récupérer et il est possible de définir différents PathTypes et AttributeTypes :

<RegistryAttributeDefinition>

<AttributeName>##UniqueID##RegValueData</AttributeName>

<Path>##RegValuePath##</Path>

<PathType>1</PathType> <!-- 0=RegKey 1=RegValue -->

<AttributeType>2</AttributeType> <!-- 0=CheckIfExists (Boolean) 1=treat data as (String) 2=treat data as (Integer) -->

</RegistryAttributeDefinition>

PathType permet de préciser s’il faut récupérer un Clé ou une Valeur, et AttributeType permet de de préciser si le module doit se contenter de vérifier l’existence de l’entrée, de récupérer sa valeur sous forme de String (chaine de caractères) ou de la récupérer sous forme d’Integer (entier numérique).

Jusqu’ici, rien de bien particulier pour qui est habitué à travailler avec ces découvertes…

Un cas particulier s’est cependant présenté il y a quelques semaines : une application dont le numéro de version était stocké dans la valeur « Default Value » :

clip_image001_thumb

S’il s’agit manifestement d’une valeur plus que d’une clé, elle ne possède pas de nom… comment faire alors pour indiquer son chemin ?

Faut-il indiquer le chemin de la clé parente mais préciser PathType = 1 comme s’il s’agissait d’une valeur ?

Ou bien indiquer le chemin SOFTWARE\Appli\(Default) ?

Un très ancien article du blog de Marius Sutra (https://blogs.msdn.microsoft.com/mariussutara/2008/02/28/howto-registry-attribute-definition-explained/) indique qu’un PathType = 2 existerait pour ce cas précis, mais les tests ne sont pas concluants et aucune autre trace de cette possibilité ne semble exister, même pas dans la définition de la probe Registry sur MSDN.

Après quelques essais infructueux, la bonne réponse a finalement été trouvée directement par le client avec qui je travaillais :

Il suffit en réalité d’indiquer le chemin sous la forme SOFTWARE\Appli\\ (avec deux antislash à la fin, donc), et de conserver le PathType = 1

Encore une astuce à conserver dans un coin… Merci Jérémie !

Outils Azure : récupérer le certificat du proxy transparent

L’utilisation d’Azure et d’outils qui s’appuient dessus (tels que Storage Explorer, Azure Migrate, Azure CLI, Visual Studio et VS Code…) est devenue presque banale et quotidienne pour beaucoup d’entre nous.

Cependant, dans un environnement d’entreprise, un problème récurrent se présente : la connexion d’un de ces outils à Azure échoue avec un message indiquant un certificat racine incorrect ou autosigné ; comme par exemple ici « Self-signed certificate in certificate chain » :

clip_image002

Une vérification dans les journal d’événement CAPI2 de la machine où s’exécute l’outil devrait permettre d’identifier quel certificat empêche la connexion et, bien souvent il s’agit du proxy d’entreprise qui fonctionne en mode « transparent », interceptant ainsi tous les flux sortants.

Deux solutions sont alors possibles : demander à l’administrateur du proxy de mettre en liste d’exclusion les flux nécessaires à l’application, ou récupérer le certificat racine du proxy afin de l’intégrer au magasin des autorités de confiance de votre machine ou dans les certificats de confiance de l’application, si elle le supporte (c’est le cas pour Storage Explorer).

C’est bien entendu le second cas qui nous intéresse ici. Pour récupérer le certificat, il est nécessaire de passer par l’outil OpenSSL qui n’est pas présent nativement sous Windows. Fort heureusement, il est possible de télécharger des binaires déjà compilées et de les exécuter directement depuis l’invite de commande : https://sourceforge.net/projects/openssl/

Une fois l’archive téléchargée et décompressée, la commande suivante permet de récupérer la chaine de certificats réellement reçus par le système lors d’une requête HTTPS :

s_client –showcerts –connect urldeconnexionauservice.test.com:443

clip_image004

On retrouve ici l’erreur « self signed certificate in certificate chain » ainsi que les certificats présents, inclus entre les lignes ----BEGIN CERTIFICATE---- et ----END CERTIFICATE---- :

clip_image006

Il ne reste plus qu’à copier cette chaine de caractères dans un fichier texte, à renommer ce fichier avec une extension .cer et à l’importer dans l’outil ou directement dans le magasin Windows des autorités de certification approuvées.

Orchestrator : récupérer la liste des variables et leurs valeurs

Bien que cela n’arrive pas souvent, il peut se révéler nécessaire d’extraire l’intégralité des variables dans Orchestrator ainsi que leurs valeurs, par exemple dans le cadre de la migration vers un autre outil d’ordonnancement.

Malheureusement, nativement cette extraction n’est possible qu’au format d’export Orchestrator, difficilement lisible.

L’outil communauté « Parse Orchestrator Export Tool » permet d’obtenir une version plus lisible de cet export, mais il ne permet malheureusement aucune sortie dans un format « universel » tels que des tableaux CSV ou Excel.

Nous allons donc nous appuyer directement sur la base de données SQL d’Orchestrator pour obtenir les valeurs qui nous intéressent :

with VariablePath as

(

select 'Variables\' + cast(name as varchar(max)) as [path], uniqueid

from dbo.folders b

where b.ParentID='00000000-0000-0000-0000-000000000005' and disabled = 0 and deleted= 0

union all

select cast(c.[path] + '\' + cast(b.name as varchar(max)) as varchar(max)), b.uniqueid from dbo.FOLDERS b

inner join

VariablePath c on b.ParentID = c.UniqueID

where b.Disabled = 0 and b.Deleted = 0

)

select O.Name,V.Value,VP.[Path]

from dbo.objects AS O

INNER JOIN VariablePath AS VP ON VP.UniqueID = O.ParentID

INNER JOIN Variables AS V ON V.UniqueID = O.UniqueID

Cette requête retourne le nom, la valeur et l’arborescence de la variable :

clip_image002[10]

Notez cependant que la valeur des variables chiffrées (mots de passe…) reste illisible, puisqu’elles ne sont pas disponibles en texte clair dans la base.

Azure DNS : Du mieux dans les zones privées !

Bref rappel : Azure DNS est un service PaaS qui propose d’héberger vos zones DNS sans que vous n’ayez besoin de vous préoccuper de la gestion de l’infrastructure sous-jacente.

De plus, comme tout service « cloud », il est possible de gérer ces zones et leurs entrées à l’aide d’une API REST, ce qui apporte une flexibilité certaine face au fonctionnement encore un peu archaïque du service Windows DNS dont la gestion passe nécessairement par la MMC DNS ou par Powershell, voire par l’utilisation de dnscmd.exe pour ceux d’entre vous qui lisent cet article en 1992.

Microsoft a introduit il y a quelques mois un type de zone « Private » à ce service, permettant ainsi d’héberger des zones qui ne seraient pas résolvables depuis l’extérieur de votre environnement ; mais ce mode souffrait de lacunes sérieuses, qui le rendaient inexploitable dans un contexte réel :

  • Il n’était disponible qu’en Powershell
  • Seules les requêtes provenant d’un unique VNet avaient le droit de créer des entrées dans une zone donnée
  • Seuls 10 VNet avaient le droit de lire les entrées d’une zone donnée
  • Ces VNet devaient être déclarés manuellement
  • Ces VNet ne devaient contenir aucune ressource au moment de leur déclaration (!!)
  • Les enregistrements étaient invisibles via powershell ou l’API REST, mais étaient bel et bien resolvables
  • … etc.

Une mise à jour majeure est apparue la semaine dernière, et elle corrige la majorité de ces défauts :

  • On peut désormais créer les zones privées directement dans le portail Azure
  • On peut lier jusqu’à 1000 VNet à une zone privée, même si ces VNet contiennent déjà des ressources ; et les notions de VNet « enregistreur » ou « requêteur » disparaissent
  • On peut désormais accéder aux enregistrements via l’API ou Powershell

Bref, on peut maintenant raisonnablement utiliser ce service dans un environnement réel… mais attention tout de même, il est toujours en Public Preview et susceptible d’évoluer n’importe quand !

Notez également que la résolution dans une zone Private DNS ne fonctionne par défaut que si votre VNet est configuré pour utiliser la résolution DNS native d’Azure.

Si vous utilisez une résolution « Custom » (un contrôleur de domaine déployé dans votre tenant par exemple), il faudra créer un conditional forwarder pour votre zone Private DNS, pointant vers l’IP d’Azure DNS (unique pour tous les tenant et toutes les régions) : 168.63.129.16

Enfin, comme la résolution dans une zone Private DNS n’est possible que depuis un VNet, il faudra également prévoir un forwarder différent sur les serveurs DNS de votre Lan si vous souhaitez pouvoir résoudre depuis cet emplacement !

L’occasion idéale pour mettre en place une partition DNS à réplication limitée

Windows DNS - créer un scope de réplication limité

Les partitions DNS intégrées à Active Directory, permettant ainsi leur réplication et leur gestion sur tous les contrôleurs de domaine disposant du rôle DNS, sont depuis longtemps la norme dans un environnement Windows.

Il existe cependant une possibilité moins connue de ce mécanisme : la partition DNS « custom », qui permet de définir un scope de réplication limité à seulement un ou quelques contrôleurs de domaine de votre choix.

J’ai eu recours à cette possibilité afin de résoudre un problème lié à l’utilisation de Conditional Forwarders que vous pourriez bien rencontrer dans votre propre environnement sans même le savoir : les Conditional Fowarders sont répliqués dans toute votre forêt de la même façon que les zones DNS « classiques » (foward et reverse), mais si vous en utilisez il est fort possible que seuls certains de vos contrôleurs de domaine soient réellement en mesure de les atteindre en raison de contraintes réseaux propres à votre environnement.

Il devient alors nécessaire de limiter la réplication de ces Conditional Forwarders aux seuls serveurs DNS qui y ont accès !

La création d’une partition DNS se fait uniquement en powershell (en tant qu’administrateur) :

Add-DnsServerDirectoryPartition -Name "ConditionalForwardersPartition"

Il est ensuite nécessaire d’y ajouter les contrôleurs de domaine qui répliqueront cette partition :

Register-DnsServerDirectoryPartition -Name "ConditionalForwardersPartition" -ComputerName "DC01.cogip.com"

Répétez cette opération pour chaque contrôleur pour lequel vous souhaitez activer la réplication sans trop prêter attention aux possibles erreurs que vous pourriez obtenir : ca marche quand même (… normalement !) ; puis vérifiez justement que les serveurs sont bien ajoutés à la zone :

Get-DnsServerDirectoryPartition -Name "ConditionalForwardersPartition"

clip_image002

Il est désormais possible de créer ou de déplacer un conditional forwarder dans cette partition, simplement à l’aide de la MMC DNS :

clip_image004

Attention : dans le cas du déplacement d’un forwarder existant déjà, assurez -vous qu’il n’est pas protégé contre la suppression ! Si c’est le cas, le déplacement échouera avec un message peu explicite, et toutes les tentatives successives échoueront également même si vous retirez la protection entre temps ! La seule solution sera ici d’utiliser ADSI Edit pour aller faire le ménage dans la partition DC=ConditionalForwardersPartition …

Azure Storage - Failed to create blob container

La création d’un conteneur Blob dans un compte Azure Storage est une opération devenue plutôt banale, mais qui peut toutefois encore donner lieu à des messages d’erreur assez cryptiques :

clip_image002

Failed to create blob container.

Details : This request is not authorized to perform this operation.

Le message d’erreur pourrait laisser penser à un manque de droits, mais l’utilisateur dispose bien de permissions suffisantes dans ce Storage Account.

Par contre, dans le cas qui nous intéresse ici, le filtrage par adresse IP est activé sur le Storage Account utilisé, et la VM qui tente d’accéder au Storage Account est déployée dans un tenant Azure différent ; le filtrage est donc réalisé à l’aide de l’IP publique de la VM :

clip_image004

Or, les connexions entrantes dans le storage account sont s-natées à l’intérieur d’un même Datacenter Azure, comme indiqué ici : https://github.com/MicrosoftDocs/azure-docs/issues/10359 . Ce n’est donc pas l’IP publique de la VM qui se présente en entrée du Storage Account, et cela explique le blocage rencontré…

Deux solutions sont toutefois disponibles :

  • Déployer le Storage Account dans une région Azure différente de celle de la VM : ca sera alors bien l’IP publique de cette dernière qui se présentera en entrée du Storage Account
  • Utiliser le filtrage par VNET à la place du filtrage par IP. Cette solution reste possible même si le VNET de la VM est dans un tenant différent de celui du Storage Account, mais il faudra que l’utilisateur qui réalise la configuration dispose de permissions spécifiques sur le VNET de la VM : https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security#grant-access-from-a-virtual-network

SCOM – Supprimer un management pack directement dans la base de données

Préambule : cette manipulation n’est pas supportée par Microsoft, vous ne devriez pas vous en servir sur une infrastructure de production en dehors des instructions que vous fournirait le support.

Ceci étant dit, revenons-en au sujet.
Il peut arriver que certains Management Packs aient écrit tellement de données dans la base que leur suppression via la console ou via Powershell échoue après 30 minutes de travail :

clip_image002

Remove-SCOMManagementPack : The requested operation timed out

On entre alors dans un cercle vicieux : plus on attend pour les supprimer, plus il y aura de données à supprimer ; sans compter que ces management packs ont la facheuse tendance à noyer la base de données et à provoquer le redouté événement 2115 (mais c’est une autre histoire…).

Heureusement, il existe une procédure stockée qui permet de supprimer un Management Pack et toutes les données qu’il a enregistrées dans la base, sans craindre de timeout : p_ManagementPackRemove.

Afin de l’exécuter, il est d’abord nécessaire de récupérer l’id du management pack à supprimer :

SELECT ManagementPackId,MPName
FROM [OperationsManager].[dbo].[ManagementPack]
where MPName like ‘%MP à supprimer%’

Puis la procédure s’appelle simplement avec la requête suivante :

exec [dbo].[p_ManagementPackRemove] ‘ManagementPackId‘
go

Il ne vous reste alors plus qu’à patienter… à titre d’exemple, la suppression du MP Dell (Detailed) sur un environnement contenant plusieurs centaines de serveurs physiques a nécessité plus de 4h !

SCOM – Utiliser une propriété issue du workflow dans une Recovery

Au programme de cet article, une nouvelle astuce méconnue : comment utiliser une propriété issue du changement d’état d’un moniteur dans une tâche de remédiation (Recovery).

Prenons pour exemple un moniteur de service tout ce qu’il y a de plus classique :

 clip_image002

Imaginons maintenant que nous ayons besoin de déclencher une Recovery lorsque ce moniteur repasse à l’état Healthy (oui, c’est parfaitement réalisable en XML même si impossible directement dans la console), par exemple pour aller écrire le Process ID de l’exécutable sous-jacent au service dans un fichier de log.

Le PID fait partie des informations contenues dans le PropertyBag qui entraine le passage du moniteur en Healthy :

clip_image004

Il faudrait donc pouvoir passer la valeur de cette propriété en entrée de notre Recovery.

On pense alors immédiatement à la notation couramment utilisée pour afficher ces valeurs dans les alertes :
$Data/Context/Property[@Name=’ProcessId’]$
Malheureusement, elle ne fonctionne pas dans le cadre d’une Recovery…

La syntaxe correcte, très peu utilisée et documentée, est en réalité la suivante :

$Data/StateChange/DataItem/Context/DataItem/Property[@Name=’ProcessId’]$

Elle résulte de la structure du MonitorTaskDataType qui encapsule un PropertyBag dans un autre lors de la circulation des données dans un workflow de moniteur, tel que le montre cet exemple sur MSDN : https://docs.microsoft.com/en-us/previous-versions/system-center/developer/ee533651(v=msdn.10)

Cette astuce ne vous servira probablement pas tous les jours, mais elle m’a déjà été bien utile… peut-être vous le sera-t-elle aussi !

SCOM - La variable $Data$ ou comment utiliser Powershell n’importe où dans un module

L’article d’aujourd’hui s’adresse en priorité aux développeurs de management packs aguerris puisqu’il nécessite que vous maitrisiez déjà des notions d’authoring avancé comme la composition de modules personnalisés, de data source, de probe et donc les concepts de property bags et de circulation des données au sein d’un module.

Si ce n’est pas votre cas, ne partez pas tout de suite : cela pourrait quand même vous donner envie d’en savoir plus sur ces sujets !

Revenons-en donc au sujet qui nous intéresse : ne vous êtes-vous jamais retrouvé frustré par l’impossibilité de récupérer un Property Bag complet dans une probe Powershell afin de le traiter dans son ensemble avant de le réinjecter dans le workflow d’un module personnalisé ?
Par exemple pour travailler sur l’ensemble des données retournées par un SnmpWalk (ma bête noire !), d’une requête SQL issue de la Datasource OleDB native ou plus généralement lorsqu’une datasource renvoie un résultat dont les propriétés sont en nombre variable et imprévisible ; pour produire à partir de ces derniers des PropertyBags formatés à votre guise afin de les réutiliser plus loin dans votre module ?

Si ce n’est pas le cas, tant mieux ! Mais cela m’est arrivé plus d’une fois… Jusqu’à ce que je me souvienne d’un article de l’illustre Daniele Grandini qui, je dois bien l’admettre, ne m’avait pas interpelé plus que ça lors de ma première lecture. Ces préoccupations étaient alors bien éloignées de mes besoins en authoring, encore modestes !
Il y met en lumière la problématique que j’exposais plus haut, et propose pour la résoudre un module de type ConditionDetection de sa propre conception qui permet de « reconstruire » un property bag complet afin de le passer dans le workflow.

S’il s’agit assurément d’un grand pas en avant, une solution encore largement supérieure proposée par « bobgreen84 » (alias Validimir Zelenov) se cache dans les commentaires de l’article : en décompilant la ProbeAction powershell native de SCOM (Microsoft.EnterpriseManagement.Modules.PowerShell.dll – SCOM n’utilise pas directement l’exécutable original de powershell présent dans toute installation de Windows lors de l’utilisation de ProbeAction powershell), il a remarqué que celle-ci disposait d’une possibilité à ma connaissance non documentée ni utilisée dans aucun management pack.

Mais avant d’aller plus loin sur cette découverte, revenons rapidement sur l’aspect d’un PropertyBag et le fonctionnement d’une Probe powershell.

Voici un PropertyBag classique, issu d’une Datasource quelconque.
Il s’agit d’un bloc de code XML formaté d’une façon bien spécifique qui permet au moteur de SCOM de faire circuler les données entre les différents composants d’un module.
Celui-ci contient les propriétés nommées Value1 et Value2, dont les valeurs sont respectivement 10 et 5 :

image

Voici maintenant une Probe powershell qui exécute un script dont le but est simplement d’additionner deux valeurs qui lui sont passées en paramètre, puis de retourner le résultat de cette addition dans un PropertyBag.
Les valeurs de ces paramètres proviennent du PropertyBag précédent et sont récupérées à l’aide de la notation habituelle $Data/Property[@Name=’nomdelapropriété’]$ .

clip_image004

Le PropertyBag résultant de l’exécution de cette probe ressemblera donc à ceci :

clip_image006

Rappelons par ailleurs que la notation  $Data/Property[@Name=’nomdelapropriété’]$ est héritée de xQuery, une notation standard permettant de naviguer et de lire des données dans un fichier xml.

Votre mémoire étant maintenant rafraichie, revenons-en au code découvert par Vladimir Zelenov :

clip_image008

Ce que dit ce code, c’est que si vous passez la variable $Data$ en paramètre de votre ProbeAction et non pas une variable utilisant la notation habituelle vue ci-dessus, ce ne seront plus les valeurs des propriétés du PropertyBag mais bien le PropertyBag complet qui sera envoyé au script !

Prenons un exemple concret :

clip_image010

Intégrée dans un module personnalisé, cette probe très simple vous permettra de copier l’intégralité du Propertybag qui y entre dans un fichier texte.
Cela peut s’avérer extrêmement utile lors du debug d’un module, lorsqu’on ne comprend pas pourquoi l’on n’obtient pas les résultats attendus !

Il est évidemment possible de créer des scripts beaucoup plus complexe, d’autant plus que Powershell permet nativement de typer un objet en tant que XML et donc de naviguer dans son arborescence.
L’exemple suivant (fictif) récupère le résultat de la requête SnmpWalk d’un tableau snmp contenant des métriques systèmes et en réorganise le contenu afin de créer des PropertyBags plus lisibles :

clip_image012

Bref, les possibilités sont infinies…A vous de jouer !

SCCM - Les clients ne reçoivent plus les mises à jour après une restauration ou un changement de serveur

Suite au remplacement du serveur de site dans une infrastructure SCCM, les clients ne recevaient plus aucune mise à jour.

L’analyse du fichier de log UpdatesDeployment.log révèle le message “EnumerateUpdates for action (UpdateActionInstall) - Total actionable updates = 0 ' “.

Bien qu’il ne s’agisse pas à proprement parler d’une erreur, cette information est manifestement erronée : il y a bien des mises à jour manquantes, et l’exécution de la commande powershell suivante sur un client en donne la liste :

get-wmiobject -query "SELECT * FROM CCM_UpdateStatus" -namespace "root\ccm\SoftwareUpdates\UpdatesStore" | where {$_.status -eq "Missing"} 

Le client SCCM n’en reconnait pourtant aucune comme actionnable, comme le montre cette nouvelle commande qui ne renvoie rien :

get-wmiobject -query "SELECT * FROM CCM_SoftwareUpdate" -namespace "ROOT\ccm\ClientSDK"

Il faut savoir qu’à chaque synchronisation du catalogue WSUS, SCCM incrémente la version du catalogue. Cela permet aux agents de savoir si une version plus récente que celle qu’ils ont déjà téléchargé est disponible.

Or, lors du changement de serveur ou de la restauration d’une sauvegarde, il arrive que ce compteur reparte de 0… Si votre infrastructure SCCM existe depuis longtemps, il pourrait donc falloir des milliers de mise à jour du catalogue avant que la version n’atteigne à nouveau celle attendue par les agents!

Heureusement, le correctif est simple : il suffit de modifier dans le registre la version du catalogue afin de reprendre là où les agents s’étaient arrêté.

Commencons donc par identifier la version du catalogue qu’attendent les agents, à l’aide de la requête SQL suivante qui indique la plus haute valeur attendue :

;WITH XMLNAMESPACES ( DEFAULT 'http://schemas.microsoft.com/SystemsCenterConfigurationManager/2009/07/10/DesiredConfiguration') 
SELECT MAX(CI.SDMPackageDigest.value('(/DesiredConfigurationDigest/SoftwareUpdateBundle/ConfigurationMetadata/Provider/Operation[@Name="Detect"]/Parameter/Property[@Name="MinCatalogVersion"]/@Value)[1]', 'int')) MinCatalogVersion  
FROM [CI_ConfigurationItems] as CI  
WHERE CIType_ID = 8  

Il faut ensuite incr��menter d’une unité cette valeur, puis l’insérer dans la base de registre dans les clés suivantes :

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SMS\Components\SMS_WSUS_SYNC_MANAGER]
"ContentVersion"=x
"SyncToVersion"=x
"LastAttemptVersion"=x

Enfin, il faut exécuter une nouvelle synchronisation du catalogue dans SCCM afin que sa valeur reflète les modifications effectuées (ou attendre la prochaine synchronisation planifiée), puis exécuter un Machine policy refresh suivi d’un Update evaluation cycle sur les agents si vous souhaitez forcer le téléchargement des mises à jour.