1

I have a script that returns a DictionaryEntry collection, I've noticed if that dict happens to only have one K/V pair that I must specify var.value vs if it has multiple its var.values ! what gives? is there a common way to resolve this? in one command?

Tony
  • 8,681
  • 7
  • 36
  • 55
  • Are you using [tag:powergui] by any chance? [See this comment](https://stackoverflow.com/questions/36090764/powershell-hash-table-storing-values-of-system-collections-dictionaryentry#comment59826420_36090764). – briantist Nov 03 '21 at 02:15
  • hmm no using vscode – Tony Nov 03 '21 at 02:19
  • 2
    It might be helpful to see your script code, or at least a [mcve]. It sounds to me like when you have multiple entries you're returning a real `[hashtable]` and when you have one, you are for some reason returning a `DictionaryEntry`. – briantist Nov 03 '21 at 02:20
  • 1
    An individual `DictionaryEntry` has `Key` and `Value` properties. A `Hashtable`, by way of implementing [`IDictionary` interface](https://docs.microsoft.com/dotnet/api/system.collections.idictionary), has `Keys` and `Values` properties that return all keys and all values, respectively. It sounds like [how properties are handled for collections](https://docs.microsoft.com/powershell/module/microsoft.powershell.core/about/about_properties#properties-of-scalar-objects-and-collections) is what you're seeing, though it seems like when you access the single entry it must not be through a collection. – Lance U. Matthews Nov 03 '21 at 02:26
  • 2
    Though it yielded a quality answer, this question leaves a lot to be desired. I'd recommend _showing_ rather than (barely) _describing_ the code as well as not relying on abbreviations. – Lance U. Matthews Nov 03 '21 at 07:50

1 Answers1

6

if that dict happens to only have one K/V pair that I must specify var.value

No: The implication is that you're dealing with an isolated key-value pair or a (non-dictionary) collection (array) of such pairs, such as [System.Collections.DictionaryEntry] instances, that aren't part of a (single) dictionary (hashtable):

# Single key-value pair
$kvPair = [System.Collections.DictionaryEntry]::new('foo', 42)
$kvPair.Value # -> 42

# Array of key-value pairs
(
  [System.Collections.DictionaryEntry]::new('foo', 42), 
  [System.Collections.DictionaryEntry]::new('bar', 43)
).Value # -> 42, 43

The fact that .Value works even on an (array-like) collection of key-value pairs - even though .Value is a property of that collection's individual elements - is owed to PowerShell's member-access enumeration feature.


By contrast, .Values is a type-native property of a dictionary (hashtable) object. Such an object contains a (typically unordered) internal collection of key-value pairs with distinct keys, whose values the .Values property returns as a collection; using a [hashtable] literal as an example:

# Single-entry hashtable.
@{ foo = 42 }.Values # -> @(42) (single-element collection)

# Multi-entry hashtable.
@{ foo = 42; bar = 43 }.Values # -> 42, 43

Note, however, that - unlike with member-access enumeration - the .Values property always returns a collection, even if that collection happens to contain just one element.

PowerShell considers a dictionary / hashtable a single object, which has two implications:

  • It is sent as whole to the pipeline.

    • To request sending its entries (key-value pairs), one by one, instead, you must call .GetEnumerator() explicitly.
  • Member-access enumeration is not applied, so that .Value can not be used to return the individual entries' .Value property values.

    • Instead, use the type-native .Values property, as shown above (or .Keys, to get the collection of keys).
mklement0
  • 382,024
  • 64
  • 607
  • 775