Array of Objects

Welcome Forums General PowerShell Q&A Array of Objects

This topic contains 6 replies, has 5 voices, and was last updated by

 
Participant
6 months, 2 weeks ago.

  • Author
    Posts
  • #101767

    Participant
    Points: 1
    Rank: Member

    Hi,

    I'm trying to create an array of custom objects. The custom object is very simple and has only two properties. I start by reading a text file that has many iterations of:

    [SiteName1]
    UID="blah1"
    [SiteName2]
    UID="blah2"
    [SiteName3]
    UID="blah3"

    After the script runs, the $AllSites variable is filled with three objects all with the [SiteName3] and UID="blah3" data. It seems that the objects is being referenced rather than adding three new objects. Could somebody help me get all three values?

    B

    $AllSites = @();
    
    $file = Get-Content -Path some_file_name.txt
    
    $site = New-Object -TypeName PSObject -Property @{
        Sitename = "";
        UID = "";
    }
    
    foreach ($line in $file) {
        if ($line -like "``[*") {
            $site.Sitename = $line;
        }
        if ($line -like "UID=`"*") {
            $site.UID = $line.Replace("UID=`"", "UID=`"tst");
        }
        
        $AllSites += $site;
    }
    
  • #101784

    Participant
    Points: 17
    Rank: Member

    Someone more knowledgeable may be able to explain why exactly that is happening to you, I believe it is because you are pulling from alternating lines of text and using += to add to your $AllSites variable. A quick way to try and see what is happening inside your variable is to add a Write-Host command to view it at each iteration.

     $AllSites += $site;
     Write-Host $AllSites
    

    Also, I don't believe you need to define $AllSites as an array at the start of your script because it gets overwritten as a PSCustomObject anyway when you do $allSites += $site

    Anyway, you can try the below which I believe provides the output you are looking for, as a PSCustomObject. There may be a better way but here is what I came up with

    I used ReadCount2 to pull 2 lines at a time and combine them to a single string with a ";" delimiter
    Then you can do your text replacement
    Then convert it into an object

    $file = Get-Content file.txt -ReadCount 2 | foreach {$_ -join ";"}
    $file = $file | foreach {$_ -replace  "UID=`"","UID=`"tst"}
    $obj = $file | ConvertFrom-String -Delimiter ";" -PropertyNames SiteName,UID
    Write-Output $obj
  • #101803

    Participant
    Points: 190
    Helping Hand
    Rank: Participant

    You probably want to do something like this instead.
    So that you create a new object on every iteration and adding that to the array.
    Not changing/replacing the same object and adding that three times.

    $AllSites = @();
    
    $file = Get-Content -Path some_file_name.txt
    
    foreach ($line in $file) {
        if ($line -like "``[*") {
            $Sitename = $line;
        }
        if ($line -like "UID=`"*") {
            $UID = $line.Replace("UID=`"", "UID=`"tst");
        }
    
        $properties = @{Sitename = $Sitename;
                        UID=$UID
                       }
        
        $AllSites += New-Object -TypeName PSObject -Property $properties
    }
    
  • #101809

    Participant
    Points: 1
    Rank: Member

    Thanks to both of you. I'll be at work in 1.5 hours and will let you know.

  • #101813

    Participant
    Points: 90
    Rank: Member
    
    [CmdletBinding()] 
    Param([Parameter(Mandatory=$false)][String]$FilePath = 'E:\Scripts\input1.txt')
    
    
    Remove-Variable Header,UID -EA 0
    
    
    $SiteList = foreach ($Line in (Get-Content $FilePath)) {
    
    
        # Parse lines
        if ($Line -match '\[' -and $Line -match '\]') {
            [String]$Header = $Line.Replace('[','').Replace(']','')
            Remove-Variable UID -EA 0 # Once a header is identified, we're interested in the next UID, removing any left over prior UID
            Write-Verbose "Identified header '$Header'"
        } elseif ($Line -match 'UID') {
            [String]$UID = $Line.Replace('UID=','').Replace('"','')
            Write-Verbose "Identified UID '$UID'"
        } else { # This if branch is to catch lines that are not caught in the first 2 branches
            Write-Verbose "Uhm, found a line '$Line' that does not match header definition (missing []) or contains 'UID', skipping.."
        }
    
    
        # Identify object pair
        if ($Header -and $UID) { 
            [PSCustomObject][Ordered]@{
                SiteName = $Header
                UID      = $UID 
            }
            Write-Verbose "Identified site 'SiteName=$Header, UID=$UID'"
            Remove-Variable Header,UID -EA 0
        }
    
    
    }
    
    $SiteList | FT -a 
    
  • #101815

    Participant
    Points: 325
    Helping Hand
    Rank: Contributor

    First, the code you posted is using the object as a reference, as you guessed. A new object isn't being generated, you are just setting the properties of the referenced object. You could copy the object, but the method below is the best method I've found to generate objects.

    Second, you don't need += to build objects. Create an object and just assign a variable to the for loop to capture the output.

    Last, it's difficult to help you parse without some example of the file you are attempting to parse. It appears from your code that different properties exist on separate lines, so you need set a variable but not generate an object during loop 1 and during loop 2 use the variable from loop 1 to generate the object during loop2. This is where you get into more advanced parsing.

    #Emulate what we guess the file looks like
    $sites = @"
    [Site1]
    UID = 89679fbd-d7f0-4408-bb60-5f127effe533
    [Site2]
    UID = 2ea7129e-646d-4938-b956-767583df0746
    [Site3]
    UID = 2ea7129e-646d-4938-b956-767583df0746
    "@
    
    #Set the $results variable for your loop
    $results = foreach ($line in ($sites.split([System.Environment]::NewLine))) {
        switch -WildCard ($line) {
            "[[]*" { 
                #No object, just a variable for lines starting with [
                $site = $line.Replace("[","").Replace("]","")
            }
            "UID*" {
                #This will be loop 2, line start with UID, so we generate an object
                #assuming that the next line we care about is [SiteX]
                New-Object -TypeName PSObject -Property @{
                    Site = $site
                    UID = $line.Replace("UID = ","")
                }
            }
        }
    }
    
    #Our final object
    $results
    

    Output:

    Site  UID                                 
    ----  ---                                 
    Site1 89679fbd-d7f0-4408-bb60-5f127effe533
    Site2 2ea7129e-646d-4938-b956-767583df0746
    Site3 2ea7129e-646d-4938-b956-767583df0746
    
  • #101822

    Participant
    Points: 1
    Rank: Member

    Wow, so many ways to do the same thing. Thanks everybody for responding. You've all been helpful. I've tested the various samples scripts and will use what makes sense for us.

    Thanks again and happy shelling.

The topic ‘Array of Objects’ is closed to new replies.