Reputation: 517
The below script is an example of me importing a CSV file, trying to edit one of the values, then checking the value.
$Animal_Farm = Import-CSV "Test.csv"
Echo "The Data"
$Animal_Farm
Echo "`n`n`n"
Echo "Dog's Status"
$Animal_Farm.Status[1]
Echo "`n`n`n"
Echo "Updating Dog's Status to Employed"
$Animal_Farm.Status[1] = "Employed"
Echo "`n`n`n"
Echo "Dog's Status"
$Animal_Farm.Status[1]
This is the output, the data is unchanged and Dog's status is still Redundant.
The Data
Animal Ocupation Status
------ --------- ------
Cat Construction Employed
Dog Professional Redundant
Rat GP Employed
Dog's Status
Redundant
Updating Dog's Status to Employed
Dog's Status
Redundant
How do I edit the data imported? My plan is to feed the modified data into a JSON file.
This is the CSV file contents
Animal,Ocupation,Status
Cat,Construction,Employed
Dog,Professional,Redundant
Rat,GP,Employed
Upvotes: 2
Views: 260
Reputation: 440142
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.
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.
Upvotes: 3
Reputation: 174920
$Animal_Farm
holds an array of objects, each of which have a Status
property.
When you ask PowerShell to resolve $Animal_Farm.Status
, PowerShell goes "huh, the $Animal_Farm
array doesn't have a Status
property, let me create a new array from the Status
property values of each item in the array", which is what you eventually index into with $Animal_Farm.Status[1]
.
To address the properties of one of the underlying items in the original array, use the index operator directly on $Animal_Farm
instead:
$Animal_Farm[1].Status
Upvotes: 3