0

I have had this issue a long time, whenever I presume that it's going to output all data it does not.

Example:

$groups = "group1","Group2","Group3" # to be excluded
foreach ($group in $groups) {
    $dns = (Get-ADGroup "$Group").DistinguishedName
}
Write-Host $dns

will output only one group's distinguished name, but if at the same time I output

(Get-ADGroup "$Group").DistinguishedName | Out-File c:\list.txt

I will get all 3. The same goes with `Get-ADUser, if I try to get user from an array.

Any real solution anyone has come accross?

2 Answers 2

2

PowerShell doesn't magically create an array just because you will it. Since $dns isn't an array from the start your code is replacing its value with every iteration, so you end up with just the last value after the loop terminates.

You have 2 ways of fixing this issue:

  • Define $dns as an array before the loop, and append to that array inside the loop.

    $dns = @()
    foreach ($group in $groups) {
        $dns += (Get-ADGroup "$Group").DistinguishedName
    }
    

    Although virtually everyone seems to be doing it this way, the approach is NOT RECOMMENDED for performance reasons. Appending to an array is expensive, because it essentially creates a new array with increased size, moves all existing elements and puts the new element in the new free slot, then replaces the original array.

  • Output the results inside the loop and collect the entire loop output in a variable.

    $dns = foreach ($group in $groups) {
        (Get-ADGroup "$Group").DistinguishedName
    }
    

    This approach has significantly better performance than appending inside a loop. However, it's worth noting, that if the loop produces zero or one elements, the result will be either $null or a simple value, not an array. You can force it to an array by putting the loop in the array construction operator, though:

    $dns = @(foreach ($group in $groups) {
        (Get-ADGroup "$Group").DistinguishedName
    })
    

Addendum: As @Clijsters mentioned in the comments there's actually a third way to approach this issue, using a .Net collection instead of basic PowerShell arrays:

$dns = New-Object System.Collections.ArrayList
foreach ($group in $groups) {
    $dns.Add((Get-ADGroup "$Group").DistinguishedName) | Out-Null
}

Appending to a collection is far less expensive than appending to a PowerShell array. However, there's some overhead to instantiating the collection. You'll get the best performance by simply collecting loop output in a variable ($dns = foreach (...) {...}).

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks ansgar actually im doing this exporting all users from a group but excluding certain who are member of another 3 groups I wll test. $groups="group1","Group2","Group3" # to be excluded ForeacH($group in $groups){ $dns=(Get-ADGroup "$Group").DistinguishedName } Foreach($dn In $dns){ get-ADGroupMember -Identity "GroupA" |get-aduser -prop memberof |where{$_.memberof -notcontains $dn}|select name }
Wouldn't it be worth it to mention ArrayLists and their Add method?
@Clijsters Collections have their own disadvantages, because their initial creation tends to be expensive. Collecting the loop output in a variable is actually the fastest way of doing this kind of thing, at least as far as I'm aware.
@DhruvSaxena Please do not move the target. If you have a new or followup question: post a new question.
@AnsgarWiechers Didn't you mentioned array appending, which is on it's own (as stated out in your answer) quite inperformant? Would be interesting to compare them and to have an idea at which item size it is worth to consider...
|
1

The problem is your Write-Host is outside of your loop!

$groups = "Group1", "Group2", "Group3"
foreach ($group in $groups) {
    $dns = (Get-ADGroup $group).DistinguishedName
    Write-Host $dns # <--- it's inside, now!
}

This will write the value out for each group, not just the last one.

1 Comment

While this is correct it doesn't really target the core f the question which points to $dns only having one value, not an array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.