ForEach and multidemensional array issue

With the help of this forum and google I have finally got my head around the basics of multidemensional arrays and then I went to use a basic ForEach that I have used many time and it did not work and I am at a loss to know why, below is a sample of the code, any help with troubleshooting multidemensional arrays and ForEach would be greatly appreciated. All I get is Unmatched results. (The actual arrays that I am using have many more fields than the below example but the code is the same)

 

[pre]

$matched = @()

$unmatched = @()

Foreach ($data in $first)
{
If ($data.login -eq $second)
{
write-host $data.login " Matched" -ForegroundColor Green
$matched += $data
}
Else
{
write-host $data.login " Unmatched" -ForegroundColor Red
$unmatched += $data
}
}

[/pre]

The arrays look like this

$first

name = Fred

surname = White

login = fred.white

name = Lisa

surname = Smith

login = lisa.smith

$second

name = Fred

surname = White

login = fred.white

name = Kylie

surname = Brown

login = kylie.brown

 

P.S

Sorry for missing the to display the code correctly

Is that really two object arrays? Wouldn’t that be:

for ($data1 in $first) {
  for ($data2 in $second) {
    If ($data1.login -eq $data2.login) { 'yes' }
  }
}

[quote quote=143822]P.S

Sorry for missing the to display the code correctly[/quote]
You can go back and edit your initial post again and correct the formatting. You just have to select the code an click on the “pre” tag button. :wink:

Those aren’t arrays though. They are just a list of strings, maybe the output you were expecting???

Anyway, this is an array…

$myArray = 64,"Hello",3.5,"World"

Or this…

$usa_states=@{ CA="California";
  "NY" = "New York";
  "IL" = "Illinois";
  "NH" = "New Hampshire"
}

Array keys (left side of the equal sign ), in a literal hash, must be unique, and yours are not. Notice you have repeated name, surname and login keys, in these hash literals.

$first = @{'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white';
'name' = 'Lisa';
'surname' = 'Smith';
'login' = 'lisa.smith'
}

$second = @{'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white';
'name' = 'Kylie';
'surname' = 'Brown';
'login' = 'kylie.brown'
}

If you paste the above in to the PowerShell ISE or VSCode, they will immediately show errors. Those dreaded red squiggles. Hover over those squiggles, to see the error description.

I get you are trying to do this for multiple users, but… Take a read of these write ups, if you have not already.

Powershell: Everything you wanted to know about arrays
Multidimensional arrays in Powershell

So, taking out the duplicates -

$first = @{'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white'
}

$second = @{'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white'
}

Once getting thru those, the thought becomes:

Multi-dimensional array - Basic strings

# Multi-dimensional array
($Marshmallows = @(("Pink","Yellow","Orange","Green","Blue"),("Hearts","Stars","Moons","Clovers","Diamonds")))

# Results

Pink
Yellow
Orange
Green
Blue
Hearts
Stars
Moons
Clovers
Diamonds


$Marshmallows[0][1]

Yellow

$Marshmallows[0][2]

Yellow

$Marshmallows[1][3]

Clovers

$Marshmallows[1][4]

Diamonds

Or properly constructing your Multi-dimensional arrays becomes this…

($first = (@{'name' = 'Fred';'surname' = 'White';'login' = 'fred.white'}),
(@{'name' = 'Lisa';'surname' = 'Smith';'login' = 'lisa.smith'}))

# Resutls

Name                           Value
----                           -----
name                           Fred
login                          fred.white
surname                        White
name                           Lisa
login                          lisa.smith
surname                        Smith

$first[0]

Name                           Value
----                           -----
name                           Fred
login                          fred.white
surname                        White


($second = (@{'name' = 'Fred';'surname' = 'White';'login' = 'fred.white'}),
(@{'name' = 'Kylie';'surname' = 'Brown';'login' = 'kylie.brown'}))

# Results

Name                           Value
----                           -----
name                           Fred
login                          fred.white
surname                        White
name                           Kylie
login                          kylie.brown
surname                        Brown

$second[1]

Name                           Value
----                           -----
name                           Kylie
login                          kylie.brown
surname                        Brown

Putting it together with, it this what you are after.

Clear-Host 

$first = (@{
'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white'}
),
(@{'name' = 'Lisa';
'surname' = 'Smith';
'login' = 'lisa.smith'}
)



$second = (@{
'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white'}
),
(@{
'name' = 'Kylie';
'surname' = 'Brown';
'login' = 'kylie.brown'}
)


$matched = @()
$unmatched = @()

Foreach ($data1 in $first)
{
    Write-Host "Validating $($data1.login) in compared array" -ForegroundColor Yellow
    If ($second.login -contains $data1.login)
    {
        Write-Host "Match found in compared array for $($data1.login)`n" -ForegroundColor Green
    }
    Else
    { Write-Warning -Message "No match found in compared array for $($data1.login)"}
}

# Results

Validating fred.white in compared array
Match found in compared array for fred.white

Validating lisa.smith in compared array
WARNING: No match found in compared array for lisa.smith

Thanks js for your suggestion I get an error with yours, was the “for” suppose to be “foreach”??

Thanks Olaf for the edit tip, I change the original post.

Thanks postanote for your help, I made a mistake with the way I displayed the arrays I should have used “:” instead of “=”. Below is what they would look like if I displayed them in powershell. Would this may them multidemensional array or are they something else??

Any help to work this out is greatly appreciated.

 

[pre]

$first

name login surname


Fred fred.white White

Lisa lisa.smith Smith

 

 

$first | format-list

name : Fred
login : fred.white
surname : White

name : Lisa
login : lisa.smith
surname : Smith

[/pre]

As for this…

I get an error with yours, was the "for" suppose to be "foreach"??

… I am not sure which section you are addressing here as I only have one code block using a loop. The last one and as constructed, it does not error. As note by the results from actually running the code. So, are you saying you use my ForLoop block, but not the array sample I have there as that would be the only way that would fail. Because what you are seeing is the actual code run and the results unchanged / copied and pasted from my system.

As for this…

$first

name login surname
—- —– ——-
Fred fred.white White

Lisa lisa.smith Smith

$first | format-list

name : Fred
login : fred.white
surname : White

name : Lisa
login : lisa.smith
surname : Smith

… that is not a multi-dimensional array,

This …

$first

name login surname
—- —– ——-
Fred fred.white White

Lisa lisa.smith Smith

… is a csv / table, that you converted to a list when you did this…

$first | format-list

With a multi-dimensional array, it does that by default. Notice, no format commands needed.

$first = (@{
'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white'}
),
(@{'name' = 'Lisa';
'surname' = 'Smith';
'login' = 'lisa.smith'}
)
$first

Name                           Value
----                           -----
name                           Fred
login                          fred.white
surname                        White
name                           Lisa
login                          lisa.smith
surname                        Smith



 $second = (@{
'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white'}
),
(@{
'name' = 'Kylie';
'surname' = 'Brown';
'login' = 'kylie.brown'}
)
$second

Name                           Value
----                           -----
name                           Fred 
login                          fred.white
surname                        White
name                           Kylie
login                          kylie.brown
surname                        Brown

Even if one tries to for a table format, it will not happen, because it already is.

$first = (@{
'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white'}
),
(@{'name' = 'Lisa';
'surname' = 'Smith';
'login' = 'lisa.smith'}
)
$first | Format-Table -AutoSize

Name    Value     
----    -----     
name    Fred      
login   fred.white
surname White     
name    Lisa      
login   lisa.smith
surname Smith  


 $second = (@{
'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white'}
),
(@{
'name' = 'Kylie';
'surname' = 'Brown';
'login' = 'kylie.brown'}
)
$second | Format-Table -AutoSize

Name    Value      
----    -----      
name    Fred       
login   fred.white 
surname White      
name    Kylie      
login   kylie.brown
surname Brown      

Formatting is as a list change the layout, it will convert to a property value list.

$first = (@{
'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white'}
),
(@{'name' = 'Lisa';
'surname' = 'Smith';
'login' = 'lisa.smith'}
)
$first | Format-List


Name  : name
Value : Fred

Name  : login
Value : fred.white

Name  : surname
Value : White

Name  : name
Value : Lisa

Name  : login
Value : lisa.smith

Name  : surname
Value : Smith




  $second = (@{
'name' = 'Fred';
'surname' = 'White';
'login' = 'fred.white'}
),
(@{
'name' = 'Kylie';
'surname' = 'Brown';
'login' = 'kylie.brown'}
)
$second | Format-List


Name  : name
Value : Fred

Name  : login
Value : fred.white

Name  : surname
Value : White

Name  : name
Value : Kylie

Name  : login
Value : kylie.brown

Name  : surname
Value : Brown

The display / code block you recently posted, tells what you are using in the construct of your multi-dimensional array is not valid.

So, are you reading the values in from a text file, or have you hard coded them in your code. Either way, the construct must be valid as per the links and samples I included earlier.

Right now, you are posting the results of is already stored in your variables, not how you constructed that content that you are sending in to those variables. That is where the error is.

Doing any formatting to display that data is a completely separate thing.

Thanks postanote the code that did not work was not yours but “js”, I think the part that has been confusing me is when I manipulate the data it changes it from one type of array to another so I think it may help to take a step back and try to clarify the different types of arrays that I use (some may even be just hash table)

What type is it when

  1. I import a csv with headings (are these always tables)
  2. import data from Active Directory
  3. Separate data using eg:
[pre]

for($i=0; $i -lt $data.length; $i++)
{$compare += New-Object psobject -Property @{‘first name’ = $data[$i].‘first name’; ‘last name’ = $data[$i].‘last Name’; ‘login’ = $data[$i].login}}

[/pre]

If there are any other common variations please let me know

Thanks again for the help.

 

Just store the data in a variable and check what type it is.

E.g.
[pre]
$users = Get-ADUser -Filter “Name -like ‘A*’”
$users.GetType()
[/pre]

The above will grab all the users starting with the letter A in their Name attribute.
GetType() will show you the BaseType e.g. System.Array.

Thanks Fredrik for the suggestion, I tried it on a couple of the arrays that my script uses and only got 2 types which was object system.array and PSCustomOgbject system.object. (false for IsSerial).

 

Thanks everyone for the information it has helped me get a bit more of an understanding (still a long way to go)

The solution that I ended up to fix my foreach problem is below. I figured out that if I dumped the column that I wanted to compare into a variable and used it as the first item to compare it to then using the -like I could compare the second value against the whole of the first one instead of feeding each a line at a time using a double foreach.

[pre]

$matched = @()
$unmatched = @()
$a = $students.faxu

foreach ($data in $Eggs)
{
If ($a -ilike $data.login)
{
$data.Login
write-host $data.login " Matched" -ForegroundColor Green
$matched += $data
}
Else
{
$data.Login
write-host $data.Login " Unmatched" -ForegroundColor Red
$unmatched += $data
}
}

[/pre]