Script Repository


Copy group members

February 18, 2021
2096

The below two scripts can be used to create custom commands for copying group members from one group to another. One of the commands can be executed on an AD group to copy its members. The other one can be executed on another group to paste the copied members.

For more information on creating custom commands, see Create a Custom Command. Both the commands must be configured for the Group object type.

To add scripts to custom commands, use the Run a program or PowerShell script action.

To pass group members between the groups, the 1st custom command saves GUIDs of members of the source group to the CustomAttributeBinary1 property of the user who invokes the custom command. The 2nd command reads the GIUDs from the same property and adds the objects whose GUIDs are specified to the destination group. Each GUID is represented as an array of 16 bytes (Byte[]), and the property will store an array of arrays of bytes.

CustomAttributeBinary1 is one of Adaxes virtual properties for binary data. Such properties are not stored in Active Directory, but you can use them the same as any other properties of AD objects.

Script for copying group members:

Edit Remove
PowerShell
# Get GUIDs of direct members of the group
try
{
    $sourceMemberGuids = $Context.TargetObject.GetEx("adm-DirectMembersGuid") 
}
catch
{
    $Context.LogMessage("The target group does not have members. Nothing to copy.", "Warning")
    return
}

# Build a single-dimension array of member GUIDs
$totalBytes = $sourceMemberGuids.Count * 16
$result = New-Object 'System.Collections.Generic.List[System.Byte]' $totalBytes
foreach ($memberGuidBytes in $sourceMemberGuids)
{
    $result.AddRange($memberGuidBytes)
}

# Save the GUIDs to the adm-CustomAttributeBinary1 virtual property user who invokes the script
$Context.Initiator.UserAdsObject.Put("adm-CustomAttributeBinary1", $result.ToArray())
$Context.Initiator.UserAdsObject.SetInfo()

Script for pasting group members:

Edit Remove
PowerShell
# Get an array of member GUIDs
try
{
    $sourceMemberGuids = $Context.Initiator.UserAdsObject.Get("adm-CustomAttributeBinary1")
}
catch
{
    $Context.Cancel("Failed to get member GUIDs.")
    return
}

# Calculate the number of GUIDs
$totalBytes = $sourceMemberGuids.Length

# Make sure that the total number of bytes is a divisible of 16
$remainder = 0
[System.Math]::DivRem($totalBytes, 16, [ref] $remainder)
if ($remainder -ne 0)
{
    $Context.Cancel("Unexpected data length! Exiting.")
    return
}

$membersToAdd = New-Object "System.Collections.Generic.HashSet[System.Guid]"

for ($i = 0; $i -lt ($totalBytes / 16); $i++)
{
    $bytes = [System.Guid]::Empty.ToByteArray()
    [System.Array]::Copy($sourceMemberGuids, $i * 16, $bytes, 0, 16)
    $guid = New-Object "System.Guid" (,$bytes)
    $membersToAdd.Add($guid)
}

# Get GUIDs of the current group members
try
{
    $memberGuids = $Context.TargetObject.GetEx("adm-DirectMembersGuid")
}
catch
{
    $memberGuids = @()
}

# Adjust the list of members that will be added to the target group
foreach($memberGuidBytes in $memberGuids)
{
    $guid = New-Object "System.Guid" (,$memberGuidBytes)
    if (-not($membersToAdd.Contains($guid)))
    {
        continue
    }
    $membersToAdd.Remove($guid) # already a member of the group
}

# Add new members to the group
foreach($memberGuid in $membersToAdd)
{
    $memberGuid = $memberGuid.ToString("B")
    $memberPath = "Adaxes://<GUID=$memberGuid>"
    try
    {
        $Context.TargetObject.Add($memberPath)
    }
    catch
    {
        if ($_.Exception.InnerException.ErrorCode -eq -2147019886)
        {
            continue
        }

        $Context.LogMessage($_.Exception.Message, "Error")
    }
}

$Context.LogMessage("Finished copying members to the group.", "Information")


Comments ( 2 )
avatar
Jason
Dec 08, 2020
The scripts for copying and pasting groups works well for us however we have a copy and paste scripted on user creation with an approval process. If more than one user is approved at the same time that has the same initiator, this causes odd results as Adaxes seems to be doing the same set of tasks synchronously. Is there a way to make Adaxes setup one user after the other when approved, with a potential a delay, or an amendment to the script to assign users to different CustomAttributeBinary attributes.
avatar
Support
Dec 10, 2020
Hello Jason,

We opened a support ticket to help you with the script. An email was sent to the address of your account.
Leave a comment