Article
In many cases there is a need to add loops to a workflow.
Such loops may be required if you need to execute repetitive tasks, or to perform tasks on multiple objects.
This article shows both:
- the sample task will disable users who have been inactive for a specified number of days
- the sample task is repeated daily until explicitly stopped
The workflow sample outlined in this article has the purpose to deactivate users who have not logged in for a specified number of days.
For this purpose, the example uses two loops:
- The outer loop is repeated every day. It scans for users who have not logged in for longer than the specified time
- The inner loop goes through the result list and perform an Entity activity (disable the user) for each matching user.
Adding a time-controlled loop is rather simple.
- behind your custom actions, append a dummy approval activity with a timeout of your choice
- on timeout, go back to the start of your custom actions
Adding data-dependent loops is only slightly more complicated, since you need to add some custom ECMAscript to evaluate the data and control the loop.
Here's the basic logic for a workflow that, once started, will automatically run every day, identify the inactive users, and disable each user in the list:
- Start Form
Start your workflow and enter the inactivity interval. The sample uses a list with the options "30 days", "60 days", "90 days", "180 days", and "360 days"The form will also show what users will be affected during the first run.
Internally, a Query is used, and you will probably need to adapt this query to your own needs:
The sample query is named "CoolSolution_inactiveUsers" and perform a search on the container "OU=users,O=utopia" with a filter "( && ( loginDisabled != true )( loginTime < [param] ))"
- Calculate the Criterion Date
If we want to identify the users who have not logged in for 90 days, we need to calculate the criterion date with something like "criterionDate = ([current date] - 90 days)", before finding all users whose las login date is earlier that this criterion.We store the calculated criterionDate in flowdata (flowdata.start/criterionDate).
This is the code to calculate the target date:
function getCriterionDate( ) { var result = "00000000000000Z"; try { var daysOfInactivity = flowdata.get('start/request_form/daysOfInactivity'); var someTimeAgo = new Date(); someTimeAgo.setDate( someTimeAgo.getDate() - daysOfInactivity ); result = "" + ( // make date 8-digit 10000 * someTimeAgo.getUTCFullYear() + 100 * (someTimeAgo.getMonth() +1) + someTimeAgo.getUTCDate() ) + ( // make time 8-digit 10000 * someTimeAgo.getUTCHours() + 100 * someTimeAgo.getUTCMinutes() + someTimeAgo.getUTCSeconds() ) + "Z"; } catch ( ex ) {} return( result ); } getCriterionDate(); - Query for Inactive Users
Here, we run the query, passing the calculated criterionDate as parameter. The query will return an unknown number of matching users, which we store in flowdata (flowdata.start/inactiveUsers/DNs).This is the code to run the query and store the list:
function getInactiveUsers() { var result = new java.util.Vector(); try { var daysOfInactivity = flowdata.get('start/request_form/daysOfInactivity'); var criterionDate = flowdata.get('start/criterionDate'); result = IDVault.globalQuery( "CoolSolution_inactiveUsers", {"someTimeAgo": criterionDate }); } catch ( ex ) {} return( result ); }; getInactiveUsers(); - Inactive Users Found
If no inactive users were found, we skip the next actions, jump to step i), and wait for the next polling loop on the next day.If inactive users were found, we continue with step e)
( flowdata.get('start/inactiveUsers/DNs').length > 0 ) - Get Next User
So, we have found a list of one or more inactive users.This step will simply get the first user from this list and store the DN in flowdata (flowdata.start/inactiveUsers/nextDN).
flowdata.get('start/inactiveUsers/DNs') - User Found?
This conditional activity checks if we have identified the next user in the list.The condition will return "true" as long there are more users to process; in this case, we'll continue with step g).
It will return "false", after all users have been processed; in this case we'll goto step i) to wait for the next polling loop on the next day.
( flowdata.get('start/inactiveUsers/nextDN').length > 0 ) - Disable this User
This entity activity will set the selected user's (flowdata.start/inactiveUsers/nextDN) attribute "Login Disabled" to true. - Remove this User from List
We have now just disabled the first user in the result list. In this step, we recalculate the list and remove the user that we have just processed.We continue with step e) to get the next user in the reduced list.
This code removes the first list entry:
function removeFirstElement() { var result = new java.util.Vector(); try { var objectsRemaining = flowdata.getObject('start/inactiveUsers/DNs') // start loop with second element for ( var i=1; i < objectsRemaining.size(); i++) { try { result.add( objectsRemaining.get(i).getFirstChild().getNodeValue() ); } catch (e) {} } } catch (e) {} return result; } ; removeFirstElement(); - Await Next Scan
We have now processed all users in the list, coming from step d) or from step f), we will use this dummy approval activity to wait for its timeout, i.e., for the next polling interval.If the selected addressee does nothing, the workflow will timeout and continue with step b)
If an admin opens the approval form and presses "Deny Request", the whole workflow ends with step j)
- We're done
The sample workflow for this article has been attached and can be imported into designer.
It consists of
- the workflow with forms and logic
- a test user entity with the required attributes
- the query for inactive users
- a request form
- an approval form
If you are not working with Novell's demo environment "Utopia", you will probably have to modify the trustees of the workflow and the search base for the query.
Developed and tested on Identity Manager version 3.7.0
| Allegato | Dimensione |
|---|---|
| Cool_Solutions_-_Loop_Route_-_Disable_Inactive_Users.zip | 19.3 KB |
Disclaimer: As with everything else at Cool Solutions, this content is definitely not supported by Novell (so don't even think of calling Support if you try something and it blows up).
It was contributed by a community member and is published "as is." It seems to have worked for at least one person, and might work for you. But please be sure to test, test, test before you do anything drastic with it.
Related Articles
- HowTo: Execute Workflow Activities at a Specified Date in User Application
- HowTo: Make your Move (in IDM Workflows)
- HowTo: Execute Workflow Activities with Custom Delays in User Application
- HowTo: IDM - Replace the Default Object Selector with a Simple Custom Search
- Practical example - Web Services integration: Frontrange Heat
User Comments
Correction
Submitted by jlazer on 20 October 2010 - 11:12am.
Hi,
I am confusing with the below statement, if you are quering loginDisabled == true, then finally you are setting loginDisabled == true through entity.
"The sample query is named "CoolSolution_inactiveUsers" and perform a search on the container "OU=users,O=utopia" with a filter "( && ( loginDisabled == true )( loginTime < [param] ))"
pls correct it. may be its loginDisabled not equal to True in the query.
- Be the first to comment! To leave a comment you need to Login or Register







1