1

Mutable .Net list, as e.g. List Class, are often preferred above the native immutable PowerShell Array @() along with:

Unfortunately, these types are not available in Constrained Language mode

$ExecutionContext.SessionState.LanguageMode = 'ConstrainedLanguage'
$List = [Collections.Generic.List[object]]::new()

InvalidOperation: Cannot create type. Only core types are supported in this language mode.

Is there a way to work around this?

iRon
  • 20,463
  • 10
  • 53
  • 79

1 Answers1

1

The constrained language mode might be quite a burden if want write sophisticated (recursive) PowerShell script.

  • Since Constrained Language is so limited, you will find that many of the approved scripts that you use for advanced systems management no longer work. The solution to this is simple: add these scripts (or more effectively: your code signing authority that signed them) to your Device Guard policy. This will allow your approved scripts to run in Full Language mode. See: PowerShell Constrained Language Mode
  • If you are administrator you might consider to (temporary) disable the constrained language mode completely, see: how to change PowerShell mode to full language mode from constrained mode?

Anyways, as a workaround, you might consider using the native (mutable) PowerShell HashTable collection (or an [ordered] type) instead:

# $ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
$List = @{}
function AddItem {
    $List.Add($List.Count, (New-Guid)) # or just: $List[$List.Count] = New-Guid
}
AddItem
AddItem

Although this creates a key-value pair for every entry (where the key is redundant), you might simply obtain just the values with the .Values property:

$List.Values

Guid
----
b22f9cdd-9dba-4868-978e-ccdee3723685
2ccd98a0-a729-4b07-9bd9-8f1306be28d3

Ordered
Hashtables are unordered by nature which means the first added item doesn't have to be the first item when you list the values ($List.Value). To overcome that, you might sort the list at the moment it is required:

$List.Keys |Sort-Object |ForEach-Object { $List[$_] }

Or as the Sort-Object cmdlet is quiet expensive and the keys are predefined:

0..$($List.Count) |ForEach-Object { $List[$_] }

Or using a for loop:

for ($i = 0; $i -lt $List.Count; $i++) { $List[$i] }

Or you might consider to use a [Ordered] collection type to keep items (values) in order from the start. For this, be aware that:

  • apparently the constrained language mode does support the Add() method of the ordered collection type either:
    Cannot invoke method. Method invocation is supported only on core types in this language mode.
  • any integer key refers to the actual index in the collection rather than an associated key (to resolve this, you might cast the index to a string)

In other words the following modifications are required to use an ordered dictionary instead of a hashtable:

$List = [ordered]@{}
function AddItem {
    $List[$List.Count.ToString()] = New-Guid
}

Notes

iRon
  • 20,463
  • 10
  • 53
  • 79