PowerShell – Comparer des objets avec Compare-Object

I. Présentation

La commande PowerShell "Compare-Object" est très pratique pour comparer deux objets, comme deux variables, le contenu de deux fichiers ou encore le contenu entre deux dossiers. Il m'est arrivé à plusieurs reprises d'utiliser cette commande pour comparer deux fichiers CSV.

Lorsque l'on compare deux objets avec Compare-Object, la commande retourne :

  • Les éléments identiques entre les deux fichiers
  • Les éléments présent dans l'objet de référence, mais absent dans le second objet
  • Les éléments absent dans l'objet de référence, mais présent dans le second objet

Vous l'aurez compris, dans ce tutoriel, je vais vous expliquer comment comparer deux objets en PowerShell avec Compare-Object.

II. Compare-Object : comparer deux chaînes de caractères

Compare-Object peut, tout simplement, comparer deux chaînes de caractères. Cela va nous permettre de bien appréhender la syntaxe de cette commande.

Pour comparer deux chaînes, il suffit de les préciser à la suite de Compare-Object :

Compare-Object "www.it-connect.fr" "IT-Connect"

Dans le cas où les chaînes sont égales, la commande ne va rien retourner. Si l'on veut inclure les éléments égaux, il faut ajouter le paramètre "-IncludeEqual".

Compare-Object "www.it-connect.fr" "WWW.IT-CONNECT.FR" -IncludeEqual

Comme on peut le constater avec cet exemple, la comparaison ne tient pas compte de la casse. Si elle est importante, on peut ajouter le paramètre "-CaseSensitive" pour tenir compte de la casse.

Compare-Object "www.it-connect.fr" "WWW.IT-CONNECT.FR" -IncludeEqual -CaseSensitive

Ce qui donne :

Compare-Object

Suite à cette introduction, passons maintenant à un exemple beaucoup plus utile : la comparaison de fichiers CSV avec PowerShell et Compare-Object.

III. Compare-Object : comparer deux CSV

Prenons les deux fichiers CSV suivants :

  • CSV1.csv
Pays;
France;
Costa Rica;
Canada;
Belgique;
Suisse;
  • CSV2.csv
Pays;
France;
Costa Rica;
Espagne;
Belgique;
Islande;
Colombie;

Nous allons comparer ces deux fichiers pour identifier facilement les différences.

On va commencer par importer le contenu de nos fichiers CSV dans les variables $CSV1 et $CSV2.

$CSV1 = Import-CSV "C:\TEMP\CSV1.csv" -Delimiter ";"
$CSV2 = Import-CSV "C:\TEMP\CSV2.csv" -Delimiter ";"

Ensuite, nous allons comparer la variable $CSV1 et la variable $CSV2. Le fichier CSV1 sera notre objet de référence, on va l'associer au paramètre -ReferenceObject alors que l'objet de "différence" sera le fichier CSV2. Il faut également spécifier la propriété sur laquelle se baser pour faire la comparaison, ici ce sera notre colonne "Pays".

Ce qui donne :

Compare-Object -ReferenceObject $CSV1 -DifferenceObject $CSV2 -Property Pays

Le résultat suivant est obtenu :

Compare-Object CSV

La colonne "SideIndicator" permet de savoir de quel côté est présente la valeur :

  • "=>" : fait référence à une valeur présente dans le -DifferenceObject (CSV2), mais absente dans le -ReferenceObject (CSV1)
  • "<=" : fait référence à une valeur présente dans le -ReferenceObject (CSV1), mais absente dans le -DifferenceObject (CSV2)

Si l'on veut connaître seulement les valeurs présentes dans le fichier CSV1, mais absentes du fichier CSV2, on peut ajouter un filtre sur le SideIndicator :

Compare-Object -ReferenceObject $CSV1 -DifferenceObject $CSV2 -Property Pays | Where{ $_.SideIndicator -eq "<=" }

Pour l'inverse, il suffit de changer le sens de la flèche dans le filtre.

On peut également afficher seulement les valeurs communes entre les deux fichiers en ajoutant le paramètre -ExcludeDifferent pour exclure les valeurs différentes :

Compare-Object -ReferenceObject $CSV1 -DifferenceObject $CSV2 -Property Pays -ExcludeDifferent

Sachez qu'il est possible de comparer plusieurs colonnes, et pas uniquement une seule comme ici avec la colonne "Pays". Une ligne peut alors ressortir plusieurs fois (dans les deux sens) s'il y a la valeur d'une colonne qui change dans un fichier, mais pas dans l'autre.

Voici un exemple en image avec l'ajout de la colonne "Continent" dans nos fichiers CSV. Dans cet exemple, pour le pays "Colombie", la valeur du continent évolue entre les deux fichiers, donc la ligne ressort une fois dans le sens "=>" et une seconde fois dans l'autre sens "<=".

IV. Compare-Object : comparer le contenu de deux dossiers

Pour finir ce tutoriel, prenons un autre cas concret : comparer le contenu de deux dossiers. Le but : identifier les fichiers présents dans un dossier, mais pas dans l'autre.

Voici les deux dossiers qui servent de cobaye :

Commençons par récupérer la liste des éléments avec récursivité via la commande Get-ChildItem.

$DOSSIER1 = Get-ChildItem "C:\TEMP\DOSSIER1\" -Recurse
$DOSSIER2 = Get-ChildItem "C:\TEMP\DOSSIER2\" -Recurse

Ensuite, on utilise la commande Compare-Object sur le même principe que précédemment, sans spécifier de propriété.

Compare-Object -ReferenceObject $DOSSIER1 -DifferenceObject $DOSSIER2

On obtient directement les chemins complets vers les fichiers qui sont absents dans un dossier ou l'autre.

On peut également utiliser le paramètre -Property pour compare les dates de dernière modification des fichiers. Cela nécessite de lire l'attribut LastWriteTime. On ajoutera également le nom du fichier (pas le nom complet) pour ne pas que la sortie contienne seulement la valeur de LastWriteTime.

Compare-Object -ReferenceObject $DOSSIER1 -DifferenceObject $DOSSIER2 -Property Name,LastWriteTime -IncludeEqual

Ainsi, on peut identifier les fichiers les plus récents plus facilement grâce à ce différentiel.

Maintenant, c'est à vous de jouer ! N'hésitez pas à tester ces différents exemples et les commentaires sont là si vous avez une question ?

Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Partager sur Google+ Envoyer par mail

Florian BURNEL

Ingénieur système et réseau, cofondateur d'IT-Connect et Microsoft MVP "Cloud and Datacenter Management". Je souhaite partager mon expérience et mes découvertes au travers de mes articles. Généraliste avec une attirance particulière pour les solutions Microsoft et le scripting. Bonne lecture.

Nombre de posts de cet auteur : 5561.Voir tous les posts

8 thoughts on “PowerShell – Comparer des objets avec Compare-Object

  • Bonjour Florian, je me demandais si c’etait possible de faire une condition avec compare-object?
    Par exemple est-il possible de faire un programme du style :
    S’il y a des differences faire quelque chose sinon faire autre chose.

    Répondre
    • Hello,
      Oui c’est possible, en stockant le résultat de la commande dans une variable tu pourras le tester et l’exploiter pour obtenir ce que tu veux 🙂
      Tu veux effectuer quelque chose peu importe le sens de changement ou seulement dans un sens ?
      Bonne journée 🙂
      Florian

      Répondre
      • Merci de ta réponse, j’ai trouvé la solution! Merci

        Répondre
        • Hello
          Pourrais-tu partager ta réponse ?

          Merci à toi

          Répondre
  • Bonjour Florian,

    je souhaite mettre le commun de deux listes dans une variable et suis un débutant en powershell

    ex :
    $tab1 = ‘aa’,’bb’,’cc’,’dd’
    $tab2 = ‘ab’,’ba’,’cc’,’cd’
    $res = Compare-Object $tab1 $tab2 -IncludeEqual | Where{ $_.SideIndicator -eq « == » }

    je souhaite avoir dans $res ou une autre variable juste cc

    Y a t il un livre que tu conseillerais sur powershell ?

    Merci
    Cordialement
    Bruno

    Répondre
    • Comme ça :
      $res = Compare-Object $tab1 $tab2 -IncludeEqual -ExcludeDifferent | Select InputObject

      Pour avoir une liste de string en résultat, ajoute -ExpandProperty :
      $res = Compare-Object $tab1 $tab2 -IncludeEqual -ExcludeDifferent | Select -ExpandProperty InputObject

      Répondre
  • Bonjour,

    Merci pour toutes ces explications ton blog est incroyable.
    C’est quand même impressionnant qu’il n’existe pas une commande équivalente à diff sur linux en PowerShell.

    Cordialement,
    Adaman

    Répondre
  • Bonjour
    Merci pour votre partage
    je veux utiliser compare object pour comparer 2 fichier csv avec 1champ commun
    dans le 1er Csv j’ai le champ samaccountname + d’autres champs (comptes qui devrait etre dans mon ad)
    dans le 2me Csv je n’ai que samaccountname (comptes qui sont effectivement dan mon AD)
    je compare t:
    compare-object -ReferenceObject $csv1 -DifferenceObject $csv2 -property samaccountname |where{ $_.SideIndicator -eq « <=" }
    je voudrais recuperer toute les infos du csv1 pour créer les comptes qui n'est pas dans csv2
    j'aimerais que compare object me renvoie la ligne du fichier pour que je puisse la traiter . Est ce possible
    Merci

    Répondre

Répondre à bruno Annuler la réponse

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.