Script Repository


Perform actions upon changes in group membership (including changes made by 3rd party tools)

January 26, 2016
937

The script allows you to execute Custom Commands when membership of an AD group changes, no matter whether the changes were made using Adaxes or any 3rd party tools, such as ADUC or Exchange.

To be able to identify which members were added to or removed from a group, the script saves GUIDs of the current members in a certain multi-valued attribute of the group. The saved GUIDs are used to compare the list of current members of the group with members on the previous run.

We suggest using an Adaxes custom attribute for storing member GUIDs, for example, adm-CustomAttributeTextMultiValue1. Such attributes are not stored in AD, but can be used the same as any other attribute of AD objects.

To use the script with Adaxes, create a Scheduled Task for Group objects that runs the script using the Run a program or PowerShell script action.

Parameters:

  • $savedMembersAttribute - specifies the LDAP display name of the attribute that will be used to store group member GUIDs;
  • $customCommandIdAddedToGroup and $customCommandIdRemovedFromGroup - specify the IDs of the Custom Commands that will be run on users who were added or removed from a group. How to get the ID of a Custom Command.
Edit Remove
PowerShell
$savedMembersAttribute = "adm-CustomAttributeTextMultiValue1" # TODO: modify me
$customCommandIdAddedToGroup = "{D993945F-A9B7-4349-AE18-351F80D9DCD9}" # TODO: modify me
$customCommandIdRemovedFromGroup = "{9DB88EC3-1241-4AB1-9612-C7C982BAA49F}" # TODO: modify me

function SaveCurrentMembers($guidsBytes, $savedMembersAttribute)
{
    if ($guidsBytes.Count -eq 0)
    {
        # All members were removed from the group
        $Context.TargetObject.PutEx("ADS_PROPERTY_UPDATE", $savedMembersAttribute, @("none"))
    }
    else
    {
        $values = @()
        foreach ($guidBytes in $guidsBytes)
        {
            $values += ([Guid]$guidBytes).ToString()
        }
        
        $Context.TargetObject.PutEx("ADS_PROPERTY_UPDATE", $savedMembersAttribute, $values)
    }
    
    # Save changes
    $Context.TargetObject.SetInfo()
}

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

$memberGuids = New-Object "System.Collections.Generic.HashSet[System.Guid]"
foreach ($guidBytes in $currentMemberGuids)
{
    $guid = [Guid]$guidBytes
    $memberGuids.Add($guid)
}

# Get saved member GUIDs
try
{
    $savedMemberGuids = $Context.TargetObject.GetEx($savedMembersAttribute)
}
catch
{
    if ($memberGuids.Count -eq 0)
    {
        return # No current and saved members
    }
    
    # Save current members GUIDs and exit
    SaveCurrentMembers $currentMemberGuids $savedMembersAttribute
    return
}

if (($savedMemberGuids.Length -eq 1) -and ($savedMemberGuids[0] -ieq "none"))
{
    $savedMemberGuids = @() # All users were removed from the group previous time
}

# Find members that were removed from the group
$removedMemberGuids = @()
foreach ($savedMemberGuid in $savedMemberGuids)
{
    $guid = [Guid]$savedMemberGuid
    if ($memberGuids.Remove($guid))
    {
        continue
    }
    
    $removedMemberGuids += $guid
}

if (($removedMemberGuids.Length -eq 0) -and ($memberGuids.Count -eq 0))
{
    return # No changes
}

if ($memberGuids.Count -ne 0)
{
    # Execute Custom Command on members that were added
    foreach ($newMemberGuid in $memberGuids)
    {
        # Bind to the member
        $path = "Adaxes://<GUID=$newMemberGuid>"
        $newMember = $Context.BindToObjectEx($path, $True)
        
        # Execute the Custom Command
        $newMember.ExecuteCustomCommand($customCommandIdAddedToGroup)
    }
}

if ($removedMemberGuids.Length -ne 0)
{
    # Execute Custom Command on members that were removed
    foreach ($removedMemberGuid in $removedMemberGuids)
    {
        # Bind to the member
        $path = "Adaxes://<GUID=$removedMemberGuid>"
        $removedMember = $Context.BindToObjectEx($path, $True)
        
        # Execute the Custom Command for removed members
        $removedMember.ExecuteCustomCommand($customCommandIdRemovedFromGroup)
    }
}

# Save current member GUIDs to custom attribute
SaveCurrentMembers $currentMemberGuids $savedMembersAttribute

Comments ( 2 )
avatar
Tim
June 11, 2020

Would it be possible to set this up as a business rule instead of a scheduled task?

avatar
Support
June 11, 2020

Hello Tim,

 

Yes, it is possible to run the script in a Business Rule configured for the Group object type. However, to trigger the rule corresponding changes must be made to a group via Adaxes. For example, if the script will be executed in a Business Rule triggering After adding a member to a group, it will trigger only when a member is added to a group included into the rule Activity Scope via Adaxes. If a member is added via any other tool (e.g. ADUC), the rule will not trigger.

Leave a comment

Related Scripts