PI Services

Le blog des collaborateurs de PI Services

SCOM 2012 : Erreur « PSRemotingTransportException Job Failure » lors de l’utilisation de sessions powershell distantes

Certains contextes peuvent nécessiter l’utilisation de cmdlet SCOM depuis un ordinateur ne permettant pas l’installation de la console, et donc ne permettant pas d’exécuter ces cmdlet localement ; par exemple en cas de centralisation des scripts de l’entreprise sur un serveur Windows 2003.

Dans ce cas, une des solutions les plus évidentes est le recours aux Remote Sessions Powershell : les cmdlet sont bien appelés par le serveur ne bénéficiant pas de la console SCOM, mais ils sont en réalité exécutés par un serveur où elle est cette fois installée.

Le but de ce billet n’est pas de détailler ce fonctionnement, qui n’a d’ailleurs rien de spécifique à SCOM ; mais ce dernier peut par contre être responsable de certains dysfonctionnements des Remote Sessions.

C’est notamment le cas lors de l’exécution de scripts nécessitant des traitements coûteux en mémoire, qui peuvent provoquer l’erreur suivante :

Processing data for a remote command failed with the following error message: The WSMan provider host process did not return a proper response.  A provider in the host process may have behaved improperly. For more information, see the about_Remote_Troubleshooting Help topic.

    + CategoryInfo          : OperationStopped: (System.Manageme…pressionSyncJob:PSInvokeExpressionSyncJob) [], PSRemotingTransportException

+ FullyQualifiedErrorId : JobFailure

Ce message, assez peu explicite, indique en réalité que la session powershell distante utilise trop de mémoire par rapport à ce qui est alloué : en effet, cette allocation est limitée par défaut à 150Mo, comme le confirme le Powershell suivant (à exécuter sur le serveur où se trouve la console SCOM) :

winrm get winrm/config

clip_image002

En partant de ce constant, deux solutions s’offrent à nous : optimiser le script pour qu’il utilise moins de mémoire, ou augmenter la mémoire allouée à chaque Remote Session Powershell.

Libre à vous de choisir la quantité de mémoire allouée qui vous semblera en adéquation avec les besoins de votre script, en gardant en tête qu’une valeur excessive peut entraîner la saturation du serveur et compromettre sa stabilité.

winrm set winrm/config/winrs `@`{MaxMemoryPerShellMB=`"1024`"`}

Le problème devrait désormais être corrigé.

SCOM 2012 : Alimenter un groupe depuis une source SQL

Imaginons une entreprise qui, pour ses besoins propres d’administration, détermine dans une base de données de référence (CMDB) des ensembles de serveurs sans lien apparent les uns avec les autres, et donc sans possibilité de créer une Discovery basée sur une clé de registre ou une requête WMI.

clip_image002

Le besoin de retrouver cette organisation logique dans SCOM pour positionner des overrides ou cibler des vues peut vite se faire sentir, et il semble alors évident d’intégrer ces serveurs dans un même groupe SCOM.

SCOM ne permet malheureusement pas par défaut d’utiliser une source externe pour peupler un groupe, il faudra donc en passer par la manipulation du code source XML du management pack contenant le groupe afin d’arriver à nos fins. Prêts ? Suivez le guide !

Exportez le management pack contenant le groupe à modifier, et ouvrez le fichier XML dans un éditeur de texte.

Partie 1 : Manifest

Ici, il est nécessaire d’incrémenter la version afin de pouvoir importer le management pack par la suite.

Il faut également s’assurer que les librairies Microsoft.Windows.Library et Microsoft.SystemCenter.InstanceGroup.Library sont référencées :

<ManagementPack ContentReadable="true" SchemaVersion="2.0" OriginalSchemaVersion="1.1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<Manifest>

<Identity>

<ID>TEST</ID>

<Version>1.0.0.1</Version>

</Identity>

<Name>TEST</Name>

<References>

<Reference Alias="MicrosoftWindowsLibrary7585010">

<ID>Microsoft.Windows.Library</ID>

<Version>7.5.8501.0</Version>

<PublicKeyToken>31bf3856ad364e35</PublicKeyToken>

</Reference>

<Reference Alias="MicrosoftSystemCenterInstanceGroupLibrary7585010">

<ID>Microsoft.SystemCenter.InstanceGroup.Library</ID>

<Version>7.5.8501.0</Version>

<PublicKeyToken>31bf3856ad364e35</PublicKeyToken>

</Reference>

</References>

</Manifest>

Partie 2 : TypeDefinitions

Nous allons maintenant définir le groupe qui sera peuplé via la base SQL, ainsi que sa relation.

Pour le groupe, il n’y a rien de très spécial, il y a de fortes chances que votre MP contienne déjà une classe de ce type s’il contient déjà un groupe ; sinon rajoutez la ligne <ClassTypeID …. /> entre les balises <ClassTypes> </ClassTypes> et remplacez Test.Group par un ID correspondant à votre groupe.

Il est, par contre, plus probable qu’il vous faille rajouter la relation. Reprenez le bloc <RelationshipTypes> </RelationshipTypes> et modifiez les parties en rouge pour les adapter à votre contexte.

<TypeDefinitions>

<EntityTypes>

<ClassTypes>

<ClassType ID="Test.Group" Accessibility="Public" Abstract="false" Base="MicrosoftSystemCenterInstanceGroupLibrary7585010!Microsoft.SystemCenter.InstanceGroup" Hosted="false" Singleton="true" Extension="false" />

</ClassTypes>

<RelationshipTypes>

<RelationshipType ID="GroupPopulation.TESTGroupContainsWindowsComputers" Accessibility="Internal" Abstract="false" Base="System!System.Containment">

<Source ID="Source" MinCardinality="0" MaxCardinality="2147483647" Type="Test.Group" />

<Target ID="Target" MinCardinality="0" MaxCardinality="2147483647" Type="MicrosoftWindowsLibrary7585010!Microsoft.Windows.Computer" />

</RelationshipType>

</RelationshipTypes>

</EntityTypes>

</TypeDefinitions>

Section 3: <Monitoring>

Cette section est normalement déjà présente dans votre management pack ; c’est elle qui contient les différents moniteurs et règles, en particulier celle qui nous intéresse ici : la règle de découverte liée à la classe du groupe.

C’est elle qu’il va vous falloir identifier (elle est reconnaissable à sa ligne <Discovery=…. Qui doit contenir la mention Target="TEST.Group"), puis modifier de façon à intégrer un script VBS qui se connectera au serveur SQL et récupérera la liste des serveurs à intégrer au groupe.

Attention : il est nécessaire que le compte SCOM ait accès à la base de données SQL de référence qui contient la liste de vos serveurs !
L’extrait ci-dessous montre l’ensemble de la Discovery que vous devez réutiliser à la place de votre actuelle, en surlignant les parties à adapter à votre contexte :

<Discovery ID="TEST.Group.DiscoveryRule" Enabled="true" Target="TEST.Group" ConfirmDelivery="false" Remotable="true" Priority="Normal">

<Category>Discovery</Category>

<DiscoveryTypes>

<DiscoveryClass TypeID="TEST.Group" />

</DiscoveryTypes>

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

<IntervalSeconds>300</IntervalSeconds>

<SyncTime />

<ScriptName>TESTGroupDiscovery.vbs</ScriptName>

<Arguments>$MPElement$ $Target/Id$</Arguments>

<ScriptBody>Dim SourceId

Dim ManagedEntityId

Dim oAPI

Dim oDiscoveryData

Dim objConnection,objConnection2

Dim oRS,oRS2

Dim sConnectString,sConnectStringOPSMGR

SourceId = WScript.Arguments(0)

ManagedEntityId = WScript.Arguments(1)

Set oAPI = CreateObject("MOM.ScriptAPI")

Set oDiscoveryData = oAPI.CreateDiscoveryData(0,SourceId,ManagedEntityId)

sConnectString = "Driver={SQL Server}; Server=REFERENCESQLSERVER\INSTANCE; Database=REFERENCEDATABASE;"

sConnectStringOPSMGR = "Driver={SQL Server}; Server=SCOMSQLSERVER; Database=OperationsManager;"

Set objConnection = CreateObject("ADODB.Connection")

objConnection.Open sConnectString

Set objConnection2 = CreateObject("ADODB.Connection")

objConnection2.Open sConnectStringOPSMGR

Set oRS = CreateObject("ADODB.Recordset")

oRS.Open "SELECT ServerName FROM VServers ", objConnection

Set groupInstance = oDiscoveryData.CreateClassInstance("$MPElement[Name='TEST.Group']$")

While Not oRS.EOF

Set oRS2 = CreateObject("ADODB.Recordset")

oRS2.Open "SELECT DISTINCT Id,Path FROM [OperationsManager].[dbo].[ManagedEntityGenericView] WHERE FullName LIKE 'Microsoft.SystemCenter.HealthService:" + LTRIM(RTRIM(oRS.Fields("ServerName"))) + "%'",objConnection2

If Not oRS2.BOF Then

oRS2.MoveFirst

End If

If Not oRS2.EOF Then

Set serverInstance = oDiscoveryData.CreateClassInstance("$MPElement[Name='MicrosoftWindowsLibrary7585010!Microsoft.Windows.Computer']$")

serverInstance.AddProperty "$MPElement[Name='MicrosoftWindowsLibrary7585010!Microsoft.Windows.Computer']/PrincipalName$",oRS2.Fields("Path")

Set relationshipInstance = oDiscoveryData.CreateRelationshipInstance("$MPElement[Name='GroupPopulation.TESTGroupContainsWindowsComputers']$")

relationshipInstance.Source = groupInstance

relationshipInstance.Target = serverInstance

oDiscoveryData.AddInstance relationshipInstance

End If

oRS.MoveNext

Wend

objConnection.Close

objConnection2.Close

Call oAPI.Return(oDiscoveryData)

</ScriptBody>

<TimeoutSeconds>120</TimeoutSeconds>

</DataSource>

</Discovery>

Section 4: <LanguagePacks>

Il s’agit simplement ici de rajouter les DisplayString pour les classes nouvellement créées, par exemple :

<DisplayStrings>

<DisplayString ElementID="GroupPopulation.TESTGroupContainsWindowsComputers">

<Name>TEST_from_SQL</Name>

</DisplayString>

</DisplayStrings>

Il ne reste plus ensuite qu’à réimporter ce management pack, et au bout de quelques minutes votre groupe devrait être peuplé par les serveurs contenus dans votre table SQL (à condition bien sûr que ces serveurs soient déjà connus par SCOM, et donc qu’un agent soit déployé dessus !).

image

Active Directory Replication Status Tool : "License has expired"

 

Cet outil permet de surveiller la réplication entre les contrôleurs de domaine sur l’ensemble d’une même forêt.

clip_image002

Pour les personnes ayant installé la version 1.0 Build 2.3.20717.1 (ou antérieur) de cet outil, un message d’erreur va apparaître : « The License has expired. Please download a new version of the Active Directory Replication Status Tool from the Microsoft website ».

clip_image004

Depuis le 08 juin 2013, les versions 2.3.20717.1 ou antérieures sont confrontées à cette erreur. Cela est dû au fichier License.xml que l’on trouve dans le répertoire C:\Program Files (x86)\Microsoft Active Directory Replication Status Tool\Licensing. En ouvrant le fichier, la date d’expiration apparaît :clip_image006

Ce fichier n’est pas modifiable puisqu’il est signé numériquement.

Afin de corriger ce problème, il est obligatoire de télécharger la dernière version de l’outil disponible depuis le 06 avril à l’adresse suivante : http://www.microsoft.com/download/details.aspx?id=30005

La version disponible est la build 2.4.20.717.1.

clip_image008

Elle expirera le 30 Novembre 2013.

clip_image010

Powershell: Générateur de Mot-de-passe

Il arrive souvent dans le cadre de migration ou de création de nouvelle forêt/Domaine Active Directory, de générer des nouveau mots de passe pour les nouveau comptes. Afin d’automatiser cette opération, le PowerShell nous permet de scripter cette étape et de la faire correspondre à la stratégie de mot-de-passe mise en œuvre.

Voici un exemple de fonction qui permet de générer des mots-de-passe correspondant à la stratégie par défaut (complexité et 8 caractères):

#============================================
# Fonction de création de Password aléatoire   
#============================================
function RandomPassword ([int]$intPasswordLength)
       {
          if ($intPasswordLength -lt 4) {return "password cannot be <4 chars"}   # -lt inférieur à
             
          $strNumbers = "1234567890"
          $strCapitalLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
          $strLowerLetters = "abcdefghijklmnopqrstuvwxyz"
          $strSymbols = "@-?!#"
          $rand = new-object random
 
          for ($a=1; $a -le $intPasswordLength; $a++)  #inférieur -le inférieur ou égal à
               {
                    if ($a -gt 4) #supérieur à
                       {
                             $b = $rand.next(0,4) + $a
                             $b = $b % 4 + 1
                       } else { $b = $a }
                    switch ($b)
                       {
                             "1" {$b = "$strNumbers"}
                             "2" {$b = "$strCapitalLetters"}
                             "3" {$b = "$strLowerLetters"}
                             "4" {$b = "$strSymbols"}
                       }
                    $charset = $($b)
                    $number = $rand.next(0,$charset.Length)
                    $RandomPassword += $charset[$number]
               }
          return $RandomPassword
       }
 
#######################
# PROGRAMME PRINCIPAL
#######################
                # Génération aléatoire du Password en lançant la fonction définie précédemment                 
             RandomPassword 8
              

Il suffit de modifier le programme principal pour générer des mots-de-passe plus longs. Il ne reste plus qu’à intégrer et appeler la fonction dans un script global de création des comptes Active Directory.

PowerShell : Ajout d’entrée DNS

Dans le cadre d’installation de certaines plateformes, il est parfois nécessaire de créer de nombreuses entrées DNS.

Pour réaliser cette opération, l’interface graphique peut s’avérer fastidieuse et source d’erreurs. Il peut donc être intéressant de réaliser quelques commandes pour réaliser ces ajouts :

Pour cela, les entrées DNS à créer peuvent être stockées dans un fichier csv comme ici dans le cadre de Lync Server:

image

Une fois le fichier construit, il suffit de le parser et de construire la commande dnscmd:

   1:  $file=import-csv C:\sources\dnslync.csv -Delimiter ";"
   2:   
   3:  foreach ($entry in $file)
   4:  {
   5:     dnscmd v-DNS-01 /recordAdd mazone.org $entry.Host $entry.type $entry.IP
   6:  }

L’exécution confirme la création des entrées:

image

Les entrées sont ainsi créées dans la zone précisée.