Introduction

The purpose of this task is to free up licenses consumed by externally disabled user accounts, i.e. user accounts that are disabled in the Active Directory.

The task can be found by navigating to the task, then scrolling down to the task "Release licenses from disabled accounts";

Task Parameters

The task parameters are used by the task script to determine which tokens are to be deleted and are edited by left clicking on the context menu of the task and selecting "Parameters";

A new window titled "Task Parameters" will now open that lists the parameters making them available for editing, and the default parameters for this task are as follows;







If provided, this property will specify the Domain for which users within this domain will receive PIN notification.




If provided, this property will specify the Unit for which users within this domain will receive PIN notification.





If provided, this property will specify the Group for which users within this domain will receive PIN notification.





The parameters may then be editing by selecting one of the parameters, then clicking on the button.


Editing and Scheduling the Task

Viewing and Editing the task

The task can be edited by left clicking on the context menu of the task and selecting "Edit";

A new window will not open titled "Task - Edit";







Enter the name to be assigned to the task within the management console.





Enter a description of what the task will do.





The version number of the task.





This field is used to specify when the task is scheduled to execute.





This field will determine if the task schedule is enabled (if enabled the task will execute at the scheduled time).





Specifies how many times the task should be repeated after the task is executed.






                import com.deepnet.das.exception.DasParameterErrorException
                import com.deepnet.das.user.User
                import com.deepnet.das.user.LdapUser
                import com.deepnet.das.domain.*
                import java.util.Date
                import com.deepnet.das.util.*
                import com.unboundid.ldap.sdk.*
                import com.deepnet.das.identitysource.*
                import com.deepnet.das.token.TokenAssignment

                def result, failed = false
                def errMsg = ""
                def list = getDomains(domainName)
                int count = 0;
                int total = 0;
                def content = ""
                def f = createDIRAndFile()
                f.append('"Name", "Login name", "Domain name"\r\n')

                for (def domain : list) {
                        try {
                                Iterator itr = createIteratorForDisabledUser(domain, unitName, groupName)
                                onProgress(0, "Preparing...")

                                def usersToQuery = new ArrayList(100)
                                def idsToUpdate = new ArrayList(100)

                                while (itr.hasNext()) {
                                        def user = itr.next()

                                        total++
                                        usersToQuery << user

                                        // query usres in 100 per batch
                                        if(usersToQuery.size()>=100){
                                                def users = batchQueryUsers(usersToQuery)
                                                idsToUpdate.addAll(users*.userID)
                                                count += users.size()
                                                outputToCSV(users, f)
                                                usersToQuery.clear()
                                        }

                                        if(idsToUpdate.size()>=100){
                                                LdapUser.executeUpdate("update LdapUser user set user.status='DISABLED' where user.userID in :list and user.domain.id=:domainId", [list:idsToUpdate, domainId:domain.id])
                                                idsToUpdate.clear()
                                                LdapUser.withSession { it.clear() }
                                        }

                                        //println("Users updated:  " + count + "/" + total)
                                        onProgress(count, "Users updated:  " + count + "/" + total)
                                }

                                // query left over users
                                if(usersToQuery.size()>0){
                                        def users = batchQueryUsers(usersToQuery)
                                        idsToUpdate.addAll(users*.userID)
                                        count += users.size()
                                        outputToCSV(users, f)
                                        usersToQuery.clear()
                                }

                                // update left over users
                                if(idsToUpdate.size()>0){
                                        LdapUser.executeUpdate("update LdapUser user set user.status='DISABLED' where user.userID in :list and user.domain.id=:domainId", [list:idsToUpdate, domainId:domain.id])
                                        idsToUpdate.clear()
                                        LdapUser.withSession { it.clear() }
                                }

                        } catch(Exception e) {
                                errMsg += e.message + ", "
                        }
                }

                def msg =  "Disabled: " + count + '/' + total + " users. "
                if (errMsg)
                        msg += "Errors: ${errMsg}"
                setEndMessage(msg)

                def outputToCSV(def users, def f){
                        users.each{
                                //println 'updated: ' + it.status + ' ' + it.dn + ' ' + it.fullName
                                f.append("\"${it.fullName}\", \"${it.loginName}\", \"${it.domain.name}\"\r\n")
                        }
                }

                def batchQueryUsers(def usersToQuery){
                        def idsNotDisabled = LdapUser.executeQuery("select userID from LdapUser user where user.userID in :list and user.status != 'DISABLED'", [list:usersToQuery*.userID])
                        return idsNotDisabled ? usersToQuery.findAll{ it.userID in idsNotDisabled } : []
                }

                def batchQueryUsersWithSideEffect(def usersToQuery, def idsToUpdate, def count, def f){
                        def idsNotDisabled = LdapUser.executeQuery("select userID from LdapUser user where user.userID in :list and user.status != 'DISABLED'", [list:usersToQuery*.userID])
                        if(idsNotDisabled.size() > 0){

                                idsToUpdate.addAll(idsNotDisabled)
                                count += idsNotDisabled.size()

                                usersToQuery.findAll{ it.userID in idsNotDisabled }.each{
                                        //println 'updated: ' + it.status + ' ' + it.dn
                                        f.append("\"${it.fullName}\", \"${it.loginName}\", \"${it.domain.name}\"\r\n")
                                }
                        }
                }

                def getDomains(def domainName) {

                        def list = Domain.list().findAll{it.identitySource.type == IdentitySourceType.LDAP }
                        if (domainName && list) {
                                list = list.findAll {
                                        it.name == domainName
                                }
                        }
                        return list
                }

                def createDIRAndFile() {
                        def exportFolder = ConfigLoader.getProperty('dual/export/directory')
                        def sep = System.getProperty('file.separator')
                        if(!exportFolder){
                                def catalinaBase = System.properties.getProperty('catalina.base')
                                exportFolder = catalinaBase.substring(0, catalinaBase.lastIndexOf(sep)) + sep + 'export'
                        }
                        def dir = new File(exportFolder)
                        if(!dir.exists()){
                                dir.mkdir()
                        }
                        return new File(exportFolder + sep + "Disabled-Users-" + new Date().format( 'ddMMyy-HHmmss' ).toString() + ".csv")
                }

                Iterator createIteratorForDisabledUser(def domain, def unitName = null, def groupName = null) {
                        def ids = domain.identitySource
                        return ids.queryLdapUsersLiterally(getBaseDN(ids, unitName), searchLdap(ids, groupName), domain, null, false, 100)
                }

                Filter searchLdap(def ids, def groupName = null) {

                        def list = []
                        Filter f1 = Filter.createExtensibleMatchFilter("userAccountControl", "1.2.840.113556.1.4.803", false, "2")
                        list << f1

                        if (groupName) {
                                Filter f2 = Filter.createExtensibleMatchFilter(ids.memberOfAttribute, "1.2.840.113556.1.4.1941", false, getGroupBaseDN(ids, groupName))
                                list << f2
                        }
                        return Filter.createANDFilter(list)
                }

                def getGroupBaseDN(def ids, def groupName) {
                        if (!groupName) return null
                        def match = [["name", "=", groupName]]

                        def ele = ids.queryGroups(match, null)
                        if (!ele || !ele.rows) return null
                        if (ele.rows.size() > 1)
                                throw new DasParameterErrorException("Multiple groups found")
                        return ele.rows[0].dn
                }

                def getBaseDN(def ids, def unitName) {
                        if (!unitName) return null

                        def match = [["name", "=", unitName]]
                        def ele = ids.queryOUs("", match, false, [:])
                        if (!ele || !ele.rows) return null
                        if (ele.rows.size() > 1)
                                throw new DasParameterErrorException("Multiple units found")
                        return ele.rows[0].dn
                }





Scheduling the Task

Select the "Enable Schedule" checkbox to ensure the task schedule is activated, then use the pencil icon ("")  to specify the time and frequency settings for automated task execution.

Manual Task Execution

The task can be run manually from the management console by left click on the context menu of the task, then selecting "Run";

A new window will open titled "Run Task" will then open (the window will be populated with the default task property values);






Provide a brief description that will be used to describe the purpose of the task in the audit logs that should be retained in the database after the purge has been performed.





This property will specify the Domain for which users within this domain will receive PIN notification.





This property will specify the Unit for which users within this domain will receive PIN notification.





This property will specify the Group for which users within this domain will receive PIN notification.




To execute the task click  the  button.