This sounds scenario sounds pretty simple, and theoretically it is. It’s also a common request. Someone comes to you and says, I have members in one group and I need them copied to another group. Sure, no problem. But what they forgot to mention is that the source group is in a different domain and has users and groups from the same or different domain than their target group.
Issue
There are a few commands, especially in the newer releases of Windows that work with AD quite well. When your user account is in one domain and you want to work with objects in another domain, the ActiveDirectory cmdlets offer a -server parameter and a -credential parameter in order to connect to other domains and forests. In our case, this works great for the Get-ADGroupMember cmdlet. We are able to get a list of members from our source group, regardless of the domain membership the object has.
Unfortunately, when we use the Add-ADGroupMember cmdlet and we’re going to get an error. Let’s look in the scenario below.
There is a parent, child domain in an AD forest. Let’s call them parent.local and child.parent.local.
- The group with all the members inside it is “GroupOld” and resides in child.parent.local
- The group that will be updated
Let’s run some simple code, which is syntactically correct and would work if the AD objects were in the same domain, but in this case it will fail.
Import-Module ActiveDirectory $group1 = Get-ADGroup "GroupNew" $object = Get-ADUser "sally" -Server "child.parent.ad" Add-ADGroupMember -Identity $group1 -Members $object
After execution of the Add-ADGroupMember cmdlet, you’ll get an error message – Add-ADGroupMember : A referral was returned from the server.
What does this mean? Well the group we’re trying to update is in parent.ad ($group1). When we talk to AD, in this case to parent.ad, we’re requesting that AD add an object from another domain to the group membership. In almost all other AD tools, this happens as one would expect, successfully! The problem arises is that behind the scenes, AD is saying, wait a minute, I need more information about this AD object and it’s in another domain, I need to send you over to that DC for a moment (referral) to get the information. All the tools that you’ve used before probably do this for you. Unfortunately, the Add-ADGroupMember cmdlet doesn’t do this for us!
Solution
It’s quite simple, we use another cmdlet! Let’s look at some working code that will copy all the members of a group in another domain to one in the local domain. This code will add whatever AD objects are in the old group regardless of their domain membership to the new group.
Let’s start off with similar code to above – Get the group information for the old group and the new group
Import-Module ActiveDirectory $group1 = Get-ADGroup "GroupNew" $group2 = Get-ADGroup "GroupOld" -Server "child.parent.ad"
Now let’s get the group members for the groups
$membersInGroup1 = Get-ADGroupMember $group1 $membersInGroup2 = Get-ADGroupMember $group2 -Server "child.parent.ad"
Great, now that we have a list of groups, doesn’t it make sense that there is a possibility that a few members are a member of both groups? I think there is, so let’s filter out our list and only keep members that are not in the GroupNew.
$notAddedToGroup1 = Compare-Object -ReferenceObject $membersInGroup1 -DifferenceObject $membersInGroup2 -Property distinguishedName | Where {$_.SideIndicator -eq "=>"}
Now we are at the point we can finally add members to the group, GroupNew!
$notAddedToGroup1 | ForEach { Try { Set-ADObject -Identity $group1.distinguishedName -Add @{"member"=$_.distinguishedName} } Catch { Write-Host -ForegroundColor Red "[ERROR] $server - $($_.distinguishedName) - $($Error[0])" } }
That should be enough could to get you going or to even solve your problem!
One thing to note – I keep using the term “AD Object”. This is because AD Groups can have users or groups members. So if you’re going to add a specific object, you might want to use a command like:
$groupmember = Get-ADUser "TsInternetUser" $object = Get-ADObject $groupmember.DistinguishedName
Enjoy!
Hello Allan,
great blog ! Thank you very much!
What means
$object = Get-ADObject $groupmember.dsn specially .dsn ?
Best regards,
Michael
My bad! What one thinks and types doesn’t always happen. It should be the .DistinguishedName attribute. I have updated accordingly. Thanks for double checking!
I’m running this, but getting the error:
Compare-Object : Cannot bind argument to parameter ‘ReferenceObject’ because it is null.
At C:\temp\Copy_group_members.ps1:7 char:53
+ $notAddedToGroup1 = Compare-Object -ReferenceObject $membersInGroup1 -Difference …
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Compare-Object], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.CompareObje
ctCommand
[ERROR] – – Cannot validate argument on parameter ‘Add’. The argument is null or an element of the argument collection
contains a null value.
The actual code I’m running:
Import-Module ActiveDirectory
$group1 = Get-ADGroup “Zogenix_NYX_2925-W”
$group2 = Get-ADGroup “FG_BIOSAS_Zogenix-W” -Server “USPPYPICLDCW02.CLINICAL.ivh” -Credential clinical\dgower
$membersInGroup1 = Get-ADGroupMember $group1
$membersInGroup2 = Get-ADGroupMember $group2 -Server “USPPYPICLDCW02.CLINICAL.ivh”
$notAddedToGroup1 = Compare-Object -ReferenceObject $membersInGroup1 -DifferenceObject $membersInGroup2 -Property distinguishedName | Where {$_.SideIndicator -eq “=>”}
$notAddedToGroup1 | ForEach {
Try {
Set-ADObject -Identity $group1.distinguishedName -Add @{“member”=$_.distinguishedName}
} Catch {
Write-Host -ForegroundColor Red “[ERROR] $server – $($_.distinguishedName) – $($Error[0])”
}
}
Any thoughts appreciated.