PowerShell – Comparer des objets avec Compare-Object
Sommaire
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 :
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 :
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 ?
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.
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
Merci de ta réponse, j’ai trouvé la solution! Merci
Hello
Pourrais-tu partager ta réponse ?
Merci à toi
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
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
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
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