none
How to update an object property located in an array of objects RRS feed

  • Question

  • Hello all,

    I have a script that creates custom objects and populates them and saves them into an array. This array of objects is later converted to a CSV file for reuse later on. On a subsequent need to run the script and to save time and avoid recollecting data I have previously amassed, I read in the contents of the csv file and put this data into an arryOfObjects.

    I need to manipulate the data in specific objects but I can't figure out how to accomplish that task.

    I can identify the correct object within the array with the following command. I have been trying to pipe that result into either set-variable or set-itemproperty without success.

    $arrayOfObjects | select-object | where HostName -like $_.'name'

    This works, I can see my desired object and the data fields contained within it.

    I now need to modify one of the property fields. (Alias).

    I have been trying the following as a line of thought, but so far without success. It doesn't fail/error out, but it doesn't update the data either.

    $arrayOfObjects | select-object | where HostName -like $_.'name' | set-itemproperty -name Alias -value "newAlias"

    I'm wondering if I need to specify something for the -path argument, but since the array is in memory and not a registry location or a file I am not sure what I should use, if this is the problem at all.

    Any suggestions would be appreciated.

    Thanks

    Smitty

    Wednesday, December 31, 2014 7:19 PM

Answers

  • I like Bill's solution, but it should also be possible for you to change the actual objects themselves instead of creating new ones. 

    I've done what SteveLarson-W mentioned above in the past, so I'm not sure why that's not working for you. If you take Bill's sample data above ($myTable), you should be able to walk through the following examples to directly change the objects' properties:

    # Look at the original data
    $myTable
    
    # Make a change using SteveLarson-W's method:
    $myTable | where Column1 -like "Row1*" | foreach { $_.Column2 = "Direct assignment" }
    
    # Look at updated data
    $myTable
    
    # Use Add-Member to overwrite property:
    $myTable | where Column1 -like "Row2*" | foreach { $_ | Add-Member -MemberType NoteProperty -Name Column2 -Value "Add-Member" -Force }
    
    # Look at updated data
    $myTable
    
    # Use PSv3+ Add-Member parameters:
    $myTable | where Column1 -like "Row3*" | foreach { $_ | Add-Member -NotePropertyName Column2 -NotePropertyValue "Add-Member PSv3+" -Force }
    
    # Look at updated data
    $myTable

    The final output should look like this:
    Column1      Column2            Column3    
    -------      -------            -------    
    Row1Column1  Direct assignment  Row1Column3
    Row2Column1  Add-Member         Row2Column3
    Row3Column1  Add-Member PSv3+   Row3Column3

    Does that help any?



    Tuesday, January 6, 2015 1:49 AM

All replies

  • Arrays do not have named properties.  An array of objects has names but all objects must be the same.

    Import-csv file.csv | where{$_.name -match 'something'}


    ¯\_(ツ)_/¯

    • Proposed as answer by jrv Thursday, January 1, 2015 5:17 AM
    Wednesday, December 31, 2014 7:48 PM
  • After the Where-Object cmdlet returns the object you want, use Foreach-Object to set the properties you want to change. As an example, " | % {$_.name = 'hostname';$_.ip = '1.1.1.1'}".
    Thursday, January 1, 2015 3:47 AM
  • $ArrayOfObjects=@()

    $ObjectProperties = @{'Property1'="Val1";'Property2'="Val2";'Property3'="Val3";}
    $Object1 = New-Object -TypeName PSObject -Property $ObjectProperties

    $ArrayOfObjects += $Object1

    $ObjectProperties = @{'Property1'="Val4";'Property2'="Val5";'Property3'="Val6";}
    $Object2 = New-Object -TypeName PSObject -Property $ObjectProperties

    $ArrayOfObjects += $Object2

    See if the above works for you. I find this to be an easier way to manipulate objects within arrays.


    Thursday, January 1, 2015 5:11 AM
  • Why does everyone of all of you so much make complicated complications of otherwise simple and uncomplicated simple selections of little things.

    Perhaps you have some noise issues?

    It is a filter tha tis needed and not much more.

    Happy New Ear!


    ¯\_(ツ)_/¯

    Thursday, January 1, 2015 5:20 AM
  • JRV,

    I don't have a problem importing a csv file.

    In fact once I have created the output of my previous run of my entire network, I am reusing the collected data to improve the crunch time by eliminating the need to re-evaluate those systems that  I have evaluated in the past. But since each of these objects do have the potential to have their last report-in date to become stale, I need to re-evaluate this portion of those previously evaluated objects. If in fact, any of them have become stale, then they need to have some of their properties modified to allow me to print them out in my report.

    As for your second answer below. Looking at your points (88,394) it's obvious you're powershell savy, but your answer is not really an answer. If you have a better solution then please show us. Bloviating on how we should not make something complicated when it isn't necessary but then not elaborating on how to accomplish it, doesn't really help much.

    No offense intended.

    Thanks,

    Monday, January 5, 2015 4:06 PM
  • I think jrv is trying to say that your approach may be flawed.

    If your collection is expensive (time-consuming) to retrieve, then eliminate the time-consuming part and write the data to a CSV file. Then you can retrieve it quickly, change what you want in a foreach loop (or filter with where-object, etc.), and do whatever you want at that point.


    -- Bill Stewart [Bill_Stewart]

    Monday, January 5, 2015 4:14 PM
    Moderator
  • Raghu,

    I have already used that type of code when I created the objects originally. Thanks.

    After I had populated the objects with all of the data I wanted to know, IP, inDNS, inAD, etc. I saved all of my earlier results to a CSV file for future use.

    Now I am reading in the csv file to avoid many of the time consuming tasks that I have already paid for, (things that don't typically change) but I need to evaluate the items that are of concern to my report. Is the last reporting date stale or not.

    So I will take the last report date from the updated list and swap out the previous object's property value, with the new data, then evaluate it to see if it meets my criteria for being stale, if so then update another property within the object.

    Monday, January 5, 2015 4:26 PM
  • The code you have posted shows some confusion about how PowerShell works.  Look at this line of yours:

    $arrayOfObjects | select-object | where HostName -like $_.'name'

    The "select object" does nothing at all unless you have a column in your CSV called "object".  The where clause will do nothing because it is syntatctically wrong and illogical. 

    You fail to tell us what is in the "array of objects" (CSV) file so we cannot easily guess at what you are asking.

    I recommend that you start by looking up CSV files to see how they are structured then look for examples of how to use a CSV file.

    We have posted suggestions of how to both filter and update the fields in a CSV.  A little testing and reading of the CmdLet help should sort this out for you.


    ¯\_(ツ)_/¯

    Monday, January 5, 2015 4:30 PM
  • Raghu,

    I have already used that type of code when I created the objects originally. Thanks.

    After I had populated the objects with all of the data I wanted to know, IP, inDNS, inAD, etc. I saved all of my earlier results to a CSV file for future use.

    Now I am reading in the csv file to avoid many of the time consuming tasks that I have already paid for, (things that don't typically change) but I need to evaluate the items that are of concern to my report. Is the last reporting date stale or not.

    So I will take the last report date from the updated list and swap out the previous object's property value, with the new data, then evaluate it to see if it meets my criteria for being stale, if so then update another property within the object.


    Your description of what you want to do its vague.  There is no way to understand what you are trying to do from your discussion.  Post a sample of your CSV and your script so we can try to understand what you are asking.

    ¯\_(ツ)_/¯

    Monday, January 5, 2015 4:46 PM
  • Steve,

    thanks for your reply. Tried your option but it still didn't make any changes to the specified object within the array of objects.

    example output:

    Each object has 21 properties. (not all shown for brevity)

    $objectCollection | Select-Object | where N_HostName -like $_.'name'  returns the following:

    IP: 1.2.3.4

    N_HostName: abcd.us

    IsStale: No

    LastMsgDate: Dec 30 2014 09:15:00

    Delta: 1

    Ping: Yes

    InDNS: Yes

    InAD: Yes

    Alias: *

    ______________________

    conditions running during the code execution:

    $_.'name'  = abcd.us

     

    $objectCollection | Select-Object | where N_HostName -like $_.'name' | Foreach-Object {$_.Alias='newAlias'}

    result:  No change?????

    Am I doing something obviously wrong in my command?

    Monday, January 5, 2015 5:08 PM
  • Your command makes no sense.  Why are you using select-object?  It serves no purpose.

    $objectCollection | where N_HostName -match name 

    $_.name does not require quotes.

    You appear to be trying to match two fields.  The 'N_HostName' field and the 'Name' field.  Do you want a "match" or do you want "like".

    To use "like" you need a wildcard.

    It also appears that you do not really have a CSV.  It is just a file called a CSV.  Post ther first two or three lines of your CSV.


    ¯\_(ツ)_/¯

    Monday, January 5, 2015 5:17 PM
  • yes, I have redacted things, and obscured other things because I can not go around posting critical infrastructure information out on the internet.

    Here is the first three lines of my .csv file

    "OrigIP","AL_HostName","AL_Found","AL_Enabled","AL_Status","N_HostName","InREDACTED","N_Found","Delta","IsStale","Ping","InDNS","InAD","Location","Alias","IsServer","HostType","OS","ApplianceName","FQDN","ChatterValue"
    "10.24.11.4","ABCD","yes","yes","never","abcd.domain.com","yes","yes","*","*","Y","Y","N","TEST","*","*","eventlog","","","ABCD.DOMAIN.COM","*"
    "10.24.12.18","EFGH","yes","yes","Dec 30 2014 09:15:00","efgh.domain.com","yes","yes","-25","No","Y","Y","Y","TEST","*","yes","eventlog","xxxxxx","","EFGH.DOMAIN.COM","*"

    When I import this file I create a new custom object (objectCurrent) which I populate with the data from the csv file. I then store this object into an array of objects (objectCollection).

    All of the data is present.

    I then read in a new csv file that would contain most of the same hosts, but possibly additional new ones. upon importing the second csv file I loop through the entries.

     I have a conditional statement that checks to see if the host name from the second csv file, if it isn't then treat it like a new object and go fill in all of the details of the object using my various functions, etc.

     

    Import-CSV$currentALReport-Delimiter","|ForEach-Object {

         if($objectCollection.N_HostName -notcontains$_.'name') {

            # then create a new currentObject and go populate the properties of the object 

         }

         elseif ($objectCollection.N_HostName -contains $_.'name') {

              # copy this object and update the object's AL_Status (which is the last reported message date info)

                  # send that to the function that will parse it, compare Julian dates and see if it falls within my

                  # criteria as being stale.  if so set the IsStale property to Yes, but reguardless set the AL_Status

                  # newest last reported message data

    JRV states that "The "select object" does nothing at all unless you have a column in your CSV called "object".  The where clause will do nothing because it is syntatctically wrong and illogical. "

    I beg to differ.  Using the above command :   with the script running and the current focus ($_.'name') equals "abcd.domain.com"

     $arrayOfObjects | select-object | where N_HostName -like $_.'name'

    It obtain a single object within my array of objects similar to this:

    IP: 1.2.3.4

    N_HostName: abcd.domain.com

    IsStale: No

    LastMsgDate: Dec 30 2014 09:15:00

    Delta: 1

    Ping: Yes

    InDNS: Yes

    InAD: Yes

    Alias: *

    (other fields omitted for brevity) I could get any of my existing objects if I match the hostname

    -----------------------

    If I used only the command "  $objectCollection | Select-Object "    it returns every object in my array.

    So to narrow down the selection to a single object I add the " | where N_HostName -like $_.'name'  "

    which gives me the exact object I am searching for.

    My only question is how can I modify the contents of the object that I have specified within the array of object???

    Monday, January 5, 2015 9:47 PM
  • JRV,

    Here is the running output of my command as written. It works. $_.name may not require quotes but it DOES work with them.

    > $objectCollection | select-object | where AL_HostName -like $_.'name'
    OrigIP        : 1.2.3.4
    AL_HostName   : abcd-ccc
    AL_Found      : yes
    AL_Enabled    : yes
    AL_Status     : Dec 30 2014 09:15:00
    N_HostName    : abcd-ccc.domain.com
    N_Found       : yes
    Delta         : 25
    IsStale       : No
    Ping          : Y
    InDNS         : Y
    InAD          : Y
    Location      : TEST
    Alias         : *
    IsServer      : yes
    HostType      : eventlog
    OS            : XXXX Server
    ApplianceName :
    FQDN          : ABCD-CCC.DOMAIN.COM
    ChatterValue  : *

    I have tried it without the select-object and I get the same output, so I will cede the point and remove it from future usage.

    See my earlier post containing the 1st 3 lines of my csv file. It is a csv file unless powershell's convertTo-CSV doesn't really create one because that is where it came from after running my script originally.

    # print out contents of objectCollection for future reports
    $objectCollection | Sort-Object -property OrigIP `
                             | Select-Object -property OrigIP, AL_HostName, AL_Found, AL_Enabled, AL_Status, `
                               N_HostName, XXXX, N_Found, Delta, IsStale, Ping, InDNS, InAD, Location, Alias, `
                               IsServer, HostType, OS, ApplianceName, HostType, FQDN, ChatterValue  `
                             | ConvertTo-CSV | Out-File -Append $reportOutputCSVFile


    • Edited by Dontron98 Monday, January 5, 2015 10:08 PM
    Monday, January 5, 2015 10:03 PM
  • You need some practice posting examples.  THere are code and data posting methods in forums that allow the post to be readable.  What yuo have posted is just a jumble wit fancy colors.

    Well - th efile looks like a CSV file.

    Why do you keep insisting that you are create custom objecys.  You are importing a CSV file.  A CSV file issrepresented as an array of objecys after it is imported.  We still refer to it as a CSV.

    Here is how to post code:

    Import-CSV$currentALReport-Delimiter","|
         ForEach-Object{
             if($objectCollection.N_HostName -notcontains $_.'name'){
            # then create a new currentObject and go populate the properties of the object 
         }elseif($objectCollection.N_HostName -contains $_.'name'){
    
    

    Of couse most of the code is missing or impossible to read.  You need to post correct code that illustrates you issue so we can try to understand what you are trying to ask.


    ¯\_(ツ)_/¯

    Monday, January 5, 2015 10:07 PM
  • Note that there is no field $_.Name  it does not exist in teh CSV or in code.


    ¯\_(ツ)_/¯

    Monday, January 5, 2015 10:08 PM
  • JRV,

    Here is the running output of my command as written. It works. $_.name may not require quotes but it DOES work with them.

    > $objectCollection | select-object | where AL_HostName -like $_.'name'
    OrigIP        : 1.2.3.4
    AL_HostName   : abcd-ccc
    AL_Found      : yes
    AL_Enabled    : yes
    AL_Status     : Dec 30 2014 09:15:00
    N_HostName    : abcd-ccc.domain.com
    N_Found       : yes
    Delta         : 25
    IsStale       : No
    Ping          : Y
    InDNS         : Y
    InAD          : Y
    Location      : TEST
    Alias         : *
    IsServer      : yes
    HostType      : eventlog
    OS            : XXXX Server
    ApplianceName :
    FQDN          : ABCD-CCC.DOMAIN.COM
    ChatterValue  : *

    I have tried it without the select-object and I get the same output, so I will cede the point and remove it from future usage.

    See my earlier post containing the 1st 3 lines of my csv file. It is a csv file unless powershell's convertTo-CSV doesn't really create one because that is where it came from after running my script originally.

    # print out contents of objectCollection for future reports
    $objectCollection | Sort-Object -property OrigIP `
                             | Select-Object -property OrigIP, AL_HostName, AL_Found, AL_Enabled, AL_Status, `
                               N_HostName, XXXX, N_Found, Delta, IsStale, Ping, InDNS, InAD, Location, Alias, `
                               IsServer, HostType, OS, ApplianceName, HostType, FQDN, ChatterValue  `
                             | ConvertTo-CSV | Out-File -Append $reportOutputCSVFile


    I am sorry but you really need to take some timme to learn how to correctly use PowerShelol.  A\What you have mmuddled through barely works but is very much unnecessary.

    Here is the corerct way to create a CSV file that is much easier and clener:

    $objectCollection | 
      Sort-Object -property OrigIP | 
      Export-Csv  $reportOutputCSVFile -NoTypeInformation

    To filter a collction we would do this:

    $objectCollection | 
        Where-Object( $_.AL_HostName -like '*somename*'}
    

    All of your examples of this are missing key information or are just blatently wrong.

    Please take the time to try to understand how these things work and post back with a clear question.  With what you have posted it is not possible to help you.


    ¯\_(ツ)_/¯

    Monday, January 5, 2015 10:20 PM
  • As jrv pointed out, the select-object you're inserting isn't doing anything and is superfluous. You're not selecting any properties, so just leave it out. All it does is add confusion.

    If I understand, what you are wanting to do is find specific column values in your CSV data and output replacement values for those specific values.

    One way to do this is to check for the values you want and output new objects only for the changed values. Here is a short proof of concept:


    # Create some sample data
    $myTable = `
      (new-object PSObject -property ([Ordered] @{
        "Column1" = "Row1Column1"
        "Column2" = "Row1Column2"
        "Column3" = "Row1Column3"
      })),
      (new-object PSObject -property ([Ordered] @{
        "Column1" = "Row2Column1"
        "Column2" = "Row2Column2"
        "Column3" = "Row2Column3"
      })),
      (new-object PSObject -property ([Ordered] @{
        "Column1" = "Row3Column1"
        "Column2" = "Row3Column2"
        "Column3" = "Row3Column3"
      }))
    
    # For each row in the data, replace some values
    $myTable | foreach-object {
      if ( $_.Column1 -like "Row2*" ) {
        new-object PSObject -property ([Ordered] @{
          "Column1" = "Row 2 Column 1"
          "Column2" = "Row 2 Column 2"
          "Column3" = "Row 2 Column 3"
        })
      }
      else {
        $_
      }
    }
    

    This short example outputs a replacement row for the second row of data in the table.

    (Note that this example uses the [Ordered] attribute, so it only works on PowerShell v3 or later.)


    -- Bill Stewart [Bill_Stewart]

    Monday, January 5, 2015 10:20 PM
    Moderator
  • I like Bill's solution, but it should also be possible for you to change the actual objects themselves instead of creating new ones. 

    I've done what SteveLarson-W mentioned above in the past, so I'm not sure why that's not working for you. If you take Bill's sample data above ($myTable), you should be able to walk through the following examples to directly change the objects' properties:

    # Look at the original data
    $myTable
    
    # Make a change using SteveLarson-W's method:
    $myTable | where Column1 -like "Row1*" | foreach { $_.Column2 = "Direct assignment" }
    
    # Look at updated data
    $myTable
    
    # Use Add-Member to overwrite property:
    $myTable | where Column1 -like "Row2*" | foreach { $_ | Add-Member -MemberType NoteProperty -Name Column2 -Value "Add-Member" -Force }
    
    # Look at updated data
    $myTable
    
    # Use PSv3+ Add-Member parameters:
    $myTable | where Column1 -like "Row3*" | foreach { $_ | Add-Member -NotePropertyName Column2 -NotePropertyValue "Add-Member PSv3+" -Force }
    
    # Look at updated data
    $myTable

    The final output should look like this:
    Column1      Column2            Column3    
    -------      -------            -------    
    Row1Column1  Direct assignment  Row1Column3
    Row2Column1  Add-Member         Row2Column3
    Row3Column1  Add-Member PSv3+   Row3Column3

    Does that help any?



    Tuesday, January 6, 2015 1:49 AM
  • 1. If I knew everything about Powershell I wouldn't be on this site asking questions.

    2. Obviously there is something wrong in the way I am doing it or I wouldn't be asking questions.

    3. I am new to Powershell but I seem to get by for the most part. 

    4. From my observations, Powershell has been written by many different people and thus the reason there are several different ways of doing something.  Take the split cmdlet for example, there are different ways of using it and you have to play around with it in order to find the right one.

    5. When I don't know how to accomplish a task I need to do, I search the internet. Some people post something similar and I extrapolate on their code and make it suit my needs.

    6. Several times you have told me something doesn't work and I have shown that it does. It may not be pretty. It most definitely is different, and when you are right about something and I can do away with it (such as the select-object I follow suit).  But when you complain about export-csv  when I was using convertTo-csv, then you say tomato and I say Toe-mato. Two different cmdlets to get the same results. Is yours cleaner? yep, but that wasn't the cmdlet that was taught to me in the MS Powershell Class I took. So I used the cmdlet I knew. But to say it isn't proper, well....Sorry your highness.

    7. If you are as knowledgeable as your claim to be, and if your ways are the best ever possible then I suggest you right a book and make a mint off of your knowledge. That will stroke your ego.

    8. YOU HAVE A HUGE EGO, AND A VERY CONDESCENDING ATTITUDE. I'VE SEEN IT NOW IN SEVERAL DIFFERNT POSTS. SO AS FAR AS I AM CONCERNED YOU CAN SAVE YOURSELF AND ME A LOT OF ANGUISH AND JUST IGNORE MY POSTS.

    9. I don't have time for flame wars. So bugger off.

    Tuesday, January 6, 2015 4:04 PM
  • Rohn's idea works too, if the memory requirements aren't too onerous.

    -- Bill Stewart [Bill_Stewart]

    Tuesday, January 6, 2015 4:05 PM
    Moderator
  • Thanks Rohn,

    I will give it a whirl and see if I can get it to work. I've been tied up with a different project but I will definitely try your advise.

    I do appreciate it.


    • Edited by Dontron98 Tuesday, January 6, 2015 4:11 PM
    Tuesday, January 6, 2015 4:11 PM
    1. If I knew everything about Powershell I wouldn't be on this site asking questions.

    Your questions are very hard to decode because you know too little about the fundamentals of PowerShell.  You seem to have invented your own language and definition which none of us can easily decode.

    1. Obviously there is something wrong in the way I am doing it or I wouldn't be asking questions.

     We understand that and are asking for simple and consistent clarification.  You have posted numerous inconsistent copies of a script.

    1. I am new to PowerShell but I seem to get by for the most part. 

    ???

    1. From my observations, Powershell has been written by many different people and thus the reason there are several different ways of doing something.  Take the split cmdlet for example, there are different ways of using it and you have to play around with it in order to find the right one.

    All software in the modern world is designed by teams if engineers.  PowerShell is representative of most modern software.  It only appears confusing because you do not have the correct fundamental definitions.

    1. When I don't know how to accomplish a task I need to do, I search the internet. Some people post something similar and I extrapolate on their code and make it suit my needs.

    This is one big flaw in learning only from the Internet.  New users tend to choose poor or incorrect examples to learn from.

    1. Several times you have told me something doesn't work and I have shown that it does. It may not be pretty. It most definitely is different, and when you are right about something and I can do away with it (such as the select-object I follow suit).  But when you complain about export-csv  when I was using convertTo-csv, then you say tomato and I say Toe-mato. Two different cmdlets to get the same results. Is yours cleaner? yep, but that wasn't the cmdlet that was taught to me in the MS Powershell Class I took. So I used the cmdlet I knew. But to say it isn't proper, well....Sorry your highness.

    You insist on arguing with everyone’s examples.  If you would listen and research the suggestions you would learn some good fundamentals

    1. If you are as knowledgeable as your claim to be, and if your ways are the best ever possible then I suggest you right a book and make a mint off of your knowledge. That will stroke your ego.

    Sorry – I cannot “right” your book.  Many people write books that are useful to you.  I recommend reading at leat one of them.

    1. YOU HAVE A HUGE EGO, AND A VERY CONDESCENDING ATTITUDE. I'VE SEEN IT NOW IN SEVERAL DIFFERNT POSTS. SO AS FAR AS I AM CONCERNED YOU CAN SAVE YOURSELF AND ME A LOT OF ANGUISH AND JUST IGNORE MY POSTS.

    I cannot affect a stubborn and fairly poorly trained wannabe technician.  I can only give examples, links and suggestions.  You have to be the one to take the steps to understand what is being shown or taught.

    1. I don't have time for flame wars. So bugger off.

    Nastiness is not going to help you learn what you do not understand.  Bill and others have pointed out the same issues as I have.  You have not listed and still cannot see how to do what you ask.  It is you who are wasting your own time by being so defiensve about what you obviously don’t know.


    ¯\_(ツ)_/¯

    Tuesday, January 6, 2015 4:26 PM
  • It is my opinion that the OP has comehere with the idea of posting nonsensse and using it to pick a fight.

    I see no attempt on the OP's part to try anyones suggestions.  I recommend miving tthis thread to the "off topic" forum.


    ¯\_(ツ)_/¯

    Tuesday, January 6, 2015 4:28 PM
  • This is the ticket!!!!

    $myTable | where Column1 -like "Row3*" | foreach { $_ | Add-Member -NotePropertyName Column2 -NotePropertyValue "Add-Member PSv3+" -Force }

    This is exactly what I needed. Thank you very much.

    Tuesday, January 6, 2015 4:46 PM