Thursday, December 26, 2019

Sailpoint Identity IQ QuickLink WorkFlow Default Input

All the WorkFlow which are getting invoked from the Quicklink has below default input parameters.














currentUserName - Current User
launcher - Lanucher of this quicklink
quicklink - Name of the QuickLink
quickLinkIdentityId - Identity involved in this quicklink
quickLinkIdentityIds - Identity involved in this quicklink
sessionowner - Sessnion Owner
workflowName - WorkFlow which is getting trigger once we invoke the quicklink
trace - Logger for tracking
transient - Transient

Saturday, December 14, 2019

Sailpoint IIQ Quicklink Launch Workflow showing Form Value

Sailpoint IIQ Quicklink Launch Workflow showing Form Value

1. Create a quick link make sure the below category is created follow the step from the previous post

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE QuickLink PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<QuickLink action="workflow" category="Service Account Management" messageKey="Manage Service Account" name="Service Account View QuickLink">
  <Attributes>
    <Map>
      <entry key="workflowName" value="Service Account View Workflow"/>
    </Map>
  </Attributes>
  <Description>QuickLink to View Service Account in IIQ table</Description>
  <QuickLinkOptions allowSelf="true">
    <DynamicScopeRef>
      <Reference class="sailpoint.object.DynamicScope" name="Self Service"/>
    </DynamicScopeRef>
  </QuickLinkOptions>
</QuickLink>










2.Import the form created in the previous post

3.import the below Workflow

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Workflow PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Workflow explicitTransitions="true" name="Service Account View Workflow">
  <Variable editable="true" input="true" name="launcher">
    <Description>Launcher name.</Description>
  </Variable>
  <Variable initializer="true" name="transient"/>
  <Variable initializer="true" name="trace">
    <Description>Used for debugging this workflow and when set to true trace
      will be sent to stdout.</Description>
  </Variable>
  <Step icon="Start" name="Start" posX="229" posY="21">
    <Transition to="Display Form"/>
  </Step>
  <Step icon="Approval" name="Display Form" posX="427" posY="21">
    <Approval mode="serial" name="Display Form" owner="ref:launcher">
      <Arg name="workItemType" value="Approval"/>
      <Arg name="workItemDescription" value="Service Account Details"/>
      <Arg name="workItemForm" value="string:Service Account Details Form"/>
      <Arg name="workItemFormBasePath"/>
    </Approval>
    <Description>
       Display the Service Account form .
    </Description>
    <Transition to="Stop"/>
  </Step>
  <Step icon="Stop" name="Stop" posX="611" posY="21"/>
</Workflow>










Thursday, December 12, 2019

Active Directory Authentication Error Codes

When authentication fails while using Active Directory , Active Directory returns its own error codes to indicate 
the reason for the failure; you must retrieve and handle or display these errors appropriately. 

Below are some of the most common errors you may receive, including example error messages and reasons for the error.
525 - user not found
52e - invalid credentials
530 - not permitted to logon at this time
532 - password expired
533 - account disabled
701 - account expired
773 - user must reset password
775 - account locked

525 - user not found - 
Returned when an invalid username is supplied.
80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 525, v893
HEX: 0x525 - user not found
DEC: 1317 - ERROR_NO_SUCH_USER (The specified account does not exist.)

52e - invalid credentials
Returned when a valid username is supplied but an invalid password/credential is supplied. If this error is received, 
it will prevent most other errors from being displayed
80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 52e, v893
HEX: 0x52e - invalid credentials
DEC: 1326 - ERROR_LOGON_FAILURE (Logon failure: unknown user name or bad password.)

530 - not permitted to logon at this time
Returned when a valid username and password/credential are supplied during times when login is restricted.
80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 530, v893
HEX: 0x530 - not permitted to logon at this time
DEC: 1328 - ERROR_INVALID_LOGON_HOURS (Logon failure: account logon time restriction violation.

531 - not permitted to logon from this workstation
Returned when a valid username and password/credential are supplied, but the user is restricted from using the workstation 
where the login was attempted.
80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 531, v893
HEX: 0x531 - not permitted to logon from this workstation
DEC: 1329 - ERROR_INVALID_WORKSTATION (Logon failure: user not allowed to log on to this computer.)
LDAP[userWorkstations: <multivalued list of workstation names>]
 
 
532 - password expired
Returned when a valid username is supplied, and the supplied password is valid but expired.
80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 532, v893
HEX: 0x532 - password expired
DEC: 1330 - ERROR_PASSWORD_EXPIRED (Logon failure: the specified account password has expired.)
LDAP[userAccountControl: <bitmask=0x00800000>] - PASSWORDEXPIRED

533 - account disabled
Returned when a valid username and password/credential are supplied but the account has been disabled.
80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 533, v893
HEX: 0x533 - account disabled
DEC: 1331 - ERROR_ACCOUNT_DISABLED (Logon failure: account currently disabled.)
LDAP[userAccountControl: <bitmask=0x00000002>] - ACCOUNTDISABLE

701 - account expired
Returned when a valid username and password/credential are supplied but the account has expired.
80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 701, v893
HEX: 0x701 - account expired
DEC: 1793 - ERROR_ACCOUNT_EXPIRED (The user's account has expired.)
LDAP[accountExpires: <value of -1, 0, or extemely large value indicates account will not expire>] - ACCOUNTEXPIRED

773 - user must reset password
Returned when a valid username and password/credential are supplied, but the user must change their password immediately
(before logging in for the first time, or after the password was reset by an administrator).
80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 773, v893
HEX: 0x773 - user must reset password
DEC: 1907 - ERROR_PASSWORD_MUST_CHANGE (The user's password must be changed before logging on the first time.)
LDAP[pwdLastSet: <value of 0 indicates admin-required password change>] - MUST_CHANGE_PASSWD

775 - account locked out
Returned when a valid username is supplied, but the account is locked out. Note that this error will be returned regardless 
of whether or not the password is invalid.
80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 775, v893
HEX: 0x775 - account locked out
DEC: 1909 - ERROR_ACCOUNT_LOCKED_OUT (The referenced account is currently locked out and may not be logged on to.)
LDAP[userAccountControl: <bitmask=0x00000010>] - LOCKOUT

Sailpoint IIQ Form - Reading Value from IIQ Database


Below is the sample Form in which most of the value of the field is read from the IIQ Custom 
Table DB . in the previous posts we have seen the sample code for reading the data from IIQ Database.
Create a Table in IIQ Database name VIS_SERVICE_ACCOUNT with below fields

ACCOUNT_ID
APPLICATION_NAME
ACCOUNT_DESCRIPTION
OWNER
INTERACTIVE


    
    
    <?xml version='1.0' encoding='UTF-8'?>
    <!DOCTYPE Form PUBLIC "sailpoint.dtd" "sailpoint.dtd">
    <Form name="Service Account Details Form" type="Workflow">
      <Attributes>
        <Map>
          <entry key="pageTitle" value="Service Account Details Form"/>
        </Map>
      </Attributes>
      <Section>
        <Field displayName="Account Identifier" helpKey="Account ID of Service Account" name="accountID" postBack="true" required="true" type="string">
          <AllowedValuesDefinition>
            <Script>
              <Source>
       import sailpoint.tools.Util;
       import sailpoint.tools.GeneralException;
       import org.apache.log4j.Logger;
    
       Logger logger= Logger.getLogger("vis.form.ServiceAccount.fields");
    
       List itemList = new ArrayList();
                
       try{
    
       String  columnSearch = "ACCOUNT_ID";
       String  tableName = "VIS_SERVICE_ACCOUNT";
       String  conditionColumnName = "ACCOUNT_ID";
       String  sqlStatement ="select "+columnSearch+" from "+tableName;
       Iterator it = context.search("sql:"+sqlStatement, null,null);
    
        while ((null != it) &amp;&amp; it.hasNext()) {
          String i= it.next();
          if(!itemList.contains(i)) {
           itemList.add(i);
          }
        }
       Util.flushIterator(it);
       }
       catch(GeneralException ex){
        logger.error("Error in AppEdit form : " +ex.getMessage());
       }
       return itemList;
              </Source>
            </Script>
          </AllowedValuesDefinition>
        </Field>
        <Field displayName="Application Name" displayType="combobox" helpKey="Application Name of the Service Account" name="applicationName" postBack="true" required="true" type="string">
          <AllowedValuesDefinition>
            <Script>
              <Source>
       import sailpoint.tools.Util;
       import sailpoint.tools.GeneralException;
       import org.apache.log4j.Logger;
    
       Logger logger= Logger.getLogger("vis.form.ServiceAccount.fields");
       List itemList = new ArrayList();
                
       try{
    
       String  columnSearch = "APPLICATION_NAME";
       String  tableName = "VIS_SERVICE_ACCOUNT";
       String  conditionColumnName = "ACCOUNT_ID";
       String  sqlStatement ="select "+columnSearch+" from "+tableName + " where ACCOUNT_ID ='"+ accountID + "'";
                System.out.println("sqlStatement = " + sqlStatement);
       Iterator it = context.search("sql:"+sqlStatement, null,null);
    
        while ((null != it) &amp;&amp; it.hasNext()) {
          String i= it.next();
          itemList.add(i);
        }
       Util.flushIterator(it);
       }
       catch(GeneralException ex){
        logger.error("Error in AppEdit form : " +ex.getMessage());
       }
       return itemList;
              </Source>
            </Script>
          </AllowedValuesDefinition>
          <Attributes>
            <Map>
              <entry key="hidden">
                <value>
                  <Script>
                    <Source>if(accountID==null || accountID ==void){
                      return true;
                    }</Source>
                  </Script>
                </value>
              </entry>
            </Map>
          </Attributes>
        </Field>
        <Field displayName="Account Description" dynamic="true" helpKey="Description of Service Account" name="accountDescription" type="string">
          <Attributes>
            <Map>
              <entry key="hidden">
                <value>
                  <Script>
                    <Source>if(accountID==null || accountID ==void || applicationName==null || applicationName ==void){
                      return true;
                    }</Source>
                  </Script>
                </value>
              </entry>
              <entry key="readOnly" value="true"/>
            </Map>
          </Attributes>
          <Script>
            <Source>
              if(accountID!=null){
         String  columnSearch = "ACCOUNT_DESCRIPTION";
         String  tableName = "VIS_SERVICE_ACCOUNT";
         String  conditionColumnName = "ACCOUNT_ID";
         String  sqlStatement ="select "+columnSearch+" from "+tableName+" where "+conditionColumnName+"='"+accountID+"'"+" and APPLICATION_NAME ='"+applicationName+"'";
         Iterator  itr = context.search("sql:"+sqlStatement, null,null);
         while(itr.hasNext()){
          String accountDescription =  itr.next();
          if(accountDescription!=null){
         return accountDescription;
          }
         }
             }
            </Source>
          </Script>
        </Field>
        <Field displayName="Account Owner" dynamic="true" helpKey="Owner of the Service Account" name="owner" type="sailpoint.object.Identity">
          <Attributes>
            <Map>
              <entry key="hidden">
                <value>
                  <Script>
                    <Source>if(accountID==null || accountID ==void || applicationName==null || applicationName ==void){
                      return true;
                    }</Source>
                  </Script>
                </value>
              </entry>
              <entry key="readOnly" value="true"/>
            </Map>
          </Attributes>
          <Script>
            <Source>         
            if(accountID!=null){
         String  columnSearch = "OWNER";
         String  tableName = "VIS_SERVICE_ACCOUNT";
         String  conditionColumnName = "ACCOUNT_ID";
         String  sqlStatement ="select "+columnSearch+" from "+tableName+" where "+conditionColumnName+"='"+accountID+"'"+" and APPLICATION_NAME ='"+applicationName+"'";
         Iterator  itr = context.search("sql:"+sqlStatement, null,null);
         while(itr.hasNext()){
          String owner =  itr.next();
          if(owner!=null){
         return owner;
          }
         }
              }</Source>
          </Script>
        </Field>
        <Field displayName="Interactive" dynamic="true" helpKey="Service Account is Interactive or Non-Interactive" name="interactive" type="string">
          <AllowedValuesDefinition>
            <Value>
              <List>
                <String>Yes</String>
                <String>No</String>
              </List>
            </Value>
          </AllowedValuesDefinition>
          <Attributes>
            <Map>
              <entry key="hidden">
                <value>
                  <Script>
                    <Source>if(accountID==null || accountID ==void || applicationName==null || applicationName ==void){
                      return true;
                    }</Source>
                  </Script>
                </value>
              </entry>
              <entry key="readOnly" value="true"/>
            </Map>
          </Attributes>
          <Script>
            <Source>
              if(accountID!=null){
         String  columnSearch = "INTERACTIVE";
         String  tableName = "VIS_SERVICE_ACCOUNT";
         String  conditionColumnName = "ACCOUNT_ID";
         String  sqlStatement ="select "+columnSearch+" from "+tableName+" where "+conditionColumnName+"='"+accountID+"'"+" and APPLICATION_NAME ='"+applicationName+"'";
         Iterator  itr = context.search("sql:"+sqlStatement, null,null);
         while(itr.hasNext()){
          String interactive =  itr.next();
          if(interactive!=null){
         return interactive;
          }
         }
              }
            </Source>
          </Script>
        </Field>
      </Section>
      <Button action="back" label="Cancel"/>
    </Form>
    




    Wednesday, November 27, 2019

    Sailpoint Identity IQ Reading Data from Custom Table

    Reading Data from the Custom Table created in the Sailpoint identity IQ Database ,
    Once the table is created within the IdentityIQ database, it can be queried like any JDBC connection.  However, the advantage of using a table within the IdentityIQ database is that the connection to the database can be obtained from the IIQ context rather than having to store the URL, username, and password within the code itself.

    Below sample code can be used in any places , such as showing the data in the Form (from custom table) , Rules or Workflow

       List itemList = new ArrayList();
                
       try{
    
       String  columnSearch = "ACCOUNT_ID";
       String  tableName = "VIS_SERVICE_ACCOUNT";
       String  conditionColumnName = "ACCOUNT_ID";
       String  sqlStatement ="select "+columnSearch+" from "+tableName;
       Iterator it = context.search("sql:"+sqlStatement, null,null);
    
        while ((null != it) &amp;amp;&amp;amp; it.hasNext()) {
          String i= it.next();
          if(!itemList.contains(i)) {
           itemList.add(i);
          }
        }
       Util.flushIterator(it);
       }
       catch(GeneralException ex){
        logger.error("Error in form : " +ex.getMessage());
       }
       return itemList;
    


    Monday, November 18, 2019

    Sailpoint IIQ Audit WorkFlow using OOTB Audit Method

    If you want to add custom auditing to existing Audit method in a workflow or any where in the call etc., it's as easy as below, creating and call a audit method and setting the Action, Source, Target and values.

    Here we need to make sure that we are adding proper action and source so that it's easily tracked.  

    <Step action="call:audit" icon="Audit" name="Audit" posX="920" posY="91">
        <Arg name="string1" value="value1"/>
        <Arg name="string2" value="value2"/>
        <Arg name="string3" value="value3"/>
        <Arg name="string4" value="value4"/>
        <Arg name="action" value="Service Account Management"/>
        <Arg name="source" value="Service Account Management"/>
        <Arg name="target" value="spadmin"/>
        <Description>This step is use to Audit the Operation performed and the Values set during the operation.</Description>
        <Transition to="Stop"/>
      </Step>
    


    Enable the Audit from the Audit Config Object from the Sailpoint IIQ Debug Page  








    Use the Advance Analytics and Use Search Type as Audit to see the Entry


    Sunday, October 13, 2019

    Sailpoint Identity IQ Calling Rule from Anywhere API

    Calling a Rule from anywhere either it's from any Rule, Work Flow, LCM Provisioning 

    Java Code

    public void runRule(SailPointContext context) throws GeneralException{
                 Rule TestRule = context.getObject(Rule.class,"TestRule1");
                 HashMap ruleParam = new HashMap();
                 ruleParam.put("log",null);
                 ruleParam.put("context",context);
    
                 ruleParam.put("name","Vishal");
                 String name  = (String) context.runRule(TestRule ,ruleParam);
                 System.out.println("name : " + name);
           }
    

    Rule :TestRule1


    <?xml version='1.0' encoding='UTF-8'?>
    <!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
    <Rule  language="beanshell"  name="TestRule1">
      <Signature>
        <Inputs>
          <Argument name="log">
            <Description>
              The log object associated with the SailPointContext.
            </Description>
          </Argument>
          <Argument name="context">
            <Description>
              A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
            </Description>
          </Argument>
          <Argument name="name">
            <Description>
              name value from the place where this is called.
            </Description>
          </Argument>
        </Inputs>
      </Signature>
      <Source>
      return name + "Kejriwal";
      </Source>
    </Rule>
    

    Output

    name : VishalKejriwal

    Thursday, October 10, 2019

    Sailpoint IQ Active Directory Application Integration Using OOTB Connector - Aggregation

    Integration of Active Directory with SailPoint IIQ

    Check this blogpost for the Active Directory Provisioning 

    Navigate to Application → New Application
    Select Application Type as Active Directory-Direct and provide the Application Name and Owner Field



    Enter the Forest Name , Global Catalog Server ie DC and the credentials of the service Account , Add the above entered Forest details and Click on Discover to get all the Domains Available in the Forest.



    Here we can add and remove the Domain which we want to manage from this Application



    Here we can add and remove account OU which we are managing from the above Domains



    Here we can add Groups OU which we are managing from the above Domains



    Test the Target Application Connectivity



    Create the correction Rule , based on which user need to be linked from the Active Directory to the Sailpoint.



    Create the Group Aggregation Task to pull all the Entitlement from Active Directory and click on save and Run.



    we can check all the Entitlements Aggregated from Active Directory in Applications Entitlement Catalog




    Create the Account Aggregation Task to pull all the Users Accounts from Active Directory and click on save and Run.



    we can check all the Accounts Aggregated from Active Directory in Applications Edit Application Accounts Tab






    Tuesday, October 1, 2019

    SAILPOINT IDENTITY IQ ALL WORKFLOW AND SUB WORKFLOW

    SAILPOINT IDENTITY IQ ALL WORKFLOW AND SUB WORKFLOW 

    Below is the List of all the OOTB Sub workflow which is getting called from the main workflow
    ==========================================================
    Workflow:LCM Provisioning
            Identity Request Initialize
                    Identity Request Violation Review
                    Do Provisioning Forms
            Manage Ticket
                    Provision with retries
            Provisioning Approval Subprocess
            Approve and Provision Subprocess
                    Provisioning Approval Subprocess
                    Manage Ticket
                            Provision with retries
                    Identity Request Provision
                            Do Provisioning Forms
                            Provision with retries
                            Check Status of queued items
                    Manage Ticket
                            Provision with retries
            Approve and Provision Subprocess
                    Provisioning Approval Subprocess
                    Manage Ticket
                            Provision with retries
                    Identity Request Provision
                            Do Provisioning Forms
                            Provision with retries
                            Check Status of queued items
                    Manage Ticket
                            Provision with retries
            Identity Request Notify
            Identity Request Finalize
                    Manage Ticket
                            Provision with retries


    ==========================================================
    Workflow:LCM Create and Update
            Identity Request Initialize
                    Identity Request Violation Review
                    Do Provisioning Forms
            Manage Ticket
                    Provision with retries
            Identity Request Approve Identity Changes
            Manage Ticket
                    Provision with retries
            Identity Request Provision
                    Do Provisioning Forms
                    Provision with retries
                    Check Status of queued items
            Manage Ticket
                    Provision with retries
            Identity Request Notify
            Identity Request Finalize
                    Manage Ticket
                            Provision with retries


    ==========================================================
    Workflow:LCM Registration
            LCM Create and Update
                    Identity Request Initialize
                            Identity Request Violation Review
                            Do Provisioning Forms
                    Manage Ticket
                            Provision with retries
                    Identity Request Approve Identity Changes
                    Manage Ticket
                            Provision with retries
                    Identity Request Provision
                            Do Provisioning Forms
                            Provision with retries
                            Check Status of queued items
                    Manage Ticket
                            Provision with retries
                    Identity Request Notify
                    Identity Request Finalize
                            Manage Ticket
                                    Provision with retries


    ==========================================================
    Workflow:LCM Manage Passwords
            Identity Request Initialize
                    Identity Request Violation Review
                    Do Provisioning Forms
            Manage Ticket
                    Provision with retries
            Identity Request Provision
                    Do Provisioning Forms
                    Provision with retries
                    Check Status of queued items
            Manage Ticket
                    Provision with retries
            Identity Request Notify
            Identity Request Finalize
                    Manage Ticket
                            Provision with retries


    ==========================================================
    Workflow:Approve and Provision Subprocess
            Provisioning Approval Subprocess
            Manage Ticket
                    Provision with retries
            Identity Request Provision
                    Do Provisioning Forms
                    Provision with retries
                    Check Status of queued items
            Manage Ticket
                    Provision with retries


    ==========================================================
    Workflow:Approve and Provision Subprocess
            Provisioning Approval Subprocess
            Manage Ticket
                    Provision with retries
            Identity Request Provision
                    Do Provisioning Forms
                    Provision with retries
                    Check Status of queued items
            Manage Ticket
                    Provision with retries


    ==========================================================
    Workflow:Batch Request Wrapper
            Identity Request Approve


    ==========================================================
    Workflow:Do Provisioning Forms


    ==========================================================
    Workflow:Do Manual Actions


    ==========================================================
    Workflow:Provision with retries


    ==========================================================
    Workflow:Check Status of queued items


    ==========================================================
    Workflow:Manage Ticket
            Provision with retries


    ==========================================================
    Workflow:Role Modeler - Impact Analysis


    ==========================================================
    Workflow:Role Modeler - Owner Approval


    ==========================================================
    Workflow:Identity Refresh
            Do Provisioning Forms
            Do Manual Actions


    ==========================================================
    Workflow:Identity Update
            Do Provisioning Forms
            Do Manual Actions


    ==========================================================
    Workflow:Scheduled Assignment
            Do Provisioning Forms
            Provision with retries
            Do Manual Actions


    ==========================================================
    Workflow:Scheduled Role Activation


    ==========================================================
    Workflow:Entitlement Update


    ==========================================================
    Workflow:Password Intercept
            Provision with retries


    ==========================================================
    Workflow:Alert - Disable Account


    ==========================================================
    Workflow:Identity Correlation


    ==========================================================
    Workflow:Generic Step Library


    ==========================================================
    Workflow:Provisioning Approval Subprocess


    ==========================================================
    Workflow:IdentityProvisioningStepLibrary
            Provisioning Approval Subprocess


    ==========================================================
    Workflow:Identity Request Violation Review


    ==========================================================
    Workflow:Identity Request Initialize
            Identity Request Violation Review
            Do Provisioning Forms


    ==========================================================
    Workflow:Identity Request Approve


    ==========================================================
    Workflow:Identity Request Notify


    ==========================================================
    Workflow:Identity Request Provision
            Do Provisioning Forms
            Provision with retries
            Check Status of queued items


    ==========================================================
    Workflow:Identity Request Finalize
            Manage Ticket
                    Provision with retries


    ==========================================================
    Workflow:Identity Request Approve Identity Changes


    ==========================================================

    SAILPOINT IDENTITY IQ GET ALL SUB WORKFLOW FROM MAIN WORKFLOW


    SAILPOINT IDENTITY IQ API GET ALL SUB WORKFLOW FROM THE MAIN WORKFLOW

    Below Rule will get the name of all the Sub Workflow Getting called from the Master Workflow in Sailpoint IIQ

    Create the below Rule using the IIQ Debug Page

    <?xml version='1.0' encoding='UTF-8'?>
    <!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
    <Rule   language="beanshell"  name="List-Workflow-Subprocesses">
    <Description> </Description>
    <Source>
     <![CDATA[
    import java.util.Iterator; 
    import java.util.ArrayList;
    import sailpoint.api.*;
    import sailpoint.object.*;
    
    public void handleWorkflow(Workflow workflow, int level) {
    if (level == 0) { System.out.print("\n\n==========================================================\nWorkflow:");  }
    for (int i = 0; i<level; i++) {
    System.out.print("        "); 
    }
         System.out.println(workflow.getName()); 
         ArrayList steps = workflow.getSteps(); 
         Iterator iter = steps.iterator(); 
         while (iter.hasNext()) { 
               Workflow.Step step = (Workflow.Step)iter.next(); 
               Workflow sub = step.getSubProcess(); 
               if (sub != null) { 
                      handleWorkflow(sub,level +1); 
               } 
        }
    }
    QueryOptions qo = new QueryOptions(); 
    Iterator  iter = context.search(Workflow.class, qo); 
    while(iter.hasNext()){
        Workflow workflow = (Workflow)iter.next();
        handleWorkflow(workflow,0);    
    }
    ]]>
    </Source>
    </Rule>
    

    Select the Rule and click on the Run Rule Page and check the Catalina.out the file , It will show all the Sub- Workflow Name which is getting called from the Workflow, Below screenshot, shows all the Sub Workflow name getting called from the LCM Provisioning WF



    Below the screenshot of the Catalina.out file



    For Example below are the List of Sub Workflow which get called from the LCM Provisioning Workflow

    Workflow:LCM Provisioning
            Identity Request Initialize
                    Identity Request Violation Review
                    Do Provisioning Forms
            Manage Ticket
                    Provision with retries
            Provisioning Approval Subprocess
            Approve and Provision Subprocess
                    Provisioning Approval Subprocess
                    Manage Ticket
                            Provision with retries
                    Identity Request Provision
                            Do Provisioning Forms
                            Provision with retries
                            Check Status of queued items
                    Manage Ticket
                            Provision with retries
            Approve and Provision Subprocess
                    Provisioning Approval Subprocess
                    Manage Ticket
                            Provision with retries
                    Identity Request Provision
                            Do Provisioning Forms
                            Provision with retries
                            Check Status of queued items
                    Manage Ticket
                            Provision with retries
            Identity Request Notify
            Identity Request Finalize
                    Manage Ticket
                            Provision with retries