Script repository

Copy group membership from specified user

Updated on: Jan 18, 2026, Views: 6130

Group membership

The scripts copy group membership from the specified user to the target user.

Script 1: Using a custom command parameter

To execute the script, create a custom command configured for the User object type. The account to copy group membership from will be taken from the Directory object picker command parameter.

Parameters

  • $sourceUserDNParamName - the name of the parameter used to select the source user with the param- prefix.
  • $replaceGroups - if set to $true, the script replaces all the target user group membership with that of the source user. If set to $false, the target user will retain its group membership and will be added to the groups the source user is a member of.
  • $onlyEntraGroups - If set to $true, the script will only add the target user to the Microsoft Entra groups the source user is a member of. If set to $false, the target user will be added to all the groups the source user is a member of.
  • $groupNamesToSkip - the sAMAccountNames of the groups that should be skipped by the script.
$sourceUserDNParamName = "param-User" # TODO: modify me
$replaceGroups = $False # TODO: modify me
$onlyEntraGroups = $False # TODO: modify me
$groupNamesToSkip = @("Group1", "Group2", "Group3*") # TODO: modify me

function SkipGroupByName($patterns, $group)
{
    if ($NULL -eq $patterns)
    {
        return $False
    }
    
    if ($group.DirectoryType -eq 1)
    {
        $groupName = $group.Get("sAMAccountName")
    }
    else
    {
        $groupName = $group.Get("name")
    }
    
    foreach ($pattern in $patterns)
    {
        if ($groupName -like $pattern)
        {
            return $True
        }
    }
    
    return $False
}

function SkipGroupByType($group, $skipPrimaryGroup, $primaryGroupId, $onlyEntraGroups)
{
    if ($onlyEntraGroups -and $group.DirectoryType -ne 2)
    {
        continue
    }
    
    if (($group.DirectoryType -eq 1) -and $skipPrimaryGroup)
    {
        # Check if the group is primary
        if ($group.Get("primaryGroupToken") -eq $primaryGroupId)
        {
            return $True
        }
    }

    # Check if the group is dynamic
    try
    {
        $dynamicMembership = $group.Get("adm-AzureDynamicMembership")
    }
    catch
    {
        $dynamicMembership = $False
    }
    
    # Check if the group is Rule based
    $isRuleBasedGroup = $group.MembershipType -eq "ADM_GROUPMEMBERSHIPTYPE_RULEBASED"
    
    return $dynamicMembership -or $isRuleBasedGroup
}

# Bind to the source user
$sourceUserDN = $Context.GetParameterValue($sourceUserDNParamName)
$sourceUser = $Context.BindToObjectByDN($sourceUserDN)

# Get groups to add
$groupGuidsToAdd = New-Object "System.Collections.Generic.HashSet[System.Guid]"
$sourceUser.GetEx("adm-DirectMemberOfGuid") | %%{[void]$groupGuidsToAdd.Add([Guid]$_)}

# Get current groups
$currentGroupGuids = New-Object "System.Collections.Generic.HashSet[System.Guid]"
$Context.TargetObject.GetEx("adm-DirectMemberOfGuid") | %%{[void]$currentGroupGuids.Add([Guid]$_)}

# Update groups
foreach ($guidBytes in $groupGuidsToAdd)
{
    $guid = [Guid]$guidBytes
    if ($currentGroupGuids.Remove($guid))
    {
        continue
    }
    
    # Skip special groups
    $group = $Context.BindToObjectEx("Adaxes://<GUID=$guid>", $True)
    if ((SkipGroupByName $groupNamesToSkip $group) -or (SkipGroupByType $group $False $NULL $onlyEntraGroups))
    {
        continue
    }

    $group.Add($Context.TargetObject.AdsPath)
}

if ($replaceGroups)
{
    $primaryGroupId = $NULL
    if ($Context.TargetObject.DirectoryType -eq 1)
    {
        # Get the primary group ID
        $primaryGroupId = $Context.TargetObject.Get("primaryGroupID")
    }
    
    foreach ($guidBytes in $currentGroupGuids)
    {
        $guid = [Guid]$guidBytes
        $group = $Context.BindToObjectEx("Adaxes://<GUID=$guid>", $True)

        # Skip the group if it is the user's Primary Group
        if (SkipGroupByType $group $True $primaryGroupId $onlyEntraGroups)
        {
            continue
        }
        
        $group.Remove($Context.TargetObject.AdsPath)
    }
}

Script 2: Using a DN syntax property

To execute the script, create a business rule, custom command or scheduled task configured for the User object type. The account to copy group membership from will be taken from a DN syntax property (e.g. Assistant) of the target user.

Parameters

  • $sourceUserDNPropertyName - the name of the DN syntax property storing the user to copy membership from.
  • $replaceGroups - if set to $true, the script replaces all the target user group membership with that of the source user. If set to $false, the target user will retain its group membership and will be added to the groups the source user is a member of.
  • $onlyEntraGroups - If set to $true, the script will only add the target user to the Microsoft Entra groups the source user is a member of. If set to $false, the target user will be added to all the groups the source user is a member of.
  • $groupNamesToSkip - the sAMAccountNames of the groups that should be skipped by the script.
$sourceUserDNPropertyName = "assistant" # TODO: modify me
$replaceGroups = $False # TODO: modify me
$onlyEntraGroups = $False # TODO: modify me
$groupNamesToSkip = @("Group1", "Group2", "Group3*") # TODO: modify me

function SkipGroupByName($patterns, $group)
{
    if ($NULL -eq $patterns)
    {
        return $False
    }
    
    if ($group.DirectoryType -eq 1)
    {
        $groupName = $group.Get("sAMAccountName")
    }
    else
    {
        $groupName = $group.Get("name")
    }
    
    foreach ($pattern in $patterns)
    {
        if ($groupName -like $pattern)
        {
            return $True
        }
    }
    
    return $False
}

function SkipGroupByType($group, $skipPrimaryGroup, $primaryGroupId, $onlyEntraGroups)
{
    if ($onlyEntraGroups -and $group.DirectoryType -ne 2)
    {
        continue
    }
    
    if (($group.DirectoryType -eq 1) -and $skipPrimaryGroup)
    {
        # Check if the group is primary
        if ($group.Get("primaryGroupToken") -eq $primaryGroupId)
        {
            return $True
        }
    }

    # Check if the group is dynamic
    try
    {
        $dynamicMembership = $group.Get("adm-AzureDynamicMembership")
    }
    catch
    {
        $dynamicMembership = $False
    }
    
    # Check if the group is Rule based
    $isRuleBasedGroup = $group.MembershipType -eq "ADM_GROUPMEMBERSHIPTYPE_RULEBASED"
    
    return $dynamicMembership -or $isRuleBasedGroup
}

# Bind to the source user
$sourceUserDN = $Context.TargetObject.Get($sourceUserDNPropertyName)
$sourceUser = $Context.BindToObjectByDN($sourceUserDN)

# Get groups to add
$groupGuidsToAdd = New-Object "System.Collections.Generic.HashSet[System.Guid]"
$sourceUser.GetEx("adm-DirectMemberOfGuid") | %%{[void]$groupGuidsToAdd.Add([Guid]$_)}

# Get current groups
$currentGroupGuids = New-Object "System.Collections.Generic.HashSet[System.Guid]"
$Context.TargetObject.GetEx("adm-DirectMemberOfGuid") | %%{[void]$currentGroupGuids.Add([Guid]$_)}

# Update groups
foreach ($guidBytes in $groupGuidsToAdd)
{
    $guid = [Guid]$guidBytes
    if ($currentGroupGuids.Remove($guid))
    {
        continue
    }
    
    # Skip special groups
    $group = $Context.BindToObjectEx("Adaxes://<GUID=$guid>", $True)
    if ((SkipGroupByName $groupNamesToSkip $group) -or (SkipGroupByType $group $False $NULL $onlyEntraGroups))
    {
        continue
    }

    $group.Add($Context.TargetObject.AdsPath)
}

if ($replaceGroups)
{
    $primaryGroupId = $NULL
    if ($Context.TargetObject.DirectoryType -eq 1)
    {
        # Get the primary group ID
        $primaryGroupId = $Context.TargetObject.Get("primaryGroupID")
    }
    
    foreach ($guidBytes in $currentGroupGuids)
    {
        $guid = [Guid]$guidBytes
        $group = $Context.BindToObjectEx("Adaxes://<GUID=$guid>", $True)

        # Skip the group if it is the user's Primary Group
        if (SkipGroupByType $group $True $primaryGroupId $onlyEntraGroups)
        {
            continue
        }
        
        $group.Remove($Context.TargetObject.AdsPath)
    }
}

Comments 4

You must be signed in to comment.

  • Dave

    Dave

    We've been using a version of this script for a while in a custom command to copy groups between users. When a group is configured with dynamic membership members cannot be manually added to the group. We've started having issues with errors that occur when a group that is in the list is configured with dynamic membership in Adaxes. I was wondering how we would modify the script to skip groups that user membership rules.

    • Support

      Support

      Hello Dave,

      Please, specify which of the two scripts you need updated.

  • Frederik

    Frederik

    I have the same issue as Dave.

    We use the "Using a custom command parameter" version of the script.

    Copying group membership goes well, but we get a lot of errors due the script trying to add or remove the user to or from dynamic user groups.

    The log shows:
    Add [user] to [groupname] ([domainname].onmicrosoft.com\Groups)
    Insufficient privileges to complete the operation.

    I would like to be able to exclude dynamic user groups from the script. Unfortunately our naming have not been the best, so doing it on name will not work. I would like to exclude on a group property.

    • Support

      Support

      Hello Frederik,

      Such a thing can happen in case a group is dynamic in Microsoft Entra or rule-based in Adaxes. We updated the scripts to skip such groups.

Got questions?

Support Questions & Answers

We use cookies to improve your experience.
By your continued use of this site you accept such use.
For more details please see our privacy policy and cookies policy.