Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a custom property to a PowerShell array?

Say I have a PowerShell array $Sessions = @() which I am going to fill with PSCustomObjects. How can I add a custom property to the array itself? E.g. so I can have $Sessions.Count which is built-in and $Sessions.Active which I want to set to the active session count.

I know that I can add properties to PSCustomObjects (in a dirty way) with

$MyCustomObject = "" | Select-Object Machine, UserName, SessionTime

but though doing so on an array would not result in the property being added.

So how can I achieve my goal? Is there any way to create a custom array?

like image 520
FatalMerlin Avatar asked Sep 11 '17 11:09

FatalMerlin


People also ask

How do you add a property to an array?

We can use the forEach method to loop through each element in an object and add a property to each. We have the arr array. Then we call forEach with a callback that has the element parameter with the object being iterated through and we assign the b property to a value. according to the console log.

How do I add an item to an array in PowerShell?

To add value to the array, you need to create a new copy of the array and add value to it. To do so, you simply need to use += operator. For example, you have an existing array as given below. To add value “Hello” to the array, we will use += sign.

How do I add a property to a PowerShell object?

Use Add-Member to Add Properties to Objects in PowerShell Not only can we create custom objects in PowerShell, but we can also add to them through the help of the Add-Member command. The Add-Member cmdlet does not list members but adds them instead.

How do you assign a value to an array in PowerShell?

To create and initialize an array, assign multiple values to a variable. The values stored in the array are delimited with a comma and separated from the variable name by the assignment operator ( = ). The comma can also be used to initialize a single item array by placing the comma before the single item.


2 Answers

The answer to your question as stated would be to just use Add-Member on the array object.

Add-Member -InputObject $sessions -MemberType NoteProperty -Name "State" -Value "Fabulous"

Adding a property to each element after you created the object is similar.

$sessions | ForEach-Object{
    $_ | Add-Member -MemberType NoteProperty -Name "State" -Value "Fabulous"
}

This of course comes with a warning (that I forgot about). From comments

Beware, though, that appending to that array ($sessions += ...) will replace the array, thus removing the additional property.

Ansgar Wiechers

Depending on your use case there are other options to get you want you want. You can save array elements into distinct variables:

# Check the current object state
$state = $object.Property .....

# Add to the appropriate array.
if($state -eq "Active"){
    $activeSessions += $object
} else {
    $inactiveSessions += $object
}

Or you could still store your state property and post process with Where-Object as required:

# Process each inactive session
$sessions | Where-Object{$_.State -eq "Active"} | ForEach-Object{}

To avoid the destroying / recreating array issue, which can be a performance hog, you could also use an array list instead.

$myArray = New-Object System.Collections.ArrayList
Add-Member -InputObject $myArray -MemberType ScriptMethod -Name "NeverTellMeTheOdds" -Value {
    $this | Where-Object{$_ % 2 -ne 0}
}

$myArray.AddRange(1..10)
$myArray.NeverTellMeTheOdds()

Notice that the array had its member added then we added its elements.

like image 87
Matt Avatar answered Oct 25 '22 13:10

Matt


As Matt commented, you can use the Add-Member on an enumerable type by supplying it as a positional argument to the -InputObject parameter.

To allow for resizing after adding the new property, use a generic List instead of @():

$list = [System.Collections.Generic.List[psobject]]::new()
$list.AddRange(@(
  [pscustomobject]@{SessionId = 1; Active = $true}
  [pscustomobject]@{SessionId = 2; Active = $false}
  [pscustomobject]@{SessionId = 3; Active = $true}
) -as [psobject[]])

Add-Member -InputObject $list -MemberType ScriptProperty -Name ActiveSessionCount -Value {
  return @($this |? Active -eq $true).Count
}

Now you can retrieve the active session count easily:

PS C:\> $list.ActiveSessionCount
2
like image 23
Mathias R. Jessen Avatar answered Oct 25 '22 13:10

Mathias R. Jessen