Qui n’a jamais eu à consolider deux listes en PowerShell ? Et comme moi, vous en avez marre de prendre un café en attendant la fin du script … Et bien, je vais vous donner une petite astuce pour accélérer drastiquement vos temps d’exécution 🙂
HashTable … kesako ?
Alors non, ce n’est pas une technique ancestrale pour découper des tables. Je ne suis pas un bucheron, mais si je suis parfois un peu bourrin 😉
Une HashTable est une liste indexée. Et c’est là que tout va se jouer : sur l’index.
Prenons, un exemple : j’ai une liste de 5000 utilisateurs avec les attributs : GUID et displayName
Si vous recherchez le displayName pour un GUID donné, vous devez faire une requête comme celle-ci
$monuser = $userList |where-object {$_.GUID -eq 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'}
Le problème est que pour récupérer la ligne qui nous intéresse, on parcours toutes les lignes une par une et on teste l’attribut qui nous intéresse. Pas très performant, vous en conviendrez.
Maintenant, imaginez que nous avons construit une HashTable des utilisateurs avec le GUID comme index. Notre commande PowerShell devient
$monuser = maHashTable['aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee']
C’est plus simple à lire et les temps d’exécution font rêver …
La démonstration
Dans mon exemple, je vais partir d’une liste d’évènements. Chaque évènement identifie un utilisateur par son GUID. De l’autre côté, j’ai la liste des utilisateurs avec le displayName associé au GUID.
Je vais créer les listes :
function create-users {
param(
$count = 5000
)
foreach ($i in 0..$count) {
[PSCustomObject]@{
guid = new-guid
displayName = "Kevin-{0}" -f $i
}
}
}
function create-events {
param(
$count=10000,
$guidList
)
foreach ($i in 0..$count) {
[PSCustomObject]@{
id = new-guid
userid = $guidList |get-random
eventid = get-random
}
}
}
# Je génère mes listes
$users = create-users
$events = create-events -guidList $users.guid
Maintenant, je peux parcourir mes évènements et associé le displayName à chaque évènement et mesurer le temps d’exécution
Tout d’abord par la méthode habituelle
$starttime1 = get-date
foreach ($e in $events) {
$e|add-member -notepropertyname "displayName1" -notepropertyvalue ($users|? {$_.guid -eq $e.userid}).displayName -force
}
$duration1 = ((get-date) - $starttime1).totalseconds
Ensuite en passant par une hashtable
# Je stocke mes utilisateurs dans une hashtable indexée par GUID
$usersHashtable = @{}
$users |% { $usersHashtable[$_.guid] = $_ }
# j'ajoute l'attribut displayname à mes évènements par la hashtable
$starttime2 = get-date
foreach ($e in $events) {
$e|add-member -notepropertyname "displayName2" -notepropertyvalue $usersHashtable[$e.userid].displayName -force
}
$duration2 = ((get-date) - $starttime2).totalseconds
Et maintenant je compare les résultats pour une liste de 5000 utilisateurs et 10000 évènements :
- Méthode standard : 771,7362843 secondes
- Méthode HashTable : 6,6859321 secondes
Je pense qu’il n’y a pas photo 🙂
Voilà, vous allez pourvoir réduire les temps d’exécution de vos scripts. Pour ceux d’entre-vous qui font tourner des Runbook PowerShell sur Azure dans un Automation Account, vous allez faire des économies !!!