0 votes

Hi,

I'm working on my "account lifecycle" review processes and have a new area that I'm starting to think about.

When staff who are also managers (of both users and other AD objects i.e. Groups) leave, we want to make sure we can 'catch' these as part of the deprovisioning process. Worst case would be to pause the deprovision until all supplicant objects are re-assigned, best case would be some way of bulk re-assigning all objects to an alternate user.

One of the issues I've hit is being able to (basic example) send an email to the AD administrators with a list of all 'ManagedObjects' if there are more than one, as purely working with the %ManagedObjects% attribute only returns the first instance.

The more complex issue is, how best to pass multiple variables to a script\adaxes job i.e. if I run a job against user 'Joe Bloggs' I can use this username attribute to search 'his' record for the ManagedObjects value/s, and as a search term to identify any other users with this username as the %Manager% value. However, I'm struggling to think how I can also pass the job the 'new' managers name.

The best option I can think of is creating a custom attribute, such as 'Replacement Manager' that has to be added to the 'old' manager record, and we have logic that doesn't allow the old user object to be deleted until it can find and use this value to replace any references to itself using a custom command etc (if that makes sense).

Note: As an aside to this - is it possible to configure a custom attribute so that it presents the 'User Selection' data entry line in the UI (ala Manager, Managed By etc) so that we can use a constrained input?

As a final question (tangentially related to the subject now!).

As part of the review process we're setting up (thanks for your fantastic help by the way), one thing we would like to consider is whether the 'manager' (approver) is available to process the review. We have a custom user attribute called 'Account Status', that can be 'Active, Suspended, Maternity Leave, Extended Leave etc, that I'd like to be able to query as a check. The resultant logic would therefore be something like:

"If reviewing Joe Bloggs, before emailing reminders to manager check that manager record is active, if not use manager's assistant instead"

I'd be very grateful if you have any experience from previous functions similar to the above, or any code snippets that I can use! I appreciate there are some complex questions in here, so don't prioritise!

Many Thanks

by (1.6k points)
0

Hi,

I've been trying a few things and I think I'm starting to get the hang of the scripting interfaces (the basics - I'm no programmer!).

In relation to the question re: checking the status of the Manager, I've been using some test scripts to go each step, and I've got this far to validate the logic of checking the Manager of the target user, and using that returned value to lookup an attribute for the Manager (in this case their fullname).

However, I don't seem to be able to return a custom Adaxes attribute at the

$manager.<attribute> stage, which I think is because this is binding to the AD record - do I need to do something different?  

$subject = "Manager Check Test"  
$bodyHtml = $NULL  
$managerDN = $Context.TargetObject.Manager  

If ($managerDN -eq $NULL)  
{  
 $Context.SendMail("<bob@bob.com>", $subject, "%fullname% has no manager", $bodyHtml)  
 return  
}  

$manager = $Context.BindToObjectByDN($managerDN)
$Context.SendMail("bob@bob.com", $subject, $manager.Fullname, $bodyHtml)

0

Hello,

We are doing something similar on our side. I will copy/paste the code there on monday when I hit the office.

As far as I can remeber it is basicaly something like that:
Import-Module Adaxes
$user=Get-AdmUser -Identity "%cn%" -Properties directreports,managedby

$user.managedby is the managedby
$user.directreports is the directreports

1 Answer

0 votes
by (216k points)

Hello,

First of all, to access a user's manager and send an email containing the user's manager full name, you do not need any scripting. Adaxes has value references for calculated (virtual) properties that you can use to access information on the manager in the text of the message for the Send email notification action. For more information, see Calculated Properties. So, for example, if you need to send an email notification containing the manager's full name, you need to add the Send email notification action to your Business Rule, Custom Command or Scheduled Task and use the %adm-ManagerFullName% value reference in the message text. To add such an action:

  1. Open Adaxes Administration Console.
  2. In the Console Tree, locate and select the Business Rule, Custom Command or Scheduled Task that you want to add the action to.
  3. Select the necessary set of actions and conditions and click Add Action.
    ***- or -*
    Click the
    Add action to a new set** link.
  4. Select the Send email notification action.
  5. Set up the template for email notification.
  6. If necessary, you can use the If <property> <relation> <value> condition to check whether the user has a manager.

As to your initial request, we would suggest the following approach. On user deprovisioning, you can use a PowerShell script that would find all the objects managed by the user (that is, all objects where the user is specified in the Managed By property), as well as all the objects for which the user is specified as manager in the Manager property. Then, you can either send the names/DNs of the objects found to a certain person in charge (or the user's manager) or reassign object/user management automatically. For example, you can specify the user's manager as the owner/manager of those objects.

Or, if you want to specify the new manager/object owner directly, we can suggest a slightly different approach. You can, for example, set up a Home Page Action with a customized form that will contain a certain field. In that field, the users will be able to specify the username of the user who will be assigned as the new manager/owner for the objects. Then, when a user clicks Save, the username specified in the property would be saved to a certain property of the user that you are deprovisioning. For this purpose you can use one of Adaxes virtual properties that can sotre text data (for example, CustomAttributeText1). This property is not stored in Active Directory, but you can use it as any other property of AD objects. The only issue here is that the user will have to specify the new manager/owner manually by his/her username.

Then, you can create a Business Rule that will be triggered after updating a user. The Business Rule will check whether the property that you specified to pass the new manager/owner is modified. If it is modified, it will reassign the management/ownership of the objects and will do the rest of the deprovisioning job.

If you would prefer such a solution, we can provide you with more details.

As an aside to this - is it possible to configure a custom attribute so that it presents the 'User Selection' data entry line in the UI (ala Manager, Managed By etc) so that we can use a constrained input?

No, this is currently not supported. As a workaround, you can use one of the AD properties that support DN input syntax for this purpose. For example, if you do not use the Secretary or Assistant properties, you can use one of them.

"If reviewing Joe Bloggs, before emailing reminders to manager check that manager record is active, if not use manager's assistant instead"

We don't quite understand the requirements for this task, can you explain it in more detail?

0

Hi,

Thanks for the reply.

As I've actually asked two different questions, but they do seem to have a cross-over, I've split my feedback below into three to hopefully make my explanation\questions easier to understand!

=== Working With Multi-Value Attributes ===

As you stated:

"On user deprovisioning, you can use a PowerShell script that would find all the objects managed by the user"

some attributes for users hold multiple values - such as 'ManagedObjects'.

I was therefore wondering whether there was any easy way of using the Adaxes GUI workflows to return ALL ManagedObjects values for a user account, or if we have to use a script for this (I guess using some form of 'For Each' loop)?

=== Querying Custom Adaxes Attributes In PowerShell Scripts ===

The script I included above to email the manager name etc was a test script that I was using to validate that I could lookup an attribute for the manger of a user account being processed in a powershell script.

Using email to send the results was really just a simple way to validate that an attribute was being returned correctly, so the important bits were really:-

# Bind to the Manager of the employee account
$managerDN = $Context.TargetObject.Manager
# Return an attribute of the manager account
$Context.SendMail("bob@bob.com", $subject, $manager.Fullname, $bodyHtml)

and what I really want to be able to do is return a custom attribute:-

# Return the custom adaxes attribute 'Account Status' of the manager account
$Context.SendMail("bob@bob.com", $subject, $manager.AccountStatus, $bodyHtml)

where, the queried value is either the customattributetextxx name or friendly name of a custom attribute, and would ultimately be used in the script to do something else i.e.

If ($manager.AccountStatus -neq 'Active')
{what to do when manager is not available}
Else
{start standard review process}

The context for this question was; we currently add a custom attribute for each user account "Account Status" that can have values of 'Active' if the user account is active, 'Maternity' if they are on maternity leave, 'Extended Leave' if they are on extended leave etc.

Therefore, when we are about to start the automated account reviews, we know that, if the Manager account status is anything other than Active, they will not be available to respond. In this case we need to have an alternate process to follow as the emails will be bing sent to someone not available to respond. This could be i) use the manager's manger, ii) use the manager's defined alternate (deputy), or iii) something else etc.

During my tests using the above script/syntax I can return any standard AD attributes, but was unable to query custom attributes as they always came back blank?

=== Putting some of the above concepts together - Replacing a Mangers repoting line objects to stop reporting line orphans being created during object deletions ===

I'm not yet sure exactly how we want this to work in practise, but I think our objective is going to be something like this:-

  • When deprovisioning a user, check to see whether they have any 'Direct Reports' and/or 'Managed Objects'

    If so, send an email to Security Team listing all of the supplicant objects and stop the account being removed until they have been reassigned.

    Reassign each link manually, or use a custom form (as per your suggestion) and a Business Rule that allows the Security Team to provide an alternate 'Manager' value that will then be used to replace all references to the old account automatically.

    When all reporting lines to the old account have been removed, allow deprovisioning to proceed.

So this script\s run by the Business Rule would be something like (apologies for badly summarised script syntax!):

# Replace reporting line logic - run against all AD objects
For each $User
{
If (Context.TargetObject.ManagedBy' -eq $UserToBeDeleted)
{Set Context.TargetObject.ManagedBy = $UserToBeDeleted.Replacement}
}

# Replace owned objects logic - run against deprovisioned account itself
For each $Context.TargetObject.ManagedObject
{
Bind to ManagedObject and change owner to Context.TargetObject.Replacement
}

===

Regards

0

Helllo,

=== Working With Multi-Value Attributes ===

The best option would be to use PowerShell scripts in this case. The following script emails names of all the objects that the user manages and his/her subordinates to the email specified in $to. Use the script as a guide/example.

# E-mail mesasage settings
$subject = "My Subject" # TODO: modify me
$to = "recipient@domain.com" # TODO: modify me

# Build message body
$bodyText = New-Object "System.Text.StringBuilder"

# Get managed objects
try
{
    $managedObjectDNs = $Context.TargetObject.GetEx("managedObjects")
}
catch
{
    $managedObjectDNs = $NULL
}

if ($managedObjectDNs -ne $NULL)
{
    $bodyText.Append("Managed objects:")
    $bodyText.AppendLine()

    foreach ($managedObjectDN in $managedObjectDNs)
    {
        $managedObject = $Context.BindToObjectByDN($managedObjectDN)
        $bodyText.Append($managedObject.Get("name"))
        $bodyText.AppendLine()
    }

    $bodyText.AppendLine()
}

# Get Subordinates
try
{
    $subordinateDNs = $Context.TargetObject.GetEx("directReports")
}
catch
{
    $subordinateDNs = $NULL
}

if ($subordinateDNs -ne $NULL)
{
    $bodyText.Append("Subordinate:")
    $bodyText.AppendLine()

    foreach ($subordinateDN in $subordinateDNs)
    {
        $subordinate = $Context.BindToObjectByDN($subordinateDN)
        $bodyText.Append($subordinate.Get("name"))
        $bodyText.AppendLine()
    }
}

# Send mail
if ($bodyText.Length -ne 0)
{
    $Context.SendMail($to, $subject, $bodyText.ToString(), $NULL)
}

=== Querying Custom Adaxes Attributes In PowerShell Scripts ===

Here's a code snippet that gets the CustomAttributeText1 property of the user's manager and checks whether it is set to Active. By the way, when accessing properties of a directory object with a PowerShell script, you should always remember that you must access properties not by their display names that you defined for them, but by their LDAP names. So, if you, for example, set the Display Name for the CustomAttributeText1 property to Account Status, in your scripts you will have to access it by the adm-CustomAttributeText1 name.

try
{
    $managerDN = $Context.TargetObject.Get("manager")
}
catch
{
    # The user does not have a manager.
    # TODO: Some code for the case when the user does not have a manager
    return # To exit the script
}
$manager = $Context.BindToObjectByDN($managerDN)
$managerStatus = $manager.Get("adm-CustomAttributeText1")
if ($managerStatus -ieq 'Active')
{
    # TODO: standard review process
}
else
{
    # TODO: actions when manager is not available
}

=== Putting some of the above concepts together - Replacing a Mangers repoting line objects to stop reporting line orphans being created during object deletions ===

When deprovisioning a user, check to see whether they have any 'Direct Reports' and/or 'Managed Objects'
If so, send an email to Security Team listing all of the supplicant objects and stop the account being removed until they have been reassigned.
Reassign each link manually, or use a custom form (as per your suggestion) and a Business Rule that allows the Security Team to provide an alternate 'Manager' value that will then be used to replace all references to the old account automatically.
When all reporting lines to the old account have been removed, allow deprovisioning to proceed.

The only issue here that if you use a Home Page Action with a customized form (as per my suggestion above), you will not be able to check whether they have any Direct Reports and/or Managed Objects. The user that will become the new owner/manager will need to be specified anyway at the very start of the process, no matter whether the user has Direct Reports or Managed Objects or not.

0

Many thanks for your continuing advice on scripting - both supplied examples are perfect for me to work with, and give a good basis from which to develop my workflows.

For the last issue - I think I understand the limitiation - this is the issue that all attributes values are 'frozen' at the point at which the initial action is triggered?

To address this, in our scenario, we are already considering a dedicated 'Deprovisioning Errors' OU so that any users that cannot be fully deleted are instead moved to this holding OU as the final action - probably with a custom entry in the Account Status ("Deprov Error - Supplicant Objects" in this case).

Once we insert the "Replacement Manager" to the record, we should then be able to run a custom job via a Custom Command or Business Rule to automate changing the links.

One advantage of this is that we could maybe delete one of the existing 'name capable' attributes (deputy, assistant) as part of moving into this OU, and then use that to temporarily define the replacement manager value (with appropriate explanation on the custom form as to why the field name is wrong!).

0

For the last issue - I think I understand the limitiation - this is the issue that all attributes values are 'frozen' at the point at which the initial action is triggered?

No, the properties of a directory object do not get 'frozen' or become read-only once an action is started. The thing is that any values that you want to use in PowerShell scripts/actions should be specified directly in the script or based on certain values of a directory object. Currently Adaxes does not support prompting for values / user input from scripts / actions, we have such a feature in our TODO list. So, what we suggest is saving the name of the user who will become the new object manager / owner in a certain property of the current owner / manager (that is being deprovisioned), so that it would be possible to access the new object manager / owner from the property of the deprovisioned user.

To implement the solution that we suggested above, you need to create a Home Page Action that will modify a user and will contain only one property on the form. The property will be used to input the name of the user that will become the 'replacement manager'. For example, you can use CustomAttributeText1. The user will need to be specified by the username.

Then, you can create a Business Rule that will be triggered after updating a user and will check whether the value of the property that you chose to pass the username has changed. If the property has changed, the Business Rule will use a PowerShell script to set the specified user as the owner / manager of the objects and, optionally, perform other actions related to deprovisioning.

I. Create a Home Page Action with a customized input form

  1. On the computer, where your Web Interface is installed, start the Web Interface Customization tool.
  2. In the Interface type drop-down list, select the Web Interface you want to configure.
  3. Activate the General tab, select the Actions pane option, and click Configure Home Page Actions.
  4. In the dialog box that appears, click Add.
  5. On the 1st step of the Add Home Page Action wizard that appears, select Modify and choose User from the associated drop-down list.
  6. On the 4th step of the wizard, select Use customized form and click Customize Form.
  7. In the Customize Form dialog that appears, you need to remove all the fields in the General section. On how to delete fields, refer to step 6 of the Customize Forms for User Creation and Editing Tutorial.
  8. Now, you need to add the virtual property that you will use on your form. To add a property to a web Interface form, click the Add button below the Section fields section.
  9. In the dialog box that appears, you need to select the virtual property that you will use. As virtual properties are not displayed by default, you need to tick Show all properties to be able to select them.
  10. Select the virtual property that you will use, for example CustomAttributeText1.
  11. Click OK.
  12. Finish the Add Home Page Action wizard.

II. Create a Business Rule that to automatically reassign object ownership / management

  1. Create a new Business Rule.

  2. On the 2nd step of the Create Business Rule wizard, select User and After Updating a User.

  3. On the 3rd step, add the Run a program or PowerShell script action and paste the following script.

     Import-Module Adaxes
    
     # Get new manager/owner name
     try
     {
         $managerName = $Context.TargetObject.Get("adm-CustomAttributeText1") # TODO: modify me
     }
     catch
     {
         $Context.LogMessage("New Manager/Owner is not specified", "Information") # TODO: modify me
         return
     }
    
     # Get new manager/owner
     $manager = Get-AdmUser $managerName -ErrorAction SilentlyContinue
     if ($manager -eq $NULL)
     {
         $Context.LogMessage("User with name $managerName not found", "Warning") # TODO: modify me
         return
     }
    
     # Get managed objects
     try
     {
         $managedObjectDNs = $Context.TargetObject.GetEx("managedObjects")
     }
     catch
     {
         $managedObjectDNs = $NULL
     }
    
     if ($managedObjectDNs -ne $NULL)
     {
         foreach ($managedObjectDN in $managedObjectDNs)
         {
             $managedObject = $Context.BindToObjectByDN($managedObjectDN)
             $managedObject.Put("managedBy", $manager.distinguishedName)
             $managedObject.SetInfo()
         }
     }
    
     # Get subordinates
     try
     {
         $subordinateDNs = $Context.TargetObject.GetEx("directReports")
     }
     catch
     {
         $subordinateDNs = $NULL
     }
    
     if ($subordinateDNs -ne $NULL)
     {
         foreach ($subordinateDN in $subordinateDNs)
         {
             $subordinate = $Context.BindToObjectByDN($subordinateDN)
             $subordinate.Put("manager", $manager.distinguishedName)
             $subordinate.SetInfo()
         }
     }
  4. Add a short description for the script and click OK.

  5. Optionally, you can set the Business Rule to perform the rest of the deprovisioning process. For example, it can perform a Custom Command used for user deprovisioning. To do this, click the Add Action button.

  6. In the dialog box that appears, select the Execute a Custom Command action and click Select.

  7. Select the Custom Command that you use for use deprovisioning and click OK two times.

  8. Now you have to add a condition when the actions will be triggered. The name of the 'replacement manager' will be passed in the CustomAttributeText1 property, so we need to check in the Business Rule whether CustomAttributeText1 has changed. To do this, click the Add Condition button.

  9. In the dialog box that appears, select the If <property> <changed> condition.

  10. In the <property> drop-down list, select Show all properties.

  11. Select the property that you chose to pass the username.

  12. Select has changed.

  13. Click OK and finish creation of the Business Rule.

To address this, in our scenario, we are already considering a dedicated 'Deprovisioning Errors' OU so that any users that cannot be fully deleted are instead moved to this holding OU <CUT> One advantage of this is that we could maybe delete one of the existing 'name capable' attributes (deputy, assistant) as part of moving into this OU, and then use that to temporarily define the replacement manager value (with appropriate explanation on the custom form as to why the field name is wrong!).

If you decide on using this scenario, this will be simple to achieve. The thing is that Adaxes allows you to create custom hints and help for properties using Property Patterns. For information on how to achieve such a task, see Provide Custom Help and Tips for AD Object Properties.

So, you can create a separate Property Pattern with the custom hint and/or help for the Assistant or the Secretary property and include only the necessary OU in the Activity Scope of the Property Pattern.

In this case, you will need a slightly modified script to set the replacement manager.

0

Perfect - many thanks.

My mistake on the use of the term 'frozen' - I meant that the variables 'read-in' by the Action when it is triggered cannot be updated during processing, so if the Action is "paused" and we then add the 'new manager' attribute it cannot be referenced by the Action itself, and we instead have to launch a new action (in this case the business rule) to use it as a variable.

Thanks also for the pointer about the form hint - I hadn'd considered that.

Best Regards

0

Hi,

FYI All working as expected - created Home Page Action so admin's can 'Reassign' objects, they choose the AD object for the 'old' manager, enter the Username of the 'new manager' (currently freeform text field for testing), which triggers the business rule.

I had to tweak the rule to stop a loop condition being created, but I think that's just inexperience on my part - see below screenshot #1 - and I also added some custom text to the logged messages so that the web portal user gets positive feedback for the performed actions - screenshot #2.

I am temporarily using CustomText15 for testing etc, but will be integrating this logic into the operational procedures when I hope to switch to one of the built-in AD fields that support user object selection (manager\assistant) so that it must be performed against a valid, current, user object.


The log messages are returning the object name and manager name is slightly different syntax, but again I'm sure I'll get the hang of binding to objects and returning values in a consistent manner with time!

I'm putting together all the elements now so that we get alerted if a user has subordinate objects during deprovisioning, then 'parking' the account until these are cleared. We can then choose to reassign all objects, or the managed objects and "reporting line" separately.

Already thinking about how to deal the scenario if the user isn't replaced immediately - retain old account as a temporary holding object, create a new holding object, or reassign objects to old users manager (with some way of being able to tag them so they can all be shifted 'back' in one go once the replacement employee is hired). Then making sure this dovetails with the review process so that the appropriate authoriser is sent the approval ticket based on the phase of the reassignment...

It's a good sign for your product when I can go from "I want to replicate our current processes" to "I want to automate things I hadn't even considered before" without breaking a sweat!

Best Regards

0

Hello,

Thank you for your good words, we really appreciate it! ;)

Related questions

0 votes
1 answer

Hello, I like to use a custom attribute to store the hardware choice for a new user: When a new user is created, a mail is sent to the manager to edit the user. One of ... not shure whether to treat it as an object or as a string. Any help will be usefull.

asked Oct 15, 2018 by Yehudi (140 points)
0 votes
1 answer

Is it possible to remove the default blank option that shows up in a multi-value field? When I add two possible options for a multi-value field in the Property Pattern constraint, ... along with the other two options. Is it possible to get rid of the blank?

asked Mar 8, 2017 by sdavidson (730 points)
0 votes
1 answer

We are trialing Adaxes and are wondering the following two things are possible. Is it's possible to have the order of Authentication methods adjusted ? Is it possible to import an ... 't look to exist, but would it be viable to add them as feature requests ?

asked Jul 6, 2020 by dgrandja (70 points)
0 votes
0 answers

Ever since upgrading to 3.16.21906.0 the script here no longer works: https://www.adaxes.com/script-repository/move-mailbox-tofrom-microsoft-365-s579.htm Not sure what the issue is as I can't find any errors in the log.

asked Nov 16, 2023 by curtisa (210 points)
3,326 questions
3,026 answers
7,727 comments
544,682 users