PI Services

Le blog des collaborateurs de PI Services

Création d’un groupe de ressource Cluster en Powershell

 

Vous souhaitez créer en ligne de commande un groupe de ressource Cluster.

Pour cela, il faut utiliser la ligne de commande suivante :

([wmiclass]"root\MSCluster:MSCluster_ResourceGroup").CreateGroup(“NomDuGroupe”, XXX)

Ou XXX représente l’identifiant du groupe de ressource que vous voulez créer.

Par exemple : pour créer un groupe de ressource Hyper-V réplica Broker, vous devez saisir l’ID 115 soit :

([wmiclass]"root\MSCluster:MSCluster_ResourceGroup").CreateGroup(“NomDuGroupe”, 115)

 

Maintenant, pour créer un groupe de ressource DHCP Cluster, l’identifiant correspondant est le 102 soit :

([wmiclass]"root\MSCluster:MSCluster_ResourceGroup").CreateGroup(“NomDuGroupe”, 102)

 

Ci-dessous, une capture d’écran qui vous donnera l’ID associé à un type de groupe de ressource Cluster.

 

image

Vérification de droits d’accès à une ressource en Powershell via wmi

 

Vous souhaitez contrôler l’accès à un fichier / répertoire en ligne de commande.

Pour cela, vous pouvez utiliser la classe Win32_Directory qui contient une méthode GetEffectivePermission. Celle ci permet de déterminer si le compte dispose des autorisations qui seront spécifiés dans notre commande.

 

Tout d’abord, récupérer le répertoire (pour l’exemple) que vous désirez contrôler.

image

 

En regardant maintenant les propriétés via la commande (gwmi Win32_directory -filter "name = 'c:\\temp'") |gm , on peut voir l’accès à la méthode GetEffectivePermission.

image

 

Nous voulons contrôler si l’utilisateur courant dispose des droits d’accès en écriture sur le répertoire c:\temp.

Pour cela, il faut saisir la valeur décimale 2 pour la méthode GetEffectivePermission.

Si l’utilisateur à les droits en écriture sur cette ressource, la commande nous renverra True. Dans le cas contraire, la commande nous renverra False.

Exemple :

(gwmi Win32_directory -filter "name = 'c:\\temp'").GetEffectivePermission(X)

X correspondant au droit contrôlé.

image

L’utilisateur peut donc accéder en écriture dans le répertoire.

 

Ci dessous un tableau contenant les valeurs à indiquer à la fonction GetEffectivePermission() pour le contrôle d’un droit spécifique

image

Powershell : Introduction à la gestion d'événements

Introduction

Le thème abordé est la gestion d'événements sous Powershell. Il s'agit d'une notion peu connue dans ce langage de scripting mais permettant d'interagir automatiquement avec le système si un événement est détecté. Ceux-ci peuvent être : 

  • Le démarrage d'un process
  • Un changement sur un dossier
  • La fin d'un timer
  • Un changement d'état dans un job Powershell
  • ...

Dans un premier, nous verrons comment connaître les objets pouvant être observés et comment gérer les événements via la Cmdlet Register-ObjectEvent, ensuite nous traiterons le cas particulier des événements WMI, puis celui des événements liés à la console Powershell. Enfin, un exemple d'utilisation sera montré (détection des changements dans un dossier).

Avant de débuter, il faut savoir que les événéments gérés, ne le sont que dans la session Powershell en cours (c'est à dire que la remontée d'événements s'arrête dès qu'on quitte la session Powershell). Il existe toutefois une méthode pour créer une gestion d'événements permanente, mais elle ne fonctionne que pour les événements en WMI. Pour faciliter sa mise en place, je vous invite à vous tourner vers l'excellent module PowerEvents : http://powerevents.codeplex.com/.

Les événements des objets Powershell

Pour connaître si un objet Powershell peut être géré via des événements, il suffit d'utiliser la commande Get-Member.

En exécutant la commande suivante :

 

Il est aussi possible de les obtenir via la méthode GetEvents :

 

On obtient le résultat :

image

On remarque que 2 de ces membres sont de type Event (Elapsed et disposed). Ces derniers vont donc pouvoir être utilisé via la cmdlet Register-ObjectEvent.

Exemple pour l’événement Elapsed (fin d’un timer) :

Lorsque l'on lance cette commande, elle crée un job Powershell (similaire à ceux lancés par la commande Start-Job). Dans cet exemple nous voulons monitorer la fin d'un timer pour récupérer les données transmises par un job Powershell à chaque seconde. On crée un objet de type Timer qui a un interval de 1 seconde (en millisecondes). Ce dernier tourne en boucle grâce à l'attribut autoreset. L'événements à surveiller est "Elapsed". On le retrouve dans la commande Register-ObjectEvent avec le paramètre EventName. Le paramètre Action définit le processus exécuté lorsque l'événment est détecté. Il s'agit d'un scriptblock (entre accolades, ici notre variable “ActionTimer”).

Il est possible de passer des données pour qu'elles soient traiter dans l'action. Cela se fait via le paramètre MessageData (N'importe quel type d'objet peut être consommé). Ces données sont ensuite accessible via la variable $event.MessageData. Nous récupérons donc la propriété Id de l'objet Job Powershell afin de recevoir les données via la commande Receive-Job. Pour que l'événement soit remonté , il est obligatoire de fournir l'objet Timer en tant qu'InputObject. Enfin, SourceIdentifier est simplement le nom du job.

Si l'on souhaite arrêter d'observer les événements d'un objet Powershell, il faut utiliser la commande Unregister-ObjectEvent conjointement à Get-EventSubscriber qui récupère l'ensemble des événements observés.

 

Cette commande arrête la remontée de tous les événements. On peut bien entendu filtrer les événements à ne plus gérer via la cmdlet Where-Object par exemple.

Les événements en WMI

En WMI, il existe de nombreuses classes WMI permettant la gestion d'événements. Pour toutes les récupérer et retrouver celle qui vous intéresse, utilisez cette commande :
 

On remarque entre autre des classes pour récupérer :

  • les changements dans les clés de registre
  • les démarrages et arrêts de processus
  • l'arrêt ou la fermeture de session d'un utilisateur
  • l'ajout d'un lecteur (disque dur, clé usb)
  • ...

Pour surveiller un événements en WMI on utilise cette fois la commande Register-WMIEvent.

Exemple de détection de lancement d'un nouveau processus :

La requête effectue une recherche toutes les 2 secondes sur la classe __InstanceCreationEvent. Elle est basé sur le langage WQL dont on peut retrouvé la syntaxe sur le lien suivant :
http://msdn.microsoft.com/en-us/library/windows/desktop/aa394606(v=vs.85).aspx

On retrouve les paramètres sourceIdentifier et Action vues précédemment avec la commande Register-ObjectEvent.

Les événements de la console Powershell

On peux écouter deux événements sur la console Powershell. Lorsqu'elle est fermée (Exiting) et lorsqu'elle est en état Idle (OnIdle). Ainsi, on peut exécuter des actions quand l'un de ces états est atteint. Cette opération s'effectue via la commande Register-EngineEvent :

 

La syntaxe est semblable à celle de la commande Register-ObjectEvent sauf que c'est le paramètre SourceIdentifier qui contient le non de l'événement (on aura donc 2 SourceIdentifier possibles : Powershell.Exiting et Powershell.OnIdle).

NB : Depuis Powershell 3.0, un troisième événement semble exister : WorkflowJobStartEvent. Cependant, il n'est à l'heure actuelle (au 23/05/2014) pas documenté.

Exemple d'utilisation :

Le script commenté ci-dessous déplace les fichiers d'un répertoire à un autre lorsqu'un nouveau fichier apparaît. Un premier événement sur l'objet de type FileSystemWatcher est récupéré : Created. Lors de la remontée de cet événement (à chaque création de fichier) le chemin du fichier est retourné. Un second objet de type Timer est surveillé. A chaque seconde, il récupère les résultats du Job précédent (les chemins de fichiers). Il les ajoute à une liste puis il traîte cette liste en essayant de déplacer les fichiers. Deux résultats sont alors possibles :

  • Si le transfert réussi, alors le chemin initial est supprimé de la liste des fichiers à transférer.
  • Si le déplacement échoue (fichier en cours d'écriture par exemple) alors il retentera de le déplacer au prochain déclenchement de l'événement (après 60 tentatives le transfert n'est plus réalisé).

Les différentes opérations sont logguées dans l'observateur d'événements.

NB : Si le fichier existe déjà à la destination, un horodatage est ajouté en suffixe du nom du fichier.

SCOM et alertes WMI: Script de redémarrage du service wmi et de ses dépendances

 

Le script suivant récupère les alertes ouvertes pour une machine, qui correspondent a des erreurs de requetage wmi. Si il en trouve au moins une dont le repeatcount est supérieur a une valeur donnée en variable, il redémarre le service wmi et ses dépendances et clos les alertes correspondantes.

   1:  
   2: $scomms="scom2k12sp1srv1"
   3: $targetcomputer="scom2k12sp1dc1"
   4: $repeatcountthreshold="1"
   5: $wmi="WinMgmt"
   6:  
   7: $scomcred=Get-Credential -Credential "scom2k12sp1maq1\administrator"
   8: $arrwmialerts=@(“Operations Manager failed to run a WMI query","Workflow Initialization: Failed to start a workflow that queries WMI for performance data","Workflow Initialization: Failed to start a workflow that queries WMI for WMI events","Operations Manager failed to run a WMI query for WMI events",
   9: "Operations Manager failed to run a performance data WMI query","Workflow Initialization: Failed to start a workflow that queries WMI","Script Based Test Failed to Complete")
  10:  
  11: Import-Module operationsmanager
  12:  
  13: New-SCOMManagementGroupConnection -ComputerName $scomms -Credential $scomcred
  14:  
  15: $arrcomputernewalertnames=Get-SCOMAlert | Where-Object {$_.Resolutionstate -eq "0" -and $_.NetbiosComputerName -eq $targetcomputer -and $_.RepeatCount -gt $repeatcountthreshold -and $_.IsMonitorAlert -eq $false } | Select-Object -Property name -ExpandProperty name
  16: $arrcomputernewalerts=Get-SCOMAlert | Where-Object {$_.Resolutionstate -eq "0" -and $_.NetbiosComputerName -eq $targetcomputer -and $_.RepeatCount -gt $repeatcountthreshold -and $_.IsMonitorAlert -eq $false }
  17:  
  18:  
  19:  
  20: $matchingalerts=0
  21: foreach ($wmialert in $arrwmialerts)
  22: {
  23:   if ($arrcomputernewalertnames -contains $wmialert)
  24:     {
  25:     Write-Host -ForegroundColor Red -BackgroundColor White "L'alerte "$wmialert.ToUpper()" a été répétée plus de $repeatcountthreshold fois sur $targetcomputer"
  26:     Write-Host -ForegroundColor Yellow "Fermeture de l'alerte "$wmialert.ToUpper()" avant redemarrage du service $wmi et de ses dependances"
  27:     $matchingalerts= ($matchingalerts + 1)
  28:     $arrcomputernewalerts | Where-Object {$_.Name -like "$wmialert*"} | foreach {Set-SCOMAlert -ResolutionState 255 -Alert $_ }
  29:     }
  30: }
  31:  
  32:  
  33: ###FUNCTIONS###
  34: Function Restart-Wmi ($targetcomputer)
  35: {
  36: Invoke-Command -ComputerName $targetcomputer -Credential $scomcred -ScriptBlock {
  37: $winmgmt=Get-Service -Name Winmgmt
  38: $winmgmtrundep=$winmgmt.DependentServices | Where-Object {$_.Status -eq "Running"}
  39: Stop-Service -Name Winmgmt -Force -ErrorAction SilentlyContinue
  40: Start-Sleep -Seconds 5
  41: Start-Service -Name Winmgmt -ErrorAction silentlycontinue
  42: Start-Sleep -Seconds 5
  43:  
  44: foreach ($dep in $winmgmtrundep) 
  45:     {
  46:     if (Get-WmiObject win32_service | Where-Object {$_.Name -eq $dep.Name -AND $_.state -ne "running" -AND $_.startmode -eq "Auto"}) 
  47:         {
  48:         write-host -ForegroundColor Green "demarrage de la dependance "$dep.Name.ToUpper()""
  49:         Start-Service -Name $dep.Name -erroraction SilentlyContinue -ErrorVariable ("start_"+$dep.Name+"_error").ToString()
  50:         }
  51:     }
  52:  
  53: }
  54: }
  55:  
  56:  
  57: Function NewEventSource
  58: {
  59:     if(!(Test-Path 'HKLM:\SYSTEM\CurrentControlSet\services\eventlog\Operations Manager\RestartWMIScript'))
  60:     {
  61:     New-EventLog -LogName "Operations Manager" -Source RestartWMIScript
  62:     }
  63: }
  64: ###FUNCTIONS###
  65:  
  66:  
  67:  
  68:  
  69:  
  70:  
  71: if ($matchingalerts -gt 0)
  72: {
  73: write-host -ForegroundColor Yellow "Redemarrage du service WinMgmt et de ses dependances"
  74: Restart-Wmi $targetcomputer
  75: }
  76: else
  77: {
  78: write-host -ForegroundColor Green "Pas d'alertes correspondantes trouvées"
  79: Write-Host -ForegroundColor Green "Pas de redemarrage du service WinMgmt et de ses dependances"
  80: exit
  81: }
  82:  
  83:  
  84:  
  85:  
  86:  
  87: ###VERIFICATION ET LOG D'ERREURS
  88:  
  89:  
  90: Invoke-Command -ComputerName $targetcomputer -Credential $scomcred -ScriptBlock {
  91: param($targetcomputer)
  92: $wmi=Get-Service -Name WinMgmt -ComputerName $targetcomputer
  93: if ($wmi.Status -ne "Running")
  94: {
  95: $function:NewEventSource
  96: Write-EventLog -LogName 'Operations Manager' -Source RestartWMIScript -EntryType Error -EventId 1002 -Message "erreur de demarrage du service winmgmt"
  97: }
  98:  
  99: } -Argumentlist $targetcomputer
 100:  
 101: ###VERIFICATION ET LOG D'ERREURS
 102:  
 103:  
 104:  

Powershell : Gestion à distance

Introduction

L’une des forces de Powershell est la gestion à distance de serveurs, de postes clients et d’applications (comme Exchange, Sharepoint,…). Communément appelée Remote Powershell, elle est apparue avec Powershell 2.0 et donc disponible à partir de Windows Server 2003 (R2) SP2. Cette fonctionnalité n’est pas activée par défaut sur les systèmes d’exploitation Windows hors Windows 2012 (R2). Pour réaliser cette opération il faut lancer la commande suivante en mode administrateur :

001
Enable-PSRemoting

Cette commande permet de démarrer le service WinRM et d’ouvrir les règles de firewall adéquates si celui-ci est activé (port 5985).

Dans cet article, nous verrons comment se connecter à une machine (qu’elle soit dans le même domaine ou dans un workgroup) ou à une application comme Exchange, comment donner la possibilité à un utilisateur de se connecter via Remote Powershell et enfin l’accès WMI distant.

Entre deux ordinateurs du domaine

Il s’agit du cas le plus simple. Pour se connecter à une machine du même domaine, il suffit d’utiliser la commande suivante :

001
Enter-PSSession -ComputerName SERVER01

Il est possible de spécifier l’utilisateur avec lequel on souhaite se connecter via le paramètre Credential :

001
Enter-PSSession -ComputerName SERVER01 -Credential SERVER01\Administrator

Ainsi, un prompt demandant le mot de passe apparaîtra.

Depuis un ordinateur d’un workgroup vers un ordinateur en domaine (et vice versa)

Pour se connecter à une machine appartenant à un domaine différent ou à un workgroup, il est nécessaire que le poste source contienne l’ordinateur distant dans sa liste de client de confiance. Pour ajouter une nouvelle machine, il faut utiliser la commande suivante en mode administrateur :

001
002
003
Set-Item WSMan:\localhost\Client\TrustedHosts -Value *
#OU
Set-Item WSMan:\localhost\Client\TrustedHosts -Value SERVER02

Le paramètre Value peut prendre les valeurs suivantes :

  • un nom explicit d’une machine (SERV01)
  • * : pour accepter toutes les machines (Ceci n’est pas recommandé)
  • *.myenterprise.com : pour accepter toutes les machines possédant le suffixe DNS myenterprise.com

Connexion à distance à une application (Exchange)

Via le couple de commande New-PSSession / Import-PSSession, il est possible de se connecter à une infrastructure Exchange et importer les commandes relatives à la messagerie de Microsoft sur son poste sans avoir à installer le snapin. De plus, seul les commandes accessibles à l’utilisateur seront chargées sur le poste utilisateur (grâce aux mécanismes de RBAC).

001
002
$Session = New-PSSession –ConfigurationName Microsoft.Exchange -ConnectionUri ` http://MYSERVER/powershell -Credential MYENTERPRISE\User_1
Import-PSSession $Session -AllowClobber | Out-Null

La première ligne de commande crée une session qui se connecte à l’infrastructure Exchange (Attention il faut modifier la valeur MYSERVER et le nom d’utilisateur avec vos valeurs) tandis que la seconde importe les commandes sur l’ordinateur initialisant la connexion.

Sessions distantes et permissions

Afin de se connecter à distance, il est nécessaire de faire partie du groupe Administrators (ou Remote Management Users pour Windows 2012 et supérieur) soit en étant connecté directement avec le bon compte (par exemple via un utilisateur administrateur du domaine) soit en s’authentifiant en tant qu’administrateur via le paramètre Credential vu précédemment. Il est aussi possible de donner l’accès à d’autres utilisateurs via la commande suivante :

001
002
003
Set-PSSessionConfiguration Microsoft.Powershell -ShowSecurityDescriptorUI -Force
#Si l'on est sur un système 64 bits.
Set-PSSessionConfiguration Microsoft.Powershell32 -ShowSecurityDescriptorUI -Force

Une fenêtre s’affiche et il est possible d’ajouter un utilisateur ou un groupe (via le bouton Add) ainsi que des permissions associées. La permission Execute est suffisante  pour se connecter à distance.

image

NB : Sur Windows 2012 et supérieur, il est nécessaire d’ajouter une clé de registre sur l’ordinateur distant pour que les groupes Administrators et Remote Management Users aient le droit de se connecter via Remote Powershell :

Dans le noeud : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system

Il faut ajouter la clé DWord : LocalAccountTokenFilterPolicy avec la valeur 1.

Cette clé de registre s’applique aussi au chapitre suivant.

Gestion WMI à distance

Pour gérer le WMI à distance (via la commande Set-WmiInstance par exemple). Il faut réunir les 3 conditions suivantes sur le serveur auquel on souhaite se connecter :

  • Faire partie du groupe Administrators ou Remote Management Users ou WinRMRemoteWMIUsers__.
  • Avoir les permissions suffisantes sur la classe WMI.
  • Autoriser l’utilisateur dans la configuration DCOM du serveur.

Les deux dernières conditions sont seulement utiles dans le cas d’un utilisateur qui ne fait pas partie du groupe Administrators (ce dernier possède déjà toutes les permissions nécessaires).

    Gestion des permissions via WMI Control :
Pour cette opération il faut lancer une console MMC et ajouter le composant WMI Control. Effectuer un clic droit et choissisez Properties puis naviguer dans l’onglet Security. Dans la MMC, on sélectionne l’espace de noms qui nous intéresse et on clique sur le bouton Security. Cliquez sur Advanced (cette option plus complète, permet éventuellement d’étendre les permissions au classes enfantes).

image image

On ajoute l’utilisateur ou le groupe avec au minimum les permissions Enable Account et Remote Enable. Il sera surement nécessaire d’ajouter d’autres droits suivants l’action que l’on souhaite réaliser.

image

Autorisation de l’utilisateur dans la configuration DCOM :

En lançant la console dcomcnfg, aller dans Component Services, Computers, My Computer et effectuer un clic droit et choisir Properties.

Dans l’onglet COM Security, choisir Edit Limits dans la section Launch and Activation Permissions. Ajoutez l’utilisateur ou le groupe souhaité et activez l’ensemble des permissions pour avoir accès en local et à distance en WMI via Powershell.

image image

SCOM - WMI Probe Module Failed Execution

 

Un type d’alerte dont la répétition est particulièrement indésirable est celui des erreur liés a des requêtes WMI en échec du a des problèmes de ressources système:

HRESULT: 0x800700a4
Details: No more threads can be created in the system.

HRESULT: 0x80041001
Details: Generic failure

HRESULT: 0x80041006
Details: Out of memory

 

En effet, la gestion de la mémoire dans WMI est assez spécifique et ces erreurs sont susceptibles d’intervenir même sur des systèmes bien dimensionnés

Cette alerte qui peut être récurrente a donc une source externe a SCOM.

Ces alertes et erreurs associées peuvent être évitées en modifiant un des paramètres WMI correspondant a la mémoire.

Pour cela, sur la machine concernée par l’erreur:

  • Executez la commande wbemtest (en mode administrateur)

image

image

  • Connectez vous a l’espace de nom "root" (pas "root\default", juste "root")

image

  • Selectionnez Ouvrir une instance (ou Open an instance)

image

  • Tapez __ProviderHostQuotaConfiguration=@ et cliquez OK

image

  • Cochez la case “Locales seulement" (Local Only), selectionnez la propriété MemoryPerHost ou ThreadsPerHost selon la source de l’erreur (voir plus haut)

image

Modifiez ces valeurs de manière raisonnable (valeur double pour commencer)

 

  • Cliquez sur Enregistrer la propriété (Save Property) puis sur Enregistrer l’objet (Save Object)
  1. Redémarrer le service Windows Management Instrumentation

 

image