I am familiar with creating read-only variables and constants in PowerShell by using the Set-Variable command with something like this:
Set-Variable -Option ReadOnly, AllScope -Name STANDARD_TOKEN_PARAMS -Force -Value @{
Username = 'username'
Password = 'password'
ClientId = 'clientID'
}
Or alternatively to sub ReadOnly with Constant for non-removable variables.
I assumed that with the ReadOnly option I would not be able to modify the collection, but this isn't the case. For example, $STANDARD_TOKEN_PARAMS.someNewEntry = 'newEntry' is valid and modifies the collection accordingly.
Are there similar commands that I could use to create a real 'ReadOnly' collection in PowerShell?
The options
ReadOnlyandConstantare variable (data-holder) concepts: they only prevent assigning a new value to the variable, they don't prevent modification of the value that a read-only/constant variable immutably stores.To also prevent modification of the value (object) itself, you must additionally use a read-only data type[1] to store in the read-only/constant variable. To get a read-only hash table (dictionary), use the generic
System.Collections.ObjectModel.ReadOnlyDictionary[TKey, TValue]type:Note:
Unfortunately, you cannot directly initialize a
ReadOnlyDictionary[TKey, TValue]instance from a PowerShell[hashtable], because a genericIDictionary-implementing instance with matching types is required; therefore, an auxiliarySystem.Collections.Generic.Dictionar[TKey, TValue]instance is used.Note the
[System.StringComparer]::OrdinalIgnoreCaseargument passed to the aux. dictionary, which ensures that key lookups are case-insensitive, the way they are by default in PowerShell[hashtables].[2]While the resulting
$STANDARD_TOKEN_PARAMSread-only variable's value is then effectively also read-only, accidental attempts to modify the read-only dictionary result in error messages that aren't obvious, as of PowerShell Core 7.1:$STANDARD_TOKEN_PARAMS['Username'] = 'foo'unhelpfully reports:Unable to index into an object of type "System.Collections.ObjectModel.ReadOnlyDictionary2[System.String,System.String]`$STANDARD_TOKEN_PARAMS.Add('foo', 'bar')unhelpfully reports:Cannot find an overload for "Add" and the argument count: "2"$STANDARD_TOKEN_PARAMS.Clear()unhelpfully reports:Cannot find an overload for "Clear" and the argument count: "0".$STANDARD_TOKEN_PARAMS.Username = 'foo'reportsCollection is read-only.[1] This isn't always necessary, namely not if the value is an instance of a by definition immutable .NET primitive type (a property-less type such as
[int]) or a[string].[2] Note that
[hashtable]in Windows PowerShell and (obsolete) PowerShell Core versions 6.1 and below use[System.StringComparer]::CurrentCultureIgnoreCase, i.e, culture-sensitive lookups instead - see this GitHub issue for background information.