Pipeline behavior in a foreach loop

Can someone help me understand why the following works fine outside of a foreach loop, but not within?

Get-ADGroupMember -Identity $Group | Remove-ADPrincipalGroupMembership -MemberOf $Group -Confirm:$false

My goal is to drop all members of a few groups in bulk so that I can pull new information from an external database and then repopulate the groups with the updated info.

PowerShell is specifically throwing an error on at Remove-ADPrincipleGroupMembership, with an error message of:

Object reference not set to an instance of an object.

Here is the code I’m using for the loop:

foreach ($Group in $AD_Groups) {

    Get-ADGroupMember -Identity $Group | Remove-ADPrincipalGroupMembership -MemberOf $Group -Confirm:$false        

}
Get-AdGroupMember -Identity <ADGroup>

The identity parameter takes a scalar (single) value not a collection. I would bet in

$group is a collection of groups (array) and not a single item which would cause an error.
the ForEach-Object will take your collection (array) $AD_Groups and process them one at a time.

In the first example it is a single group. In the loop, I’m using two groups for now. Even with your response, I’m struggling to understand why it would behave differently. In my mind, it should process each group one at a time, effectively doing the same thing as it does outside of the loop, it just occurs twice.

Without the loop, where are you assigning the variable $group

Globally, but I have both examples inside of a function.

In your loop you are using $AD_Groups. Is that assigned the same way as $group? Also, inside the loop $group is NOT the same variable as $group outside of it. The foreach loop assigns it to the current item each iteration.

To troubleshoot, you may want to either debug and step through or put some statements to write out the variable values. i.e.

Write-Host ("The value of groups inside the function is {0}" -f $groups.ToString())

Yep, I’ve been using the debugger in VS Code to walk through it. What it seems like to me is that the object that’s created with Get-ADGroupMember -Identity $Group is not being passed over the pipeline to Remove-ADPrincipalGroupMembership .... pserror

$Group DOES contain one of the string’s from $AD_Groups in each interation of the loop in the debugger, which is why I think it’s actually some weird pipeline behavior that is occurring within the loop.

When you debug does every iteration of the loop give you the error or just some? On an iteration that gives you the error, when in debug mode, run just the

Get-ADGroupMember -Identity $Group

and see what it returns.

1 Like

It’s dumping the contents of the groups to the console properly that way.

OK. So the only other difference I see is back to collection vs. scalar. Assuming the following:
Global variable $AD_Groups is a collection of groups (array) and
Global variable $group is IDENTICAL to global variable $AD_Groups
With those assumptions outside the loop:

The -memberof parameter is getting an array of groups and inside the loop

-memberof parameter is getting a single group.

I don’t know if that is causing your error but it is a difference between the two (given my assumptions)

I know this post has been about understanding pipeline behavior, but getting to your goal

You could just do this (assuming $AD_Groups is all the groups you want to clear members from).

$AD_Groups | Set-ADGroup -Clear member

Did you try $Group.Name ?

I got it working by using a ForEach-Object loop after the pipe.

foreach ($Group in $AD_Groups) {
    Get-ADGroupMember -Identity $Group | ForEach-Object -Parellel -ThrottleLimit 100 { 
        Remove-ADPrincipalGroupMembership -MemberOf $Group -Identity $_ -Confirm:$false
    }
}

I don’t love looping within another loop, but it works so I’m going with it for now.