To complement Mathias R. Jessen's helpful answer with conceptual information:
As Mathias states, accessing a property (.Status
) on a collection (array) of objects ($Animal_Farm
) automatically returns the property values of the collection's elements in an array[1] (assuming the collection doesn't itself have a property by this name, in which case the latter takes precedence).
This feature, which also works with methods, is called member-access enumeration, and is explained in more detail in this answer.
Member-access enumeration does not support assigning to properties, however:
If you tried something like $Animal_Farm.Status = 'Employed'
in an attempt to set the status property for all animals, you'd get a somewhat surprising error, stating the collection $Animal_Farm
has no .Status
property.
- The surprising error message (which is technically correct) notwithstanding, this inability to assign a (by definition uniform) value to a given property of all individual elements of a collection is by design.
- By contrast, calling a mutating method via member-access enumeration - if available - is possible.
- For more information, see this answer and GitHub issue #5271.
If you attempt to assign a property value via indexing ([...]
) into an array of values obtained with member-access enumeration ($Animal_Farm.Status
), e.g. $Animal_Farm.Status[1] = "Employed"
, that assignment is quietly ignored.
The reason is that $Animal_Farm.Status
returns an array of property values that are no longer connected to the objects they came from, and while you can technically modify this array by assigning to its elements, the modified array is simply discarded after the assignment statement, given that it isn't captured anywhere.
In short: You're mistakenly modifying a temporary array.
By contrast, applying the index to the collection itself ($Animal_Farm[1]
to return the 2nd object stored in the collection) returns an object reference whose .Status
property you can then effectively modify ($Animal_Farm[1].Status = "Employed"
)
Simplified example:
# Create a 2-element sample array.
$animals = [pscustomobject] @{ Animal = 'Cat'; Status = 'Employed' },
[pscustomobject] @{ Animal = 'Dog'; Status = 'Redundant' }
# Trying to set the status of ALL animals via member-access enumeration
# CAUSES AN ERROR, because it isn't supported:
# InvalidOperation: The property 'Status' cannot be found on this object. [...]
$animals.Status = 'Employed' # !! ERROR
# Trying to set the status of ONE animal via member-access enumeration is
# QUIETLY IGNORED:
# * What is being modified is a *temporary array* of property values.
# * Therefore, $animals.Status[1] is still 'Redundant' after this statement.
$animals.Status[1] = 'Employed' # !! QUIETLY IGNORED
# OK: Avoid member-access enumeration, and index directly into the collection
# to get the animal object of interest, then set its property:
$animals[1].Status = 'Employed' # OK
[1] Technically, an array of values is only returned if the input collection has two or more elements; for a single-element collection, that one element's property value is returned as-is. In other words: member-access enumeration behaves like the PowerShell pipeline; see this answer and this answer for examples of associated pitfalls, and GitHub issue #6802 for a discussion of this perhaps surprising behavior.