PI Services

Le blog des collaborateurs de PI Services

Script de rapport des erreur 500 sur IIS

 

Ce script génère un rapport texte des erreurs 500 en parsant les logs IIS d’une liste de serveurs. (Lien du script plus bas).

#SCRIPT REMONTANT LES OCCURENCES DES ERREURS '500' DANS LES LOGS IIS DE PLUSIEURS SERVEURS #INTERVALLE DE TEMPS PAR DEFAUT: Journée d'hier ($firstdate --> $date) #MODIFIER EN FONCTION, LE COMPTE UTILISE ($cred), LE CHEMIN DU RAPPORT ($rapport), LES NOMS DES SERVEURS ($FrontServers), LE CHEMIN DES LOGS ($Logpath) # #PAR DEFAUT L'INTERVALLE DE TEMPS EST CELUI DE LA JOURNEE DE LA VEILLE. $cred= Get-Credential -Credential "MYDOMAIN\" $rapport = "D:\Temp\error500.txt" $date = (get-date).Date $firstdate = (get-date).Date.AddDays(-1) $FrontServers=("SERVEUR1","SERVEUR2","SERVEUR3","SERVEUR4") $Logpath="c$\inetpub\logs\logfiles" $Header= "########### ERREURS 500 SUR LES FRONTAUX IIS ( $firstdate ---> $date ) ############## ######################################################################################################################" #suppression fichier rapport if (Test-Path $rapport) { Remove-Item $rapport } #ajout de l'entete au rapport $Header | Out-File -FilePath $rapport "" | Out-File -FilePath $rapport -Append "" | Out-File -FilePath $rapport -Append Function Get-Error500 ($Front,$cred) { #chaine 500 (!entourée de deux espaces!) $pattern=" 500 " New-PSDrive -Name "$Front`_drive" -Credential $cred -Root \\$Front\$Logpath -PSProvider FileSystem | Out-Null $logs= Get-ChildItem -Path "$Front`_drive:\*.log" -Recurse | Where-Object {$_.LastWriteTime -ge $firstdate -AND $_.LastWriteTime -lt $date} | Select-Object foreach ($log in $logs) { write-host -BackgroundColor White -ForegroundColor Blue "LOG: $log" "LOG: $log" | Out-File $rapport -Append "" | Out-File $rapport -Append get-content -Path $log | Select-String -Pattern $pattern | Select-Object -Property Line | Out-File $rapport -Append } Remove-PSDrive -Name "$Front`_drive" -Force } foreach ($Front in $FrontServers) { Write-Host -ForegroundColor Yellow "----SERVEUR $Front---- :" "----SERVEUR $Front---- :" | Out-File -Append $rapport Get-Error500 -Front $Front -cred $cred Write-Host "" Write-Host "***************************************************************************************************************" Write-Host "" "" | Out-File -Append $rapport "***************************************************************************************************************" | Out-File -Append $rapport "" | Out-File -Append $rapport }

 

Powershell & Office 365 : Provisionning de licences

Introduction

Dans Office 365, il existe plusieurs méthodes pour ajouter des licences à un utilisateur :

  • Via l'interface d'administration manuellement sur chaque utilisateur.
  • Via l'interface d'administration manuellement sur plusieurs utilisateurs.
  • Avec les cmdlets Powershell Office 365.

Dans cet article, nous allons nous intéresser à l'ajout/suppression de licences via Powershell. Le but est d'automatiser cette opération. On peut facilement imaginer des scénarios conjoints avec Dirsync. Ce dernier provisionne un compte, puis, une tâche ajoute automatiquement les licences nécessaires à l'utilisateur.

D'autre part, il est possible d'ajouter pour chaque utilisateur :

  • Une licence complète incluant tout les services de l'abonnement souscrit.
  • Certains services d'une licence afin de limiter les accès aux utilisateurs (par exemple : ne donner qu'une licence Exchange sans donner les accès à la suite Office).

    Nous nous attarderons sur ces différentes possibilités dans l'un des paragraphes suivants.

    Nous ferons un rappel sur les prérequis nécessaires à l'utilisation des cmdlets Powershell avant d'appréhender leur attribution. Nous verrons enfin un script permettant d'automatiser le processus d'ajout/suppression de services via l'utilisation des groupes de sécurité Office 365.

Pré requis

L'administration des utilisateurs Office 365 via Powershell a besoin de l'installation d'un module spécifique. Ce dernier nécessite un prérequis : Microsoft Online Services Sign-In Assistant. Ci dessous, vous trouverez le lien de téléchargement de ce dernier :

http://www.microsoft.com/en-us/download/details.aspx?id=41950

Voici maintenant les liens pour récupérer le module Powershell :

http://go.microsoft.com/fwlink/p/?linkid=236298

A titre informatif, la version 32 bits de ces composants n'est plus pris en charge et ne sera plus mis à jour par Microsoft.

 

Connexion à Office 365 et permission

Pour se connecter à Office 365, il est nécessaire d'exécuter la commande suivante :

Les informations d'authentification fourni doivent correspondre à un utilisateur possédant à minima le rôle de gestion des utilisateurs. Cette attribution permettra d'affecter les licences.

 

Licences et abonnements

Tout d'abord, nous allons commencer par récupérer les différents abonnements disponibles sur un tenant Office 365. Il s'agit de la commande :

Le résultat obtenu permet aussi de voir les licences disponibles (ActiveUnits) et utilisées. (ConsumedUnits)

Get-MsolAccountSku

Pour chacun des abonnements, il est possible d'accéder aux services disponibles. Exemple avec le premier abonnement de la liste :

ServiceStatus

Chaque service Office 365 possède donc un identifiant qui est utilise lors de l'affectation de licences à certains utilisateurs. Les services étant différents d'un plan à un autre, voici un tableau récapitulant les identifiants et les services auxquels ils donnent accès pour un abonnement de type E3 :

EXCHANGE_S_STANDARD Exchange Online (Plan 2)
MCOSTANDARD Lync Online (Plan 2)
SHAREPOINTENTERPRISE SharePoint Online (Plan 2)
SHAREPOINTWAC Office Online
OFFICESUBSCRIPTION Office ProPlus
RMS_S_ENTERPRISE Azure Active Directory Rights Management
INTUNE_O365 Intune
YAMMER_ENTERPRISE Yammer
 

Pour les autres abonnements, les services ont des noms identiques ou similaires (exemple : SHAREPOINT_S_DEVELOPER au lieu de SHAREPOINTENTERPRISE pour un abonnement développeur).

NB : J'ai noté deux spécificités sur certains services. Premièrement, la licence Office Online doit être attribué conjointement à une licence Sharepoint (on peut facilement s'en rendre compte via le portail d'administration Office 365). Enfin, les licences Yammer n'ont pas besoin d'être attribués. Cela est sans doute dû au fait que l'intégration du service dans l'offre Office 365 n'est pas terminée. Il se peut aussi que cela soit pensé pour simplifier le système. Néanmoins, il apparaît que le nombre d'utilisateurs peut dépasser le nombre de licences sans avoir de réduction de services (Il faut donc faire un suivi régulier du nombre de licences afin d'être en règle).

 

Gestion des licences utilisateurs

Attribution d'une licence complète

L'attribution d'une licence utilisateur se fait via la commande Powershell "Set-MSOLUserLicence". Il est possible d'utiliser cette commande pour un ou plusieurs utilisateurs. Le paramètre AddLicenses permet d'ajouter une licence correspondant à un plan Office 365.

Exemple d'attribution d'une licence :

NB : Il est nécessaire de fournir l'attribut AccountSkuId de l'objet obtenu avec la commande Get-MsolAccountSku.

NB2 : Si vous attribuez des licences à plusieurs utilisateurs et que le nombre restants est insuffisant, alors la cmdlet affectera quand même des licences jusqu'à épuisement de celles-ci.

Attention, avant d'attribuer une licence, il est nécessaire d'ajouter une localisation à l'utilisateur. Cette opération est automatisable avec la commande suviante :

La location est à remplacer par la valeur voulue (ici : FR).

 

Attribution d'une licence partielle

Pour l'instant nous avons vu, l'attribution d'une licence donnant accès à tous les services offert par l'abonnement Office 365. Dans certains cas, il peut être voulu de n'autoriser un utilisateur qu'à un certain nombre de services. Pour se faire, il faut créer un objet du type MsolLicenceOption. Celui-ci est une licence à laquelle on a désactivé certains services.

Exemple :

Cette cmdlet crée une licence avec un pack de service désactivant Azure Right Management Services et Lync Online.

La commande crée les options de licencing à partir d'un abonnement (AccountSkuId) et une liste de services sous forme de tableau. Les noms des services à fournir sont ceux définis dans le tableau du paragraphe "Licences et abonnements". On peut ensuite attribuer ces options de licencing via la même commande que précédemment mais en changeant de paramètre :

Script

Présentation

Le but du script ci-dessous est d'effectuer un provisioning automatique des licences Office 365 pour les utilisateurs synchronisés avec Dirsync. Celui-ci est basé sur l'utilisation des groupes de sécurité Office 365 (ce dernier peut être synchronisé via Dirsync). Chaque groupe correspond à l'attribution d'un ou plusieurs accès à des services Office 365.Ce script peut aussi bien gérer l'ajout que la suppression d'accès. Afin de ne pas perturber les accès déjà affectés à un utilisateur sont réattribués (tant qu'ils ne sont pas concerné par le script). Afin de mieux comprendre le comportement du script, voici un scénario d'exemple :

  • USER1 appartient au groupe GRP-SharepointOnline
  • GRP-SharepointOnline attribue les accès SHAREPOINTENTERPRISE et SHAREPOINTWAC
  • USER1 possède déjà un accès à Lync (via MCOSTANDARD)
  • Le script s'exécute et donne les accès à SHAREPOINT Online et Office Online à USER1
  • USER1 conserve également son accès à Lync Online.

Pour obtenir ce résultat, l'algorithme recalcule les accès de chaque utilisateur. Cette opération est réalisé en récupérant l'attribut DisabledServices de la licence utilisateur (avec Get-MsolUserLicense).

Il permet aussi de ne pas gérer certains services. Cela peut être notamment utile pour Yammer dont l'attribution de licence n'est pas à administrer.

Celui-ci a été utilisé au travers d'un runbook dans System Center Orchestrator mais il peut aussi être utilisé dans une tâche planifié. Il est possible d'imaginer des variantes de ce script. Par exemple, les licences à attribuer pourraient être stockée dans un attribut du groupe. On peut aussi supprimer l'exigence d'être un utilisateur synchronisé par Dirsync (dans ce cas le groupe devra être alimenté via la console Office 365 et non dans Active Directory).

 

Script

Exchange / Powershell : EWS et Impersonation

Introduction

Les Exchanges Web Services (EWS) sont très pratiques pour manipuler le contenu d'une boite aux lettres. Ceux-ci ont été créés pour s'intégrer dans des applications en C# mais peuvent aussi être utilisés dans un script Powershell. Grâce aux EWS, nous pouvons manipuler des dossiers, des messages, le calendrier. Il est possible de réaliser des opérations de créations (comme l'envoi d'un email), suppressions et modifications. Cependant, nous verrons qu'il est nécessaire d'avoir des droits sur la boite aux lettres d'un utilisateur ou d'utiliser un mécanisme d'impersonation pour réaliser ces opérations.


Contexte

Cet article est basé sur un retour d'expérience d'utilisation des EWS dans un environnement Exchange 2010 SP3. Le système de réservation de ressources d'une entreprise (salle, équipements) devait migrer vers Exchange. Un mécanisme de reprise de l'existant a dû être mis en place pour créer les réservations dans les calendriers des ressources et des personnes réservant la ressource.


EWS

Afin d'utiliser les Exchange Web Services dans un script Powershell, il faut installer le package permettant d'interagir avec ceux-ci.


Ce dernier est actuellement en version 2.2 et peuvent s'interfacer avec toutes les versions d'Exchange de 2007 SP1 à la dernière en date : 2013 SP1 (Les cumulatives updates n'ont pas d'importance).


Il est disponible en suivant le lien ci-dessous :

http://www.microsoft.com/en-us/download/details.aspx?id=42951


Impersonation

Les Exchange Web Services utilisent l'autodiscover pour communiquer avec une boite aux lettres spécifique.


Exemple de connexion aux EWS :



Cependant, dès que j'effectuerai une opération sur la boite aux lettres, il me faudra des droits sur cette boite aux lettres comme le contrôle total. Dans le cas contraire, j'obtiendrai des erreurs.


Donner des droits sur un grand nombre de boites aux lettres n'est pas recommandable car cela complexifie l'administration. il existe donc une seconde option permettant de se faire passer pour le compte utilisateur de la boite aux lettres. Il s'agit de l'impersonation. C’est un rôle à attribuer à un compte de service (via le mécanisme RBAC). Cette solution offre plusieurs avantages :


  • Simplicité d'administration : on peut rapidement ajouter ou supprimer les droits d'impersonation à un compte.
  • Contrôle des comptes visés : le scope des utilisateurs pouvant être "remplacer" par un compte de service peut facilement être modifié sans devoir changer les propriétés de chaque boite aux lettres.
  • Décoreller des délégations : le processus d'impersonation n'apparait pas dans les délégations et il est ainsi plus simple de faire la différence entre les deux mécanismes et les différentes autorisations.

Implémentation RBAC

Le rôle permettant l'impersonation est nommé ApplicationImpersonation. Pour l'implémenter, nous allons d'abord créer un scope, c’est-à-dire définir les utilisateurs sur lesquels le compte de service pourra faire de l'impersonation.


Dans l'exemple ci-dessous, nous créons un scope contenant toutes les boites aux lettres utilisateurs :

Puis, nous ajoutons le rôle ApplicationImpersonation à l'utilisateur souhaité en spécifiant le scope créé précédemment.


NB : Pensez à changer la valeur MYUSER par le nom d'utilisateur de du compte réalisant de l'impersonation.


Script

Ci-dessous vous trouverez différentes fonctions Powershell commentées permettant la création d’une réunion avec la possibilité de réserver une salle mais aussi la validation que ces réunions ont bien été créées. Ces fonctions gèrent l’impersonation tant que le compte avec lequel la connexion aux EWS possède ce droit sur les boites aux lettres visées.

 

Fonction de création de réunions :


 

Fonction de validation de la réunion dans le calendrier utilisateur :

Cette fonction valide qu’une réunion possédant les bonnes ressources ainsi que les bonnes dates de début et de fin existe dans le calendrier de l’utilisateur.


 

Elle permet aussi de vérifier qu’il n’y a pas eu de création de doublons dans le calendrier (utile si un script de création de réunion à été exécuté plusieurs fois).

 

Fonction de validation de la réunion dans le calendrier de la boîte aux lettres de ressources :

Cette fonction cherche une réservation de la ressource en validant les dates et heures ainsi que le nom de la personne ayant créé cet objet. Cette vérifications s‘effectue sur le calendrier de la boite aux lettres de ressource. Le statut de la réservation est aussi vérifié (valeur attendue : Accept) afin d’être certain que la ressource n’ait pas été réservée pas une autre personne.


Tips

La création de nombreuses réservations peut engendrer un grand nombre d'envoi d'email aux utilisateurs ayant réservés ces ressources. En effet, ils vont recevoir des réponses des ressources (acquittement ou refus de la demande) si le système de réservation automatique a été activé (Resource booking attendant). Une solution de contournement peut être mise en place pendant la phase de migration. Elle consiste à limiter le nombre de destinataires à 0 lors de l'envoi d'un mail par la boite aux lettres de ressources.


Pour réaliser cette opération, il suffit de lancer une invite de commande Powershell Exchange (EMS) et d'exécuter la commande suivante :


Ou bien, si l'on souhaite changer la valeur sur toutes les boites aux lettres de salles en une seule commande (on peut remplacer RoomMailbox par EquipmentMailbox pour les boites aux lettres d'équipements).


NB : Pensez à remplacer IDENTIFIANT_BAL par l'identifiant de la boite aux lettres de ressources (Alias par exemple).

Script Powershell – Nagios: Alimentation de fichiers d’hôtes

 

Le script suivant:

- interroge l’AD pour récupérer une liste des machines serveurs à superviser

- Détermine si la machine est reconnu (DNS)

- Détermine si la machine répond au ping

- Détermine si la machine héberge le client NSClient++ (NSCP)

- Sur la base de ces infos, des fichiers de config d’hôtes sont construit, une archive du jour (tar.gz) des fichiers à remplacer est créé dans le même répertoire. Les fichiers de conf sont ensuite envoyés par FTP dans le répertoire « /usr/local/nagios/etc/objects/HOME/HOSTS/ » du serveur nagios.

Le demon nagios est redémarré à la suite.

 

 

Exchange / Powershell : Influence du paramètre DomainController

Introduction

 

Exchange bénéficie d'un grand nombre de cmdlet Powershell très abouties et permettant de configurer et d'administrer l'intégralité d'une infrastructure de messagerie. Aussi, celles-ci sont très utiles dans le cas de scripts de provisionning. J'ai rencontré une erreur lorsque je cherchais à créer et à configurer un grand nombre de boites aux lettres de ressources.

 

Contexte

 

L'environnement dans lequel j'ai découvert ce problème est une forêt mono domaine Active Directory avec une infrastructure Exchange 2010 SP3 dans laquelle il y avait plusieurs contrôleurs de domaine dans le même site Active Directory que la totalité des serveurs de messagerie.

 

Plus globalement, cette erreur pourra être rencontrée dès qu'un serveur Exchange pourra être amené à interroger plus d'un contrôleur de domaine.

 

Erreur rencontrée

 

Dans un script de provisionning de boîtes aux lettres, on cherche à les créer mais aussi à les configurer. Si l'on souhaite configurer une boite aux lettres tout de suite après sa création alors on obtient une erreur similaire à celle ci-dessous (“ObjectNotFoundException”) :



Cela peut se retrouver en exécutant l'exemple suivant :



Une ou plusieurs opérations de modification (de type Set-…) vont échouer avec le message d'erreur cité précédemment.

 

Explication

 

Suite à cette erreur, il est logique de penser que cela est dû à l'interrogation de différents contrôleurs de domaine qui n'ont pas encore répliqué entre eux (Une réplication intra site peut prendre quelques secondes).

 

Aussi, on peut se dire qu'il suffit alors de spécifier le paramètre DomainController pour corriger le problème en l'indiquant sur toutes les commandes et en définissant un contrôleur de domaine unique qui traitera toutes les opérations.

 

Cependant, cela ne corrigera pas le problème. Microsoft en donne l'explication dans les fiches Technet des cmdlets :http://technet.microsoft.com/en-us/library/dd335046.aspx.

 

Le paramètre DomainController ne concerne que le contrôleur de domaine qui va écrire les modifications dans Active Directory. Cependant, un autre contrôleur de domaine  peut être utilisé pour lire l'objet avant d'écrire les changements sur celui spécifié en paramètre.

 

Aussi, pour une cmdlet de type Get-… (lecture), le paramètre DomainController sera bien le contrôleur de domaine sur lequel l'objet sera lu (cela sera utile pour mettre en place l'une des solutions proposées).

 

Solution

 

Pour résoudre ce problème,  il faut donc attendre que la réplication ait eu lieu sur la totalité des contrôleurs de domaine du site Active Directory de l'infrastructure Exchange. Pour cela, nous avons trois solutions.

 

Solution 1 :

 

Il est possible de séparer la création des boîtes aux lettres et leurs configurations. Cette solution oblige donc a réaliser le provisioning en plusieurs phases.

 

Solution 2 :

 

On peut définir un délai entre l'opération de la cmdlet de création et la cmdlet de configuration via un Start-Sleep par exemple. Cependant, cette solution ne garantit pas que les opérations vont toutes se dérouler correctement. Il faudra sans doute que le délai soit important pour que le provisioning ait un taux de réussite élevé et donc augmenter considérablement le temps d'exécution du script.

 

Solution 3 :

 

La dernière solution est une combinaison des deux précédentes puisqu'elle permet de n'avoir qu'une seule phase de provisioning tout en ayant un temps d'exécution relativement rapide.

 

Cette solution consiste à implémenter une boucle de test de l'opération à réaliser sur le même contrôleur de domaine via la cmdlet de lecture (Get-…).

 

Exemple :



Il est possible d'ajouter une courte pause entre chaque test afin de ne pas surcharger le processus sans pour autant trop pénaliser le temps d'exécution du script. Le paramètre ErrorAction permet d'alléger l'affichage car on connait déjà l'erreur que l'on va rencontrer.

Il ne vous reste plus qu'à choisir la solution que vous préférez.

Powershell – Exemple de transfert de données vers un système Unix

 

A la suite de la récupération d’un dataset issu d’une requête a une base sql on veut exporter et transférer les données vers un système Unix.

Comme indiqué dans le code, a la suite de la validation du fait que le résultat de la requête contienne des données (RequestSQL OK),  on converti le dataset en csv vers un fichier local ($FullLocalFile):

($DataSet.Tables[0] | convertto-csv -Delimiter ";" -NoTypeInformation)  | Out-File -FilePath $FullLocalFile

Puis on récupère le contenu du fichier pour ensuite le convertir au format UTF8 (au passage on écrase le fichier d’origine):

$content=get-content $FullLocalFile
Set-Content -value $content -Encoding UTF8 -Path $FullLocalFile –Force

Enfin on envoi en ftp le fichier vers le système Unix (en construisant dynamiquement le fichier de commande):

N.B: Il est possible que le mode de transfert (ascii ou binary) ait une influence sur le résultat du transfert. N’hésitez pas a tester les deux cas.

#construction fichier ftpcommands
New-Item -Path "$LocalDirectory\ftpcommands.txt" -ItemType file -Force -value `
"open monserverunix
user1
password
ascii
cd /monappli/data
lcd $LocalDirectory
mput $FileName
Y
bye"

#Envoi FTP et verification
ftp.exe -s:$LocalDirectory\ftpcommands.txt > "$LocalDirectory\resultatftp.txt"

(...)

#suppression du fichier ftpcommands
Remove-Item -Path "$LocalDirectory\ftpcommands.txt"
Remove-Item -Path "$LocalDirectory\resultatftp.txt"

 

$LocalDirectory="D:\Data" $FileName="data.csv" $FullLocalFile="$LocalDirectory\$FileName" (...) #Si le dataset est vide => Echec de la requête => $RequestSuccess=$false If (($DataSet.Tables[0] | Measure-Object).count -eq "0") { $RequestSuccess=$false write-host -ForegroundColor blue "Dataset vide - FIN DU SCRIPT" Exit } Else { $RequestSuccess=$true write-host -ForegroundColor green "RequestSQL OK" #Export du fichier CSV en local ($DataSet.Tables[0] | convertto-csv -Delimiter ";" -NoTypeInformation) | Out-File -FilePath $FullLocalFile #Recuperation du contenu et conversion en UTF8 pour compatibilité Unix $content=get-content $FullLocalFile Set-Content -value $content -Encoding UTF8 -Path $FullLocalFile -Force } #construction fichier ftpcommands New-Item -Path "$LocalDirectory\ftpcommands.txt" -ItemType file -Force -value ` "open monserverunix user1 password ascii cd /monappli/data lcd $LocalDirectory mput $FileName Y bye" #Envoi FTP et verification ftp.exe -s:$LocalDirectory\ftpcommands.txt > "$LocalDirectory\resultatftp.txt" (...) #suppression du fichier ftpcommands Remove-Item -Path "$LocalDirectory\ftpcommands.txt" Remove-Item -Path "$LocalDirectory\resultatftp.txt"

Powershell – Script – Suppression création de compteur de performance

 

Il peut être nécessaire dans le cas d’un script insérant des données de performance de supprimer/recréer l’objet de performance

L’exemple ci-dessous montre la suppression ré-création d’un objet MyObject et d’un compteur de performance Mycounter1.

On vérifie l’existence de l’objet de performance via wmi et l’objet .net [Diagnostics.PerformanceCounterCategory]

On supprime MyObject

On recrée l’objet et son compteur  via Diagnostics.CounterCreationDataCollection et Diagnostics.CounterCreationData

On soumet la création de l’objet “global” via [Diagnostics.PerformanceCounterCategory]

Le compteur peut a partir de là être alimenté et interrogé.

 

if((Get-WmiObject -Query "Select * from Win32_perfformatteddata_MyObject_MyObject").MyCounter1 -eq 0 ` -OR (Get-WmiObject -Query "Select * from Win32_perfformatteddata_MyObject_MyObject").MyCounter1 -eq $null ` -AND [Diagnostics.PerformanceCounterCategory]::Exists(“MyObject”)) { write-host "Suppression et re-creation de l'objet de performance MyObject" #Suppression [Diagnostics.PerformanceCounterCategory]::Delete(“MyObject”); #Creation de l'objet de perf $script:cntrColl = New-Object Diagnostics.CounterCreationDataCollection; Write-Host "Add counter 1"; $counter = New-Object Diagnostics.CounterCreationData; $counter.CounterName = "Mycounter1"; $counter.CounterHelp = "Help for Counter_1"; $counter.CounterType = [Diagnostics.PerformanceCounterType]::NumberOfItems64; $script:cntrColl.Add($counter); #Ajout du compteur Write-Host "Ajout du compteur a PerfMon"; [Diagnostics.PerformanceCounterCategory]::Create(“MyObject”, “My counter”, $script:cntrColl); }

Powershell 5.0 : Les classes

Introduction

Powershell 5.0 a bénéficié de plusieurs releases lors de l'année 2014, chacune d'entre elles apportant son lot de nouveautés/correctifs. Ce dernier est toujours en développement (la version finale n'arrivant qu'avec Windows 10) mais nous allons tout de même nous attarder dans cet article sur une nouvelle notion : la création de classes. Celle-ci n'était pas disponible nativement jusqu'en Powershell 5.0, ce qui pouvait paraître étrange pour un langage de scripting orienté objet. Je ferai un bref rappel sur les options disponibles avant cette version.

Dorénavant, nous pourrons créer nos propres objets personnalisés. Souvent, dans les scripts Powershell, on remarque l'utilisation de tableau ou de dictionnaire imbriqués et qu'il faut ensuite analyser pour récupérer la bonne valeur. Ces scripts obligent à avoir des algorithmes assez long et le script devient difficilement lisible en dehors du fait de ne pas être rigoureux. De plus, ils nécessitent souvent l'imbrication de multiples boucles de traitement influençant les performances générales du script.

Dans cet article, nous aborderons la création de classes d'objets en Powershell, l'ajout de propriétés et de méthodes ainsi que la façon d'instancier ("créer") nos objets. Pour certaines notions, une définition sera donnée (Cela permettra aux personnes non familières avec certaines notions de programmation objet de mieux appréhender le sujet).

Dans la suite de cet article, nous prendrons l'exemple d'une classe d'objet HRUser définissant un utilisateur dans le système RH pour illustrer la nouvelle syntaxe. Imaginons que cet exemple soit utilisé dans le cadre d'une interaction avec une base de données. L'objet utilisateur possédera les attributs suivant (nous ajouterons d'autres propriétés et des méthodes/fonctions ultérieurement) :

  • firstname
  • lastname
  • isCollaborator (un booléan permettant de savoir si l'utilisateur est un collaborateur)
  • salary (un nombre entier)

NB : Contrairement à la première beta, Powershell 5.0 est dorénavant disponible pour Windows 2012 et supérieur (qui n’était compatible qu’avec Windows 2012 R2 et supérieur). Le lien suivant vous mènera à la dernière beta sortie (Novembre 2014) :

http://www.microsoft.com/en-us/download/details.aspx?id=44987

Avant Powershell 5.0

Jusqu'à Powershell 4.0, il existait plusieurs méthodes pour créer des objets personnalisés en Powershell.

New-Object et NoteProperty :

La première méthode consiste à créer un objet de type PSCustomObject auquel on ajoute des propriétés de type NoteProperty.

Cependant, cette méthode ne permet pas d'ajouter des fonctions et le typage de nos attributs est dynamique. De plus, tout les objets personnalisés posséderont la même classe : PSCustomObject.

C# et Add-Type :

La seconde méthode était l'utilisation de code C#. Powershell pouvant interprété ce langage,  il est tout à fait possible d'écrire entièrement une classe en C# puis de l'ajouter dans une session Powershell via la commande Add-Type.

On peut ensuite créer l'objet grâce à la commande New-Object. Ce dernier possédera son propre type (HRUser) qui sera différent pour toutes les classes que vous créerez.

 

Il est aussi possible d'ajouter des fonctions statiques ou non à notre classe (nous reviendrons sur cette notion ultérieurement).

Cette méthode est complète mais nécessite de connaître le C#, ce qui complexifie aussi la lecture des scripts. Dans les prochains paragraphes, nous allons voir que Powershell offre dorénavant nativement les mêmes possibilités.

Les classes

Une classe contient la définition de nos objets ainsi que les traitements qui peuvent être effectués sur ceux-ci. Une nouveau mot clé apparaît dans Powershell 5.0 : “class” que l'on retrouve avant un scriptblock. Une classe se déclare de la façon ci-dessous :

Malheureusement, il n'existe pas encore de syntaxe pour gérer l'héritage de classe.

NB : Attention, les classes doivent obligatoirement être déclarées dans des scripts powershell. Une déclaration dans une invite de commande Powershell ne pourra donc pas être fonctionnelle.  De plus, lorsqu'une classe a été chargée, il est nécessaire d'ouvrir une nouvelle version avant d'en exécuter une version différente (elle ne peut pas être mis à jour dans une même session Powershell).

Les propriétés

Les propriétés contiennent tous les attributs de notre classe.

Celles-ci peuvent optionnellement contenir un type (comme dans l'exemple ci-dessus). Cela permet de réaliser de la validation sur les propriétés d'un objet.

Nous pouvons donc créer notre objet de type HRUser via la cmdlet New-Object en indiquant le type d'objet à créer.

 

On peut aussi créer un objet grâce à la méthode new qui existe dans chaque classe.

 

Toutes les propriétés sont initialisées avec une valeur par défaut (une chaîne vide, un booléen faux ou le chiffre 0 dans notre exemple).

On peut ensuite définir les propriétés de notre objet.

 

Attention, dans notre exemple, nos propriétés sont typées. On peut donc rencontrer une erreur si par exemple on définit une chaîne de caractères à la place d'un nombre pour la propriété “salary”.

ERROR PROPERTY TYPE

Les constructeurs

Un constructeur permet de créer un objet en initialisant certaines ou toutes de ces propriétés avec des valeurs fournies en paramètres et éventuellement d'effectuer des traitements lors de la création d'objets. La méthode “new” que nous avons vu précédemment correspond au constructeur par défaut. Mais il est possible d'en ajouter un ou plusieurs autre, c'est ce qu'on appelle la surcharge.

La syntaxe d'un constructeur est la suivante (il faut la placer à l'intérieur de la définition de notre classe) : On peut créer l'objet en lui passant des paramètres pour utiliser notre constructeur :

 

Ou

 

Cependant, on rencontrera une erreur si on ne renseigne pas tous les paramètres :

ERROR CONSTRUCTOR 

Pour palier à ce problème, on peut imaginer un second constructeur sans le salaire :

Les méthodes

Les méthodes sont l'équivalent de fonctions qui permettant d'interagir avec un objet. Nous allons créer une fonction permettant de gérer l'augmentation de salaire d'un employé.

Le type indiqué devant la méthode nous indique ce qui est retourné (“void” correspond à une méthode ne retournant rien).

Exemple d'exécution incluant une augmentation de salaire pour une personne :

EXEMPLE METHOD

Si nous souhaitons récupérer le nouveau salaire, il faut modifier la méthode en utilisant le mot clé “return” et en modifiant le type de retour.

Méthodes et propriétés statiques

Il reste un dernier mot clé à définir : “static”. Il permet de définir des méthodes et des propriétés qui sont accessibles sans avoir à créer un objet. Pour illustrer cette notion, nous allons ajouter une propriété représentant le total des utilisateurs du système. De plus, nous allons modifier les constructeurs pour incrémenter le compteur quand un utilisateur est créé.

On définit la propriété count :

 

On peut y accéder via : [HRUser]::count

Voici le script contenant l'intégralité de la définition de  la classe HRUser :

Exemple d'exécution :

EXEMPLE STATIC

Il aurait pu être intéressant d'intégrer la modification du compteur lors de la suppression de l'utilisateur dans la classe. Cependant, il n'existe pas de destructeur (méthode permettant de détruire un objet) dans la version actuelle de Powershell 5.0.

Conclusion

Nous avons aborder la création de classes d'objets en Powershell qui nécessite d'avoir des connaissances en programmation orientée objet. Initialement, Microsoft a ajouté cette notion pour simplifier la création de ressources pour Desired State Configuration (exemple : https://technet.microsoft.com/en-us/library/dn820211%28v=wps.640%29.aspx). A noter que lorsque vous charger une classe et que vous créer des objets, toutes les propriétés et méthodes associées sont accessible via l'auto complétion. Les classes écrites en Powershell sont une nouveauté et il reste encore des améliorations à réaliser :

  • l'héritage des classes.
  • la portée sur les propriétés : en Powershell, elles sont toutes publiques et donc accessible/modifiable depuis n'importe quel endroit dans un script. Changer la portée permettrait de spécifier des propriétés qui ne seraient accessibles que dans une méthode de la classe.

Powershell 5.0 : découvertes de quelques nouveautés

Introduction

Powershell 5.0 est encore en beta mais de nombreuses nouveautés sont déjà présentes. Nous allons aborder dans cet article quelques unes d'entres elles. Elles peuvent concerner : Powershell, son éditeur (Powershell ISE) ou encore son paramétrage dans Windows. Certaines avaient déjà été évoquées dans l'article suivant lors de la première preview de Powershell 5.0 :
http://blog.piservices.fr/post/Powershell-V5-Preview-est-sorti-!-DSC-Switch-OneGet-et-du-chocolat.aspx

NB : Contrairement à la première beta, Powershell 5.0 est dorénavant disponible pour Windows 2012 et supérieur (qui n’était compatible qu’avec Windows 2012 R2 et supérieur). Le lien suivant vous mènera à la dernière beta sortie (Novembre 2014) :

http://www.microsoft.com/en-us/download/details.aspx?id=44987

Gestion des Archives

Un nouveau module permettant de gérer nativement les archives apparaît dans Powershell 5.0. Cette option n'était auparavant disponible qu'au travers de module réalisé par la communauté. Ce dernier permet de générer des archives (Compress-Archive) ou de les extraire (Expand-Archive). Seul le format Zip est actuellement géré. Un paramètre nommé “update” permet de mettre à jour une archive existante en ajoutant seulement les nouveaux fichiers et les changements sur les fichiers déjà présents dans l'archive. Le paramètre “path” peut définir un ou plusieurs fichiers ainsi qu'un dossier entier en utilisant le caractère “*” (wildcard). Enfin le paramètre “CompressionLevel” permet d'influencer le taux de compression et la taille finale de l'archive.

 

Zip module

Support des raccourcis claviers

La console Powershell supporte désormais certains raccourcis clavier : copier (CTRL+C), coller (CTRL+V), tout sélectionner (CTRL+A).

Gestion des liens symboliques

Il est dorénavant possible de créer/supprimer des raccourcis via Powershell. Cette fonctionnalité est incluse dans la commande New-Item en spécifiant le type “SymbolicLink”.

Création d'un raccourci vers un fichier

 

Création d'un raccourci vers un dossier

 

On peut aussi lister des fichier via la commande Get-ChildItem en passant par un raccourci !

Event Viewer

Un nouveau journal de log est apparu dans l'observateur d'événements. Par défaut, ce dernier enregistre les lancements de console Powershell et les erreurs générales comme un échec de chargement de module. Ce nouveau journal est situé dans Applications and Services Logs\Microsoft\Windows\PowerShell\Operational. Il peut aussi enregistrer les exécutions de code Powershell. Cette fonctionnalité s'active via GPO.

Attention : Activer l'utilisation de ce journal pour les exécutions de code est très verbeux. Néanmoins cela peut être très utile pour obtenir rapidement des traces d'actions effectuées sur des serveurs via Powershell.

Il est possible d'activer cette fonctionnalité via GPO (voir paragraphe ci-dessous).

GPO

Les modèles d'administration possède désormais un ADMX permettant de gérer quelques paramètres Powershell. Ce dernier est situé dans Administrative Templates / Windows Components / Windows PowerShell. Il serait compatible avec les systèmes d'exploitation de la famille Windows 7 / Windows 2008 et supérieur (je ne l'ai personnellement testé que sur Windows 10 Server Technical Preview). Cette nouveauté n'est donc pas totalement liée à Powershell 5.0 puisqu'elle sera fonctionnelle sur les anciennes versions de Powershell.

Administrative Template Powershell

Les paramètres configurables sont les suivants :

  • Activer les traces dans l'observateur d'événements pour tout exécution de script.
  • Activer les traces dans l'observateur d'événements pour les exécutions de module Powershell (il faut préciser les modules concernés).
  • Définir la politique d'exécution des scripts (Set-ExecutionPolicy). Il s'agit d'une très bonne nouvelle car il n'existait pas de solution pour généraliser ce paramètre sur un grand nombre de serveur hormis en passant par une ressource DSC (ce qui représente un déploiement beaucoup plus lourd).
  • Activer automatique du transcript : cela permet de ne pas avoir à lancer la commande “start-transcript”. Il est également possible de définir le chemin où doit être stocké le transcript. Par défaut le nom du fichier est horodaté, contient le nom de l'ordinateur et est stocké dans le répertoire “Mes documents” de l'utilisateur de la session Powershell.
  • Définir la source de l'aide Powershell. Depuis Powershell 3.0, l'aide des cmdlets n'est pas entièrement incluse avec le package d'installation Powershell. Il est nécessaire d'utiliser la commande “Update-Help” pour la mettre à jour (par défaut, elle est récupéré depuis internet). Cela permet entre autre de récupérer l'aide avec la langue qui nous intéresse. Grâce à ce paramètre, on peut dorénavant spécifier une source comme un partage de fichier. Néanmoins, l'utilisateur a toujours la possibilité de changer le comportement en indiquant lui même une valeur lors de l'exécution de la commande via le paramètre “SourcePath”.

Tous ces paramètres sont disponibles dans la configuration ordinateur et utilisateur de la GPO.

Transcript

La génération de transcript n'était jusqu'à présent fonctionnelle que dans la console Powershell. Grâce aux cmdlets “Start-Transcript” / “Stop-Transcript”, il est désormais possible de générer des fichiers de traces aussi via Powershell ISE.

Powershell ISE avec Powershell 4 :

Powershell ISE transcript v4

Powershell ISE avec Powershell 5 :

Powershell ISE transcript v5

PSEdit

Une nouveauté fait son apparition dans Powershell ISE et le PSRemoting : PSEdit. Cet outil existait déjà et permettait d'ouvrir script dans un nouvel onglet dans Powershell ISE lorsque l'on exécutait la commande suivante : PSEdit chemin_de_mon_script.

Cependant, dans cette nouvelle version de Powershell ISE, il est possible d'ouvrir des fichiers à distances. Il n'y a donc plus besoin d'ouvrir Powershell ISE sur la machine où se trouve le script pour l'éditer. Il suffit d'ouvrir une PSSession puis d'exécuter PSEdit.

Cette fonctionnalité est facilement testable même en local en simulant une session distante :

PSEdit Remote file

Il n'y a pas besoin de connaître le chemin exact du script puisque l'auto complétion est disponible pour le retrouver.

Enumérations

La dernière nouveauté expliquée dans cet article est plus orientée scripting. Les énumerations font leurs apparitions dans Powershell. Pour cela un nouveau mot clé est disponible : “enum”. Celles-ci vont nous permettre de réaliser plus rapidement de la validation de paramètres.

Prenons le cas du paramètre ErrorAction disponible sur toutes les commandes Powershell. Il n'est possible de fournir qu'un certain nombre de valeurs : Continue, Ignore, Inquire, SilentlyContinue, Stop, Suspend. Ceux-ci correspondent à une énumération.

La syntaxe d'une énumération est la suivante : Pour utiliser cette dernière dans une fonction :

Nous pouvons remarquer que les choix disponibles sont proposés par le système d'auto complétion.

EnumEnfin, si l'on souhaite récupérer les valeurs d'une énumération, il faut exécuter la commande suivante :

 

Conclusion

Powershell 5.0 et Windows 10 sont riches en nouveautés pour le langage de scripting de Microsoft. Certaines d'entre elles n'ont pas été abordées mais feront l'objet d'articles dédiées :

  • La création de classes d'objets personnalisés.
  • Les améliorations de Desired State Configuration comme la gestion des configurations partielles permettant de segmenter celles-ci en plusieurs fichiers (exemple : par fonctionnalité).
  • PowershellGet : à l'instar de OneGet qui permet de récupérer des packages, ce dernier offre la possibilité de récupérer des modules depuis internet ou depuis sa propre source. Ainsi, une société peut créer sa bibliothèque de modules Powershell.

Script Powershell–Scom: Surveillance consommation reguliere de fichiers dans un dossier

 

Le script ci-dessous surveille la consommation (création / suppression) régulière de fichiers dans un dossiers en excluant potentiellement des noms de fichiers et des heures de dernieres modification puis remonte l’état a SCOM.

Lien du script plus bas.

##################################################################################################### #SCRIPT DE SUPERVISION DU CHANGEMENT DE CONTENU DU DOSSIER ARRIVEE POUR L'APPLICATION INVENTAIRE #ETAT KO SI DES FICHIERS SONT PRESENT APRES 15 minutes (CES FICHIERS SONT CENSES ETRE RAPIDEMENT CONSOMMES) ##################################################################################################### #NB: L'INTERVALLE DE TEMPS DE COMPARAISON EST CELLE DE L'INTERVALLE D'EXECUTION DU SCRIPT #SONT EXCLUS DANS LES CRITERES DE RECHERCHE LES FICHIERS CREES ENTRE 22:00 ET 00:59 Param( [string]$computerName, [string]$DirPath, [regex]$excludedfiles="^(FILETOEXCLUDE)|(FILETOEXCLUDE)$", [regex]$filename="^.*(.*)$", [regex]$excludetime="^(22:).*|(23:).*|(00:).*$" ) $scriptname="CheckDirFileConso" #API Scom $api = new-Object -ComObject 'Mom.ScriptAPI' #Verification de l'existence d'une source ayant le nom du script dans l'eventlog operation manager pour loguer certains events Function NewEventSource { if(!(Test-Path "HKLM:\SYSTEM\CurrentControlSet\services\eventlog\Operations Manager\$scriptname")) { New-EventLog -LogName "Operations Manager" -Source $scriptname } } #Verification de l'existence du dossier $DirPath if (!(test-path -Path $DirPath)) { write-host "le dossier $DirPath est introuvable" NewEventSource Write-EventLog -LogName "Operations Manager" -Source $scriptname -EntryType Error -EventId 1004 -Message "le dossier $DirPath est introuvable" Exit } $Files=Get-ChildItem -Path $DirPath | Where-Object {$_.name -match $filename -AND $_.name -notmatch $excludedfiles -AND $_.lastwritetime -lt (get-date).AddMinutes(-15) -AND $_.LastWriteTime.ToLongTimeString() -notmatch $excludetime} | Select-Object -Property Name -ExpandProperty Name If ($Files) { write-host -ForegroundColor yellow -BackgroundColor black "Les fichiers suivants sont présent depuis 15 minutes dans le dossier $DirPath:" foreach ($file in $Files) { write-host $file } NewEventSource Write-EventLog -LogName "Operations Manager" -Source $scriptname -EntryType Warning -EventId 1005 -Message "Les fichiers suivants sont présent depuis 15 minutes dans le dossier $DirPath: $Files" $status="KO" write-host "" write-host -ForegroundColor yellow -BackgroundColor black "ETAT $status" } Else { write-host -ForegroundColor green "Tout les fichiers présents il y a 15 minutes dans le dossier $DirPath ont été consommés" NewEventSource Write-EventLog -LogName "Operations Manager" -Source $scriptname -EntryType Information -EventId 1000 -Message "Tout les fichiers présent il y a 15 minutes dans le dossier $DirPath ont été consommés" $status="OK" write-host "" write-host -ForegroundColor green "ETAT $status" } #Envoi de l'état a SCOM $bag = $API.CreatePropertyBag() If ($status -eq "KO") { $bag.AddValue("Status","Warning") } Else { $bag.AddValue("Status","Success") } $bag