As I need to be able to add and remove items from an array I need to cast it as an ArrayList
as opposed to the more common options ([string[]]
, [Array]
, $Var=@()
). I also need to preset it with data, but the caller of the function needs the ability to change the preset as they desire. The preset in the Param()
block is required as another entity is looking for preset data. I've tried several variations, but here's the one that makes the most sense:
Function Test-Me{
Param
(
$Properties = [System.Collection.ArrayList]@(
"red",
"blue",
"green")
)
$Properties.GetType()
$Properties.Add("orange")
}
The above is great except that as soon as someone calls Test-Me -Properties "Purple","Yellow","Black"
the $Properties
variable becomes a standard Array
type (whereby add and remove methods don't work).
I tried methods of changing how I declared the preset values. It appears that the act of pre-populating is converting the type to a regular array. I figured this was because I was using @()
with the presets so I've tried ()
as well.
This doesn't work either:
Param
(
[System.Collection.ArrayList]
$Properties = @("red",
"blue",
"green")
)
I have a work around which converts the type outside the Param block and it looks like this:
Function Test-Me{
Param
(
[String[]]
$Properties = @("red",
"blue",
"green")
)
if("Orange" -notin $Properties){
[System.Collections.ArrayList]$Properties = $Properties
$Properties.Add("orange")
}
}
I feel like I should be able to cast as an ArrayList
in the param block and preset it with data, and return as the same datatype, but I couldn't figure it out. If anyone does, or finds documentation why it won't work, please answer.
Explicit parameter type casting
The second example you posted (explicitly casting the parameter variable) is the correct way to go:
Resulting in:
OutputType
One thing that surprised me though, is that even with the
[OutputType]
attribute, the function outputs a regular array (this may actually bea bugintended behavior, see update below):Still resulting in a regular object array being returned:
Update (with easy workaround)
As demonstrated in the comment on your Connect bug submission, PowerShell deliberately enumerates the items of any enumerable output in order to provide a consistent behavior for the pipeline (pseudo-C# stolen from commentor Derp McDerp on Connect):
The trick is then to wrap the collection in a single-item array, causing PowerShell to pipe it as a single item (notice to
,
before$Properties
):and now, we get an output with the correct type:
A co-worker was just asking me to explain some details related to this, so I thought it may be beneficial to share some supplemental information with others who come here with this question in the future.
In PowerShell, there are three basic ways to assign values to variables:
If you want to ensure that a variable (or a function parameter) is of a specific type, you must use strong typing, as was done with
$myVariable3
. Doing so prevents the type from changing to something else accidentally (e.g.$myVariable3 = 42
will fail with an error).It is useful to know that you can identify when a variable is strongly typed by using the
Get-Variable
cmdlet. For example, invokingGet-Variable myVariable1,myVariable2,myVariable3 | Format-List Name,Value,Visibility,Options,Attributes
yields the following output:Note how these are all the same except that the
myVariable3
variable has an attribute in theAttributes
property. AnArgumentTypeConverterAttribute
is added to any variable that is strongly typed, and that attribute will ensure that variable remains of the same type no matter what you assign it to.Understanding how variable assignment works, as well as how to return a collection intact as Mathias pointed out above, makes it much easier to work with data in PowerShell.