2

I need to define a container in powershell which cannot be modify able once it is created. I know there is a way, by which variables can be created as hidden in current run space but still somehow that is also not safe for my problem.

I want to create some write protected and hidden variable in such a way, once it is initialised, it shouldn't be replaceable. I would like to have dictionary that shouldn't be replaced. It have values those must be added within it but dictionary instance itself should be replaceable itself.

SessionState.PSVariable.Set(new PSVariable(paramContainerName, new Dictionary<string, PSObject>(), ScopedItemOptions.Private | ScopedItemOptions.ReadOnly))

Above can easily be replaced. Somebody can replace above dictionary by

$paramContainerName = [] in the powershell script or at terminal. Is there any way by which we can stop this.

Usman
  • 2,742
  • 4
  • 44
  • 82
  • 1
    "Somebody can replace above dictionary" - no, they can *hide it* behind a new variable with a more specific scope, they can't replace it. What are you trying to achieve? What is the underlying requirement for this? – Mathias R. Jessen Jul 03 '18 at 16:23
  • for example above dictionary was created during the initialization of commandlet. Then on powershell terminal i can simply replace the values of above dictionary by access it. ( e.g. $v = Get-Variable paramContainerName , and $v.Value.Add("Something", null) ) . – Usman Jul 03 '18 at 16:41
  • Please understand that above hidden dictionary can be read or accessed somehow. Consider it is not hidden. – Usman Jul 03 '18 at 16:42

2 Answers2

2

You seem to be confusing write-protection of the variable with write-protection of the contents of the dictionary stored in that variable.

Use a ReadOnlyDictionary<K,T> if you want no one to be able to write new entries to it:

var readOnlyDict = new ReadOnlyDictionary<string, PSObject>(new Dictionary<string, PSObject>(){
    { "initKey1", initPSobject1 },
    { "initKey2", initPSobject2 },
});
SessionState.PSVariable.Set(new PSVariable(paramContainerName, readOnlyDict, ScopedItemOptions.Private | ScopedItemOptions.ReadOnly))
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
1

You can use the New-Variable to create a constant, allscope variable. Constant variables can't be removed from the runspace and can't be set after initialization. AllScope will make sure the variable can't be overridden in a child scope. The code looks like:

 New-Variable -Name paramContainerName -Value $myReadonlyDictionary  -Option 'AllScope,Constant'

Combining this with a read-only dictionary will give you a variable that can't be changed for the duration of the session.

Bruce Payette
  • 2,511
  • 10
  • 8