Search code examples
powershellhashtable

Unable to remove item from hash table


In Powershell, I have a hash table that contains data similar to this -

Name                   Value                                           
----                   -----                                           
1-update.bat           1                                               
2-update.bat           2                                               
3-update.bat           3                                               
3.1-update.bat         3.1                                             
4-update.bat           4    

I also have an variable that contians a number, for example 3

What I would like to do is loop through the array and remove any entry where the value is less than or equal to 3

I'm thinking that this will be easy, especially as the docs say that has tables contain a .remove method. However, the code I have below fails, yeilding this error -

Exception calling "Remove" with "1" argument(s): "Collection was of a fixed size."

Here is the code that I used -

$versions = @{}
$updateFiles | ForEach-Object {
    $versions.Add($_.name, [decimal]($_.name -split '-')[0])
}

[decimal]$lastUpdate = Get-Content $directory\$updatesFile

$versions | ForEach-Object {
    if ( $_.Value -le $lastUpdate ) {
        $versions.Remove($version.Name)
    }
}

I first tried to loop $versions in a different manner, trying both the foreach and for approaches, but both failed in the same manner.

I also tried to create a temporary array to hold the name of the versions to remove, and then looping that array to remove them, but that also failed.

Next I hit Google, and while I can find several similar questions, none that answer my specific question. Mostly they suggest using a list (New-Object System.Collections.Generic.List[System.Object]), whcih from what I can tell is of no help to me here.

Is anyone able to suggest a fix?


Solution

  • Here you go, you can use .Remove(), you just need a clone of the hashtable so that it will let you remove items as you enumerate.

    [hashtable]$ht = @{ '1-update.bat'=1;'2-update.bat'=2;'3-update.bat'=3;'3.1-update.bat'=3.1; '4-update.bat'=4    }
    
    #Clone so that we can remove items as we're enumerating
    $ht2 = $ht.Clone()
    foreach($k in $ht.GetEnumerator()){ 
        if([decimal]$k.Value -le 3){
            #notice, deleting from clone, then return clone at the end
            $ht2.Remove($k.Key) 
        } 
    }
    
    
    $ht2
    

    Notice I've cast the original variable too so that it's explicitly a hash table, may not be required, but I like to do it to at least keep things clear.