Author Posts

June 4, 2018 at 11:51 pm

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;
}

June 5, 2018 at 7:00 am

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

June 5, 2018 at 12:14 pm

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
}

June 5, 2018 at 1:24 pm

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

June 5, 2018 at 1:52 pm


[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 

June 5, 2018 at 2:01 pm

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

June 5, 2018 at 3:51 pm

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.