lundi 26 décembre 2016

Journaliser les événements de ses scripts Powershell

Ou comment loguer sans se prendre la tête

Ça fait quelques temps que je n'avais pas reversé un peu de code sur ce blog !

Aujourd'hui je vous propose une fonction qui va entièrement s'occuper de la partie journalisation de vos scripts. Par journalisation, je veux dire "conserver une trace datée d'une action effectuée par un script/automate".

Et par "entièrement s'occuper de la partie journalisation", je veux dire :

  • Si le dossier contenant le journal n'existe pas, il va le créer
  • Si le journal n'existe pas, il va le créer
  • Il va zipper et déplacer vos fichier de logs dans un dossier Archives tous les 1er du mois. Si le dossier Archives n'existe pas il va le créer
  • Il journalise son propre fonctionnement (création, archivage, etc...)
  • Détecte d'éventuels problèmes de droits
  • Et, enfin, il ajoute l’information que vous souhaitez dans le fichier de log que vous souhaitez
  • Une fonction ?

    L'avantage de la fonction, c'est que vous la stockez dans votre dossier de scripts préféré, vous l’appelez et vous ne vous occupez de rien : ça tourne, ça log, enjoy !

    Vous n'aurez plus à coder cette partie-là, la fonction pourra être appelée par tous vos scripts, sans aucune incidence.
    Je m'en vais vous expliquer tout ça.

    Installation

    Téléchargez la fonction ici :

    Téléchargez Func.Logs.zip

    Décompressez-la dans le dossier où vous stockez habituellement vos scripts.
    Par cohérence, organisation, je vous recommande un dossier de ce type :

    x:\Scripts\Powershell\Fonctions

    Mais vous faites bien comme vous voulez hein.
    Voila voila, c'est installé :)

    Utilisation

    Pour qu’elle puisse fonctionner, la fonction a besoin :

  • D’être chargée par le script
  • De connaître le nom et l’emplacement du fichier journal
  • De connaître le contenu (càd l’entrée) à ajouter dans le journal.
  • D’être appelée pour faire le boulot
  • Pour illustrer ça, prenons un script useless à deux sous :

    $process = Get-Process            # On stock tous les processus dans la variable $process
    If ($($process.Count) -gt 100)    # Si le nombre de process est supérieur à 100...
    {
        Write-Warning "Fuyez pauvres fous, le nombre de processus atteint $($process.Count) !" # ...alors tu écris ça.
    }

    Ce script stock les processus Windows dans une variable $process et si le nombre de processus ($($process.Count)) est supérieur à 100, il écrit la phrase indiquée.

    Admettons que je veuille loguer ce comportement. Oui c'est inutile, mais admettons.

    Tout d'abord, pour charger la fonction, j'ajoute dans mon fichier le chemin de la fonction Logs (précédé par un point) en ajoutant la ligne suivante (en gras) :

    . "x:\Scripts\Powershell\Fonctions\Func.Logs.ps1" 
    $process = Get-Process [...]
    Evidemment, adaptez le chemin en spécifiant le votre.

    Le "." en début de ligne est essentiel !

    En rajoutant cette ligne, Powershell va lire le fichier Func.Logs.ps1 comme s'il faisait parti du script en cours d'exécution et va donc charger la fonction qu'il contient : il s’agit d’un “include”

    Il ne reste plus qu'à lui donner le chemin du fichier de log, le contenu de l’entrée à loguer et à l'appeler dans votre script pour l'utiliser pleinement :

    . "x:\Scripts\Powershell\Fonctions\Func.Logs.ps1"
    $strLogFile = "G:\Scripts\Logs\test.log" 
    $process = Get-Process
    
    If ($($process.Count) -gt 100)
    {
        Write-Warning "Fuyez pauvres fous, le nombre de processus atteint $($process.Count) !".
        $strLogLine = "Ma première ligne de log, que d'émotions. Au fait il y a $($process.Count) processus !"
        Logs
    }
    Avec ces quatre lignes en gras, la fonction Logs est pleinement fonctionnelle.
  • . "c:\Path\Func.Log.ps1" : Pour intégrer la fonction a votre script
  • $strLogFile : A définir en début de script, indique où doivent être stockés les Logs
  • $strLogLine : A définir à chaque appel de la fonction, indique la ligne à ajouter dans les journaux
  • Logs : Appel la fonction, elle est executée et le contenu de $strLogLine est ajouté dans le fichier $strLogFile
  • Si je regarde le contenu de mon fichier test.log ($strLogFile) :
    22/12/2016 14:11:40 - Maintenance : création du fichier journal test.log
    22/12/2016 14:11:40 - Ma première ligne de LOG, que d'émotions. Au fait, il y a 158 processus !

    Résumé

    Une fois que j'ai inclus la fonction dans mon script, je peux l'appeler avec la commande Logs. A ce moment-là, la fonction ajoutera le contenu de la variable $strLogLine dans mon fichier de logs $strLogFile.
    Simple non ?

    Pour aller plus loin : Plusieurs logs différents pour le même script

    Rien ne vous empêche de déclarer plusieurs fichiers de logs dans le même script, il faudra au moment où vous déclarez $stLogLine de redéfinir la variable $strLogFile avec un nouveau chemin.
    Exemple avec ce script :
    Clear
    for ($i=0 ; $i -le 10 ; $i++)
    {
         $RandomBit = get-random -Maximum 2 -Minimum 0
         Switch ($RandomBit)
         {
             0  {
                  $RandomBit
             }
             1  {
                  $RandomBit
             }
         }
    }
    Le "Switch" n'a pour le moment que peu d'intérêt puisque que le nombre fasse 0 ou 1 il fait la même chose : afficher le résultat de $RandomBit.
    Admettons que je veuille loguer les résultats sur deux logs différents, un log pour les 0 et un log pour les 1, voici ce que j'ajouterai :
    Clear
    . "x:\Scripts\Powershell\Fonctions\Func.Logs.ps1"
    for ($i=0 ; $i -le 10 ; $i++)
    {
        $RandomBit = get-random -Maximum 2 -Minimum 0
        Switch ($RandomBit)
        {
            0
            {
                $strLogFile = "c:\Logs\zero.log" 
                $strLogLine = "Un zero de plus dans ce monde de bits" 
                Logs
                $RandomBit
            }
            1
            {
                $strLogFile = "c:\Logs\un.log"
                $strLogLine = "Un un pour dans les ténébres les lier" 
                Logs
                $RandomBit
            }
        }
    } 

    Le switch prend tout son sens puisqu'on tri et on effectue une action différente selon le résultat : le même script pourra donc générer plusieurs Logs différents.

    Pour aller plus loin : Les variables de fonctionnement de func.log.ps1

    La fonction utilise ses propres variables internes pour fonctionner. Celles-ci commencent toutes par :
  • $strLog[...] dans le cas d'une string
  • $intLog[...] dans le cas  d'une entier
  • $boolLog[...] dans le cas d'une booléenne
  • Outre les variables $strLogFile et $strLogLine que vous devez utiliser pour le fonctionnement de la fonction, évitez de créer des variables avec les caractèristiques indiquées ci-dessus.
    Concernant $str, $int, $bool, $arr, etc. il s'agit de ma propre convention de nom de variable, où j'ai gardé la vieille habitude de conserver le type de la variable dans son nom. Très utile pour debug ou même pour s'y retrouver quand votre script commence à atteindre quelques centaines de lignes. En général, le mot suivant indique le contexte dans le script. Ici, comme il s'agit d'une fonction autonome, je préfère réserver les noms de variable en $[type]Log[Usage]

    Aucun commentaire:

    Enregistrer un commentaire