Search code examples
powershellperformance

Faster way to copy properties from one object to another


Currently I have two objects, one is $allVMs and has 1500 records

vmip           : 10.x.x.x
hypervisorhost : xxxxx.yyyyyyyyyy.lan
cluster        : zzzzzzzzzz
manager        : aaaaaaa
bladenaam      : empty
domainnaam     : empty
natip          : empty

and another object $allBlades which has 500 records.

domain    : dom01
name      : name01
pndn      : pndn01

I for each $vm in $allVMs, I have to search the corresponding blade in $allBlades and when found add name and domain from that blade to the $vm.domain and $vm.name.

Currently I just created a loop on $allVMs and per VM I do a "select-object | where" in $allBlades. It takes quite some time to go through the loop, about an hour. Is there a faster way?

foreach( $VM in $AllVMs)
{
    if( $null -ne $vm.vmnaam)
    {
        $Hostname = $($vm.hypervisorhost).split(".")[0]
        $FoundBlade = $AlleBlades | Where-Object {$_.name -match $hostname }
        if ($null -eq $FoundBlade)
        {
            write-host "Blade  $($vm.hypervisorhost) not found"
        }
        else
        {
            $vm.bladenaam = $FoundBlade.name
            $vm.domainnaam = $FoundBlade.domain 
        }
    }
}

Solution

  • Use a hash-based search (any IDictionary implementing type, most commonly used in PowerShell for this kind of task is hash table @{}) instead of linear search (Where-Object):

    $bladesMap = @{}
    foreach ($item in $AlleBlades) {
        $bladesMap[$item.name] = $item
    }
    
    foreach ($VM in $AllVMs) {
        if ($null -ne $vm.vmnaam) {
            $Hostname = $vm.hypervisorhost.Split('.')[0]
    
            if (-not $bladesMap.ContainsKey($Hostname)) {
                Write-Host "Blade  $($vm.hypervisorhost) not found"
            }
            else {
                $item = $bladesMap[$Hostname]
                $vm.bladenaam = $item.name
                $vm.domainnaam = $item.domain
            }
        }
    }