0 votes

I am currently using the following (previously support provided) script as part of the deprovisioning process, to remove a user from all groups:

Import-Module Adaxes
$user = Get-AdmUser "%distinguishedName%" -Properties MemberOf
if ($user.MemberOf -ne $Null)
{
foreach ($groupDN in $user.MemberOf)
{
Remove-AdmGroupMember $groupDN -Members $user -Confirm:$False
}
}

Can you assist in having this output all groups a user is in to a text file before removing the user from the groups. Preferable have it create a seperate file for each user named their SAMAccountname with domain. e.g. E:\grouparchive\username.domain.com.txt or similar.
OR
It may make more sense to create a list of the groups on a TextMultiValue attrib. , essentially what I am trying to do is get to a place where we can restore the users groups if they are accidently deleted by the above script.

by (470 points)
0

Something like this?

Import-Module Adaxes
$user = Get-AdmUser "%distinguishedName%" -Properties MemberOf
if ($user.MemberOf -ne $Null)
{
foreach ($groupDN in $user.MemberOf)
{
$groupDN | Out-File ('E:\grouparchive\' + $user.userPrincipalName.Replace('@','.') + '.txt') -Append
Remove-AdmGroupMember $groupDN -Members $user -Confirm:$False
}
}

User Bob Smith (sAMAccountName: bsmith, userPrincipalName: bsmith@bbqtesthouse.local) is disabled.
The following file is created: E:\grouparchive\bsmith.bbqtesthouse.local.txt with the following entries as the script is processed:
CN=ChilliTesters,OU=Groups,DC=bbqtesthouse,DC=local
CN=Ribs Project,OU=Groups,DC=bbqtesthouse,DC=local

0

Hello,

It may make more sense to create a list of the groups on a TextMultiValue attrib. , essentially what I am trying to do is get to a place where we can restore the users groups if they are accidently deleted by the above script.

Actually, you can have either, whatever is more convenient for you. Nodeblue has provided you a nice example on how you can save the groups to a text file. If necessary, we can make an example on saving the groups to a multi-valued attribute.

You can go even further and make a script that would reverse the action of your script, that is, a script that would read the groups, say, from a custom attribute, and them re-add the user to those groups. In this case, we would recommend saving group GUIDs as a byte[] array to some attribute that can store binary data (for example, CustomAttributeBinary1). Saving group GUIDs instead of DNs is safer because you can rename groups with the course of time, but group GUIDs won't change. Thus, you'll be able to re-add the user to the groups even if the groups were renamed. If you want, we can make such a script for you.

0

Hi,

I would love an example of the solution where you save the groups in a custom attribute, and a solution where you can reverse the action automatically from Adaxes. :)

1 Answer

0 votes
by (215k points)
selected by
Best answer

Hello,

Sure. Here you are.

The following script removes a user from all groups they are a member of and saves the GUIDs of the groups to Adaxes custom attribute CustomAttributeBinary1:

# Get GUIDs of the groups the user is a member of
$sourceGroupGuids = $Context.TargetObject.GetEx("adm-DirectMemberOfGuid") 

# Get the ID of the user's primary group
$primaryGroupId = $Context.TargetObject.Get("primaryGroupID")

# Build group list
$totalBytes = $sourceGroupGuids.Count * 16
$result = New-Object 'System.Collections.Generic.List[System.Byte]' $totalBytes
foreach ($groupGuidBytes in $sourceGroupGuids)
{
    # Bind to the group
    $guid = [Guid]$groupGuidBytes
    $groupPath = "Adaxes://<GUID=$guid>"
    $group = $Context.BindToObject($groupPath)

    # Skip the group if it is the primary group for the user
    if ($group.Get("primaryGroupToken") -eq $primaryGroupId)
    {
        continue
    }

    $result.AddRange($groupGuidBytes)

    # Remove the user from the group
    $group.Remove($Context.TargetObject.AdsPath)
}

if ($result.Count -eq 0)
{
    return
}

# Save the data to the adm-CustomAttributeBinary1 virtual property of the user
$Context.TargetObject.Put("adm-CustomAttributeBinary1", $result.ToArray())
$Context.TargetObject.SetInfo()

To execute the task when deprovisioning users, you can add the script to the Custom Command that you use for deprovisioning. By default, built-in Custom Command Deprovision is used for this purpose. For information on how to add an action to this Custom Command, see step 5 in the following tutorial: http://www.adaxes.com/tutorials_ActiveD ... ioning.htm. You need to add the Run a program or PowerShell script action and paste the above script in the Script field.


This script re-adds a user to the groups specified in Adaxes custom attribute CustomAttributeBinary1:

# Get group GUIDs
try
{
    $groupGuids = $Context.TargetObject.Get("adm-CustomAttributeBinary1")
}
catch
{
    $Context.LogMessage("Could not get the GUIDs of the groups the user was a member of before deprovisioning.", "Warning")
    return
}

# Calculate the number of groups
$totalBytes = $groupGuids.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.LogMessage("Unexpected data length when reading the GUIDs of the groups the user was a member of before deprovisioning!", "Error")
    return
}

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

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

# Get GUIDs of the groups the user is already a member of and remove them from the $groupsToAdd list
$targetGroupGuids = $Context.TargetObject.GetEx("adm-DirectMemberOfGuid")
foreach($targetGroupGuidBytes in $targetGroupGuids)
{
    $guid = [Guid]$targetGroupGuidBytes
    $groupsToAdd.Remove($guid) | Out-Null
}

# Add the user to the groups in the $groupsToAdd list
foreach($groupGuid in $groupsToAdd)
{
    try
    {
        $group = $Context.BindToObject("Adaxes://<GUID=$groupGuid>")
        $group.Add($Context.TargetObject.AdsPath)
    }
    catch
    {
        $Context.LogMessage($_.Exception.Message, "Warning")
        continue
    }
}

# Clear the custom attribute
$Context.TargetObject.Put("adm-CustomAttributeBinary1", $NULL)
$Context.TargetObject.SetInfo()

To be able to restore group memberships of the users whom you want to re-provision, you need to create a Custom Command that can run the script on a user account. For information on how to create Custom Commands, see the following tutorial: http://www.adaxes.com/tutorials_ActiveD ... ommand.htm. Use it as a guide. On step 4, add the Run a program or PowerShell script action and paste the script in the Script field.

0

That is perfect. Thank You.

0

Would it also be possible to add the OU the user was in to the script. In other words, when a user is de-provisioned it saves the path to the OU they were in before moving them to expired accounts OU. Then if the de-provision needs to be undone a script would both restore their groups and place them back in the OU they were originally in.

0

Hello,

Yes, sure. We've asked our script guys to modify the scripts for you.

0

Hello,

Use the following script on user deprovisioning. It saves GUIDs of the groups a user used to be a member of to Adaxes custom attribute CustomAttributeBinary1, and the path of the OU or container where the user was located to CustomAttributeText1:

# Save the path of the container where the user is located to adm-CustomAttributeText1
$parentPath = $Context.TargetObject.Parent
$Context.TargetObject.Put("adm-CustomAttributeText1", $parentPath)
$Context.TargetObject.SetInfoEx(@("adm-CustomAttributeText1"))

# Get GUIDs of the groups the user is a member of
$sourceGroupGuids = $Context.TargetObject.GetEx("adm-DirectMemberOfGuid")

# Get the ID of the user's primary group
$primaryGroupId = $Context.TargetObject.Get("primaryGroupID")

# Build group list
$totalBytes = $sourceGroupGuids.Count * 16
$result = New-Object 'System.Collections.Generic.List[System.Byte]' $totalBytes
foreach ($groupGuidBytes in $sourceGroupGuids)
{
    # Bind to the group
    $guid = [Guid]$groupGuidBytes
    $groupPath = "Adaxes://<GUID=$guid>"
    $group = $Context.BindToObject($groupPath)

    # Skip the group if it is the primary group for the user
    if ($group.Get("primaryGroupToken") -eq $primaryGroupId)
    {
        continue
    }

    $result.AddRange($groupGuidBytes)

    # Remove the user from the group
    $group.Remove($Context.TargetObject.AdsPath)
}

if ($result.Count -eq 0)
{
    return
}

# Save the data to the adm-CustomAttributeBinary1 virtual property of the user
$Context.TargetObject.Put("adm-CustomAttributeBinary1", $result.ToArray())
$Context.TargetObject.SetInfoEx(@("adm-CustomAttributeBinary1"))

The following code will re-add a user to groups specified in CustomAttributeBinary1 and move them back to a container specified via CustomAttributeText1:

# Get the saved parent container path
try
{
    $containerPath = $Context.TargetObject.Get("adm-CustomAttributeText1")
}
catch
{
    $Context.LogMessage("Cannot get the OU where the user was located before deprovisioning", "Warning")
    $containerPath = $NULL
}

if (($containerPath -ne $NULL) -and ($containerPath -ne $Context.TargetObject.Parent))
{
    # Move the user
    $container = $Context.BindToObject($containerPath)
    $container.MoveHere($Context.TargetObject.AdsPath , $NULL) | Out-Null
    $Context.TargetObject.UpdateAdsPath()
}

# Get group GUIDs
try
{
    $groupGuids = $Context.TargetObject.Get("adm-CustomAttributeBinary1")
}
catch
{
    $Context.LogMessage("Could not get the GUIDs of the groups the user was a member of before deprovisioning.", "Warning")
    return
}

# Calculate the number of groups
$totalBytes = $groupGuids.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.LogMessage("Unexpected data length when reading the GUIDs of the groups the user was a member of before deprovisioning!", "Error")
    return
}

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

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

# Get GUIDs of the groups the user is already a member of and remove them from the $groupsToAdd list
$targetGroupGuids = $Context.TargetObject.GetEx("adm-DirectMemberOfGuid")
foreach($targetGroupGuidBytes in $targetGroupGuids)
{
    $guid = [Guid]$targetGroupGuidBytes
    $groupsToAdd.Remove($guid) | Out-Null
}

# Add the user to the groups in the $groupsToAdd list
foreach($groupGuid in $groupsToAdd)
{
    try
    {
        $group = $Context.BindToObject("Adaxes://<GUID=$groupGuid>")
        $group.Add($Context.TargetObject.AdsPath)
    }
    catch
    {
        $Context.LogMessage($_.Exception.Message, "Warning")
        continue
    }
}

# Clear the custom attribute
$Context.TargetObject.Put("adm-CustomAttributeBinary1", $NULL)
$Context.TargetObject.SetInfo()

Related questions

0 votes
1 answer

Hi, I'm currently facing a problem where I want to set up a powershell script that should report all accounts (enabled, disabled, expired) matching a specific employeeType ... something else, just the plain Info Can you help me with this? kind regards Ingemar

asked Sep 4, 2015 by ijacob (960 points)
0 votes
0 answers

I know Adaxes has a module in it that uses e-mail verification in the password self-service policies. Can the verification system be used for anything other than an AD password ... to have a custom task run, but only after e-mail or text verification? Thanks!

asked Jul 27, 2015 by rlemaster (20 points)
0 votes
1 answer

I have written a de-provisioning job as part of removing a terminated employee's access. This job disables the account, resets the password, sets the account description to ... part of the de-provision job. Could I possibly get help with this? Thanks!

asked Jan 27, 2014 by PunkinDonuts (360 points)
0 votes
1 answer

I'm attaching below a snippet from a scheduled task. It's a function that receives as a parameter the employeeID, which is then used in the search filter. ... { $userInfo."$propertyName" = $searchResult.Properties[$propertyName].Value } } return $userInfo }

asked Oct 28, 2016 by sandramnc (820 points)
0 votes
0 answers

Please excuse this lengthy post but in order to fully explain my scenario, I believe it's necessary. We're using the Adaxes Web Interface to enable Department HR Reps to ... it being e-mailed. Any assistance or guidance would be greatly appreciated. Thanks...

asked Jul 19, 2016 by sandramnc (820 points)
2,807 questions
2,541 answers
6,615 comments
65,158 users