I am trying to process some data in an ordered dictionary, then add that to another ordered dictionary, and I can do that by reinitializing my temporary dictionary, like this...
$collection = [Collections.Specialized.OrderedDictionary]::new()
foreach ($id in 1..5) {
    $tempCollection = [Collections.Specialized.OrderedDictionary]::new()
    foreach ($char in [Char]'a'..[Char]'e') {
        $letter = ([Char]$char).ToString()
        if ($id % 2 -eq 0) {
            $letter = $letter.ToUpper()
        }
        $int = [Int][Char]$letter
        $tempCollection.Add($letter, $int)
    }
    $collection.Add($id, $tempCollection)
}
foreach ($id in $collection.Keys) {
    Write-Host "$id"
    foreach ($key in $collection.$id.Keys) {
        Write-Host "   $key : $($collection.$id.$key)"
    }
}
However, I feel like reinitializing is a bit inefficient/inelegant, and I would rather just .Clear() that temporary variable. Which leads to this...
$collection = [Collections.Specialized.OrderedDictionary]::new()
$tempCollection = [Collections.Specialized.OrderedDictionary]::new()
foreach ($id in 1..5) {
    foreach ($char in [Char]'a'..[Char]'e') {
        $letter = ([Char]$char).ToString()
        if ($id % 2 -eq 0) {
            $letter = $letter.ToUpper()
        }
        $int = [Int][Char]$letter
        $tempCollection.Add($letter, $int)
    }
    $collection.Add($id, $tempCollection)
    $tempCollection.Clear()
}
foreach ($id in $collection.Keys) {
    Write-Host "$id"
    foreach ($key in $collection.$id.Keys) {
        Write-Host "   $key : $($collection.$id.$key)"
    }
}
The problem is that while simple objects like string, int, char, etc are passed by value, all complex objects like a dictionary are passed by reference. So I pass the SAME dictionary in every iteration of $collection.Add($id, $tempCollection) and the final state of $tempCollection is cleared, so the result is 5 empty members of $collection.
I know I can force something that is normally passed By Value to be By Reference using [Ref] as outlined here. And [Ref] is just an accelerator for System.Management.Automation.PSReference. So what I need is a way to force an argument By Value, but neither [Val] nor [ByVal] works, and searching for System.Management.Automation.PSValue doesn't seem to return anything useful either. The PSReference doco linked above says
This class is used to describe both kinds of references:
a. reference to a value: _value will be holding the value being referenced.
b. reference to a variable: _value will be holding a PSVariable instance for the variable to be referenced.
which makes me think I can get to the Value somehow, but for the life of me I can't grok HOW. Am I on the right track, and just missing something, or am I misunderstanding this documentation completely?
Cloning also seems like a potential solution, i.e. $collection.Add($id, $tempCollection.Clone()), but Ordered Dictionaries don't implement ICloneable. .CopyTo() also isn't an option, since it doesn't necessarily maintain the order of the elements. Nor does .AsReadOnly() since
The AsReadOnly method creates a read-only wrapper around the current OrderedDictionary collection. Changes made to the OrderedDictionary collection are reflected in the read-only copy. Nor does OrderedDictionary implement
.copy()as PSObject does.
I also tried making a new variable, like this...
$newCollection = $tempCollection
$collection.Add($id, $newCollection)
$tempCollection.Clear()
And that doesn't work either. So it seems that complex objects by reference seems to apply to more than just passed arguments.
It seems almost like my Ordered Dictionary choice/need is the root of the problem, but it seems like needing a unconnected copy of an Ordered Dictionary would not be such an edge case that it isn't supported.
