Skip Identity Provisioning Policy when Creating Identities with Batch Request

Version

8.4

Question

Hello everyone, I would like to ask about the Identity Provisioning Policy. Is there any way to skip it when creating an identity using a Batch Request?

Currently, I created a new workflow for the Batch Request that only shows the logs. However, after I created a new Identity Provisioning Policy, I can no longer create a new identity with the same CSV file, because it checks the headers and cannot find them since they don’t match the Identity Provisioning Policy.

How can I handle this?

This is my workflow — it has just one step for showing the logs.

But it still checks the Identity Provisioning Policy. I want to either skip it or make sure it doesn’t check against the Identity Provisioning Policy.

Hello everyone, does anyone know, or is it impossible?

Hi Thirphat,

I would suggest you add one step in the workflow to skip provisioning policy.

  
    
    <Step name="Skip Provisioning Policy">
        <Description>Disable provisioning policy checks</Description>
        <Script>
            <Source>
                import sailpoint.object.ProvisioningPlan;
                import sailpoint.object.ProvisioningProject;
                import sailpoint.workflow.WorkflowContext;
                
          
                log.info("Skipping provisioning policy validation for batch request");
                
                // Set the skip flag in context
                context.put("skipProvisioningPolicy", true);
                
                 // ADD THESE LINES - These actually skip the policy!
                if (project != null) {
                    project.setProvisioningPolicy(null);  // THIS removes the policy
                }
                
                if (plan != null) {
                    plan.setCheckPolicies(false);  // THIS disables policy checking
                }
                

            
                log.info("Successfully configured to skip provisioning policy");
            ]]></Source>
        </Script>
     

Try it and see if this works for you. If id does

Hi @naveenkumar3 , I added script into the step in my workflow already

after I tried to upload the files for Batch Request I got this

Caused by: org.apache.bsf.BSFException: BeanShell script error: bsh.EvalError: Sourced file: inline evaluation of: ``import sailpoint.object.ProvisioningPlan;                 import sailpoint.objec . . . '' : Error in method invocation: Method put(java.lang.String, boolean) not found in class'sailpoint.server.InternalContext' : at Line: 9 : in file: inline evaluation of: ``import sailpoint.object.ProvisioningPlan;                 import sailpoint.objec . . . '' : context .put ( "skipProvisioningPolicy" , true )

then I tried to remove context .put ( “skipProvisioningPolicy” , true ), I still got this

Caused by: org.apache.bsf.BSFException: BeanShell script error: bsh.EvalError: Sourced file: inline evaluation of: ``import sailpoint.object.ProvisioningPlan;                 import sailpoint.objec . . . '' : Error in method invocation: Method setProvisioningPolicy(null) not found in class'sailpoint.object.ProvisioningProject' : at Line: 11 : in file: inline evaluation of: ``import sailpoint.object.ProvisioningPlan;                 import sailpoint.objec . . . '' : project .setProvisioningPolicy ( null )

Does it wrong with my environment or something?

No This is wrong. Can you go to debug, and share me the workflow xml.

I will see and correct it and share it to you.

Hi @naveenkumar3 , this is my workflow xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Workflow PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Workflow configForm="Provisioning Workflow Config Form" created="1755577523742" explicitTransitions="true" handler="sailpoint.api.StandardWorkflowHandler" id="7f00010198bb1a8d8198c0931e1e0471" libraries="Identity,BatchRequest" modified="1756441713539" monitored="true" name="LCM Create and Update test with Batch" significantModified="1756441713539" taskType="LCM" type="LCMIdentity">
  <Variable input="true" name="identityName">
    <Description>The name of the identity we&amp;#39;re supposed to update.</Description>
  </Variable>
  <Variable initializer="script:(identityDisplayName != void) ? identityDisplayName : resolveDisplayName(identityName)" input="true" name="identityDisplayName">
    <Description>The displayName of the identity being updated.
      Query for this using a projection query and fall back to the name.</Description>
  </Variable>
  <Variable initializer="false" input="true" name="endOnManualWorkItems">
    <Description>Option to skip requests with manual work items.</Description>
  </Variable>
  <Variable initializer="false" input="true" name="endOnProvisioningForms">
    <Description>Option to skip requests with provisioning forms.</Description>
  </Variable>
  <Variable input="true" name="batchRequestItemId">
    <Description>Used by the batch interface to record back individual request item status. The specific item id for the individual request in the batch file.</Description>
  </Variable>
  <Variable input="true" name="plan">
    <Description>The provisioning plan ready to execute.</Description>
  </Variable>
  <Variable input="true" name="flow">
    <Description>The name of the LCM flow that launched this workflow.

      This is one of these two values:

      IdentityCreateRequest
      IdentityEditRequest</Description>
  </Variable>
  <Variable editable="true" name="optimisticProvisioning">
    <Description>Set to true to enable optimistic provisioning.  This will cause
      changes to the entitlements compiled from role assignments to be
      applied immediately to the identity cube rather than waiting
      for the next refresh/reaggregation after the provisioning system
      completes the request.</Description>
  </Variable>
  <Variable editable="true" initializer="true" name="foregroundProvisioning">
    <Description>Normally provisioning is done in a step that uses the &amp;quot;background&amp;quot;
      option to force the workflow to be suspend and be resumed in a
      background task thread.  This prevents the browser session from
      hanging since provision can sometimes take a long time.  For demos
      and testing it can be better to do this in the foreground so that
      provisioning will have been performed when control is returned to the
      user.  This prevents having to run the Perform Maintenance task to
      see the results of the request.</Description>
  </Variable>
  <Variable editable="true" initializer="false" name="doRefresh">
    <Description>Set to true to cause an identity refresh after the changes in the plan
      have been provisioned.  This is normally off, you might want this on
      if you want modification of identity or link attributes to result in
      an immediate re-evaluation of assigned and detected roles.</Description>
  </Variable>
  <Variable initializer="Normal" input="true" name="workItemPriority">
    <Description>The String version of a WorkItem.Priority. This variable is
       used to set the priority on all of the workitems generated
       as part of this workflow and also set on the IdentityRequest
       object.</Description>
  </Variable>
  <Variable initializer="user, requester" input="true" name="notificationScheme">
    <Description>A string that specifies who should be notified when the request has been complete.
     The value can be null or a csv of one or more of the following options.

     none or null
       disable notifications

     user
       Identity that is being update will be notified.

     manager
       The manager of the Identity that is being updated will be notified.

     requester
       The person that has requested the update will be notified.</Description>
  </Variable>
  <Variable initializer="LCM User Notification" input="true" name="userEmailTemplate">
    <Description>The email template to use for user notification.</Description>
  </Variable>
  <Variable initializer="LCM Requester Notification" input="true" name="requesterEmailTemplate">
    <Description>The email template to use for requester notification.</Description>
  </Variable>
  <Variable initializer="LCM Manager Notification" input="true" name="managerEmailTemplate">
    <Description>The email template to use for manager notification.</Description>
  </Variable>
  <Variable input="true" name="securityOfficerEmailTemplate">
    <Description>The email template to use for security officer notification.</Description>
  </Variable>
  <Variable initializer="serial" input="true" name="approvalMode">
    <Description>A string that specifies how we should handle the approvals.

     By default this is serial since most of these request with
     the exception of manager transfers will have only one approver.

     parallel
       Approvals are processed concurrently and there must be consensus,
       we wait for all approvers to approve.  The first approver that
       rejects terminates the entire approval.

     parallelPoll
       Approvals are processed concurrently but consensus is not required.
       All approvals will be processed, we don&amp;#39;t stop if there are any
       rejections.

     serial
       Approvals are processed one at a time and there must be consensus.
       The first approver that rejects terminates the entire approval.

     serialPoll
       Approvals are processed in order but consensus is not required.
       All approvals will be processed, we don&amp;#39;t stop if there are any
       rejections.  In effect we are &amp;quot;taking a poll&amp;quot; of the approvers.

     any
      Approvals are processed concurrently, the first approver to
      respond makes the decision for the group.</Description>
  </Variable>
  <Variable initializer="manager, newManager" input="true" name="approvalScheme">
    <Description>A String that specifies how approvals should be generated for
      this workflow there are three built-in modes

      none - disabled approvals

      manager - The user&amp;#39;s current manager will get approvals

      newManager - The newly assigned manager will get approvals when
                   manager transfers occur. Otherwise the user&amp;#39;s manager
                   current manager will be the approver.</Description>
  </Variable>
  <Variable initializer="spadmin" input="true" name="fallbackApprover">
    <Description>A String that specifies the name of the Identity that will
      be assigned any approvals where the owner of the approver
      can&amp;#39;t be resolved. Example if the scheme is &amp;quot;owner&amp;quot; and the
      application doesn&amp;#39;t specify and owner.</Description>
  </Variable>
  <Variable initializer="LCM Identity Update Approval" input="true" name="approvalEmailTemplate">
    <Description>The email template to use for approval notifications.</Description>
  </Variable>
  <Variable input="true" name="securityOfficerName">
    <Description>The name of the identity that will be sent approvals
       during security officer approvals.</Description>
  </Variable>
  <Variable initializer="continue" input="true" name="policyScheme">
    <Description>A String that specifies how policy checks effect the overall
      process.

      none - disabled policy checking

      fail -  fail and exit the workflow if any policy violations are found

      continue -  continue if policy violations are found</Description>
  </Variable>
  <Variable input="true" name="ticketManagementApplication">
    <Description>Name of the application that can handle ticket requests.
      When non-null the Manage Ticket Steps will be visited to open
      tickets during the workflow lifecycle.</Description>
  </Variable>
  <Variable name="ticketId">
    <Description>The id of the ticket that is generated by the ticketingManagementApplication.
      This is typically generated on the &amp;quot;open&amp;quot; call, and then used in subsequent
      calls.  It is also stored on the IdentityRequest object under the
      externalTicketId variable.</Description>
  </Variable>
  <Variable input="true" name="policiesToCheck">
    <Description>A List of policies that should be checked. If this list is
      empty all violations will be checked. Used in combination
      with policyScheme.</Description>
  </Variable>
  <Variable name="policyViolations">
    <Description>List of policy violations that were found during our initial policy scan.
       This list is passed into each work item so the approvers can see
       pending violations.</Description>
  </Variable>
  <Variable initializer="LCM" input="true" name="source">
    <Description>String version of sailpoint.object.Source to indicate
      where the request originated.  Defaults to LCM.</Description>
  </Variable>
  <Variable name="approvalSet">
    <Description>This attributes is set during the &amp;quot;Build Approval Set&amp;quot; step,
       which builds this list by going through the ProvisioningPlan
       to build the line items that need to be approved,

       This variable includes all ApprovalItems that are part of
       the request process and is updated during the AfterScript
       of the approval process by assimilating the decisions
       and comments from the Approvals copy of the ApprovalItem.</Description>
  </Variable>
  <Variable initializer="false" name="trace">
    <Description>Used for debugging this workflow and when set to true trace
      will be sent to stdout.</Description>
  </Variable>
  <Variable name="project">
    <Description>ProvisioningProject which is just a compiled version of the ProvisioningPlan.</Description>
  </Variable>
  <Variable name="approvalForm">
    <Description>The form that is generated based on the changes that were made.  This
       form will be sent into the workitem and allow editing of the
       requested values during the approval process. This is generated
       in &amp;quot;Build Approval Form&amp;quot; based on the passed-in plan.</Description>
  </Variable>
  <Variable name="identityRequestId" output="true">
    <Description>The sequence id of the Identity request object which is stored in
       the name field of the identity request.</Description>
  </Variable>
  <Variable input="true" name="approverElectronicSignature">
    <Description>The name of the electronic signature object that should be used when workitems
       are completed by the batch approver when performing batch operations.</Description>
  </Variable>
  <RuleLibraries>
    <Reference class="sailpoint.object.Rule" id="7f00010196161e778196165f30ef018a" name="Approval Library"/>
    <Reference class="sailpoint.object.Rule" id="7f00010196161e778196165f39b2019d" name="LCM Workflow Library"/>
  </RuleLibraries>
  <Step icon="Start" monitored="true" name="Start" posX="14" posY="12">
    <Transition to="Build Approval Set"/>
  </Step>
  <Step action="rule:LCM Build Identity ApprovalSet" icon="Task" monitored="true" name="Build Approval Set" posX="97" posY="25" resultVariable="approvalSet">
    <Description>
       The rule will go through the plan and build an approvalItem for each AccountRequest,
       typically there is just one for the IIQ application requests.

       The rule will also annotate the plan with the previousValues so that they
       can be assimilated onto the Form that is build, which is used during the approval
       process for edits.

       Because this has some special handling keep it here in the workflow
       and pass the approval set into the initialization process.
    </Description>
    <Transition to="Initialize"/>
  </Step>
  <Step icon="Task" monitored="true" name="Initialize" posX="183" posY="12">
    <Arg name="formTemplate"/>
    <Arg name="identityName" value="ref:identityName"/>
    <Arg name="enableRetryRequest"/>
    <Arg name="allowRequestsWithViolations"/>
    <Arg name="endOnManualWorkItems" value="ref:endOnManualWorkItems"/>
    <Arg name="policiesToCheck" value="ref:policiesToCheck"/>
    <Arg name="approvalSet" value="ref:approvalSet"/>
    <Arg name="workItemPriority" value="ref:workItemPriority"/>
    <Arg name="workItemComments"/>
    <Arg name="source" value="ref:source"/>
    <Arg name="violationReviewDecision"/>
    <Arg name="policyScheme" value="ref:policyScheme"/>
    <Arg name="identityDisplayName" value="ref:identityDisplayName"/>
    <Arg name="requireViolationReviewComments"/>
    <Arg name="identityRequest"/>
    <Arg name="trace" value="ref:trace"/>
    <Arg name="batchRequestItemId" value="ref:batchRequestItemId"/>
    <Arg name="enableApprovalRecommendations"/>
    <Arg name="asyncCacheRefresh"/>
    <Arg name="endOnProvisioningForms" value="ref:endOnProvisioningForms"/>
    <Arg name="optimisticProvisioning" value="false"/>
    <Arg name="plan" value="ref:plan"/>
    <Arg name="flow" value="ref:flow"/>
    <Arg name="launcher" value="ref:launcher"/>
    <Description>
      Call the standard subprocess to initialize the request, this includes
      auditing, building the approvalset, compiling the plan into
      a project and checking policy violations.
    </Description>
    <Return name="policyViolations" to="policyViolations"/>
    <Return name="identityRequestId" to="identityRequestId"/>
    <Return name="project" to="project"/>
    <WorkflowRef>
      <Reference class="sailpoint.object.Workflow" id="7f00010196161e778196166021670316" name="Identity Request Initialize"/>
    </WorkflowRef>
    <Transition to="Exit On Manual Work Items" when="script:(isTrue(endOnManualWorkItems) &amp;&amp; (project.getUnmanagedPlan() != null))"/>
    <Transition to="Exit On Provisioning Form" when="script:(isTrue(endOnProvisioningForms) &amp;&amp; (project.hasQuestions()))"/>
    <Transition to="Exit On Policy Violation" when="script:((size(policyViolations) > 0 ) &amp;&amp; (policyScheme.equals(&quot;fail&quot;)))"/>
    <Transition to="Disable Provisioning"/>
  </Step>
  <Step condition="script:(ticketManagementApplication != null)" icon="Task" monitored="true" name="Create Ticket" posX="435" posY="7">
    <Arg name="trace" value="ref:trace"/>
    <Arg name="ticketManagementApplication" value="ref:ticketManagementApplication"/>
    <Arg name="project" value="ref:project"/>
    <Arg name="action" value="open"/>
    <Arg name="workItemPriority" value="ref:workItemPriority"/>
    <Arg name="identityRequestId" value="ref:identityRequestId"/>
    <Arg name="source" value="ref:source"/>
    <Arg name="ticketProject"/>
    <Arg name="ticketDataGenerationRule"/>
    <Arg name="ticketPlan"/>
    <Description>
      Call a subprocess to create a ticket in the ticketManagementApplication is non-null.
      You can specify a specific 'ticketDataGenerationRule' here or you can also specify
      it on the application.  It'll be read from the argument first and fall back to the '
      application config.
    </Description>
    <Return name="ticketId" to="externalTicketId"/>
    <WorkflowRef>
      <Reference class="sailpoint.object.Workflow" id="7f00010196161e778196165f34f90191" name="Manage Ticket"/>
    </WorkflowRef>
    <Transition to="Approve"/>
  </Step>
  <Step icon="Task" monitored="true" name="Approve" posX="488" posY="8">
    <Arg name="formTemplate"/>
    <Arg name="approvalScheme" value="ref:approvalScheme"/>
    <Arg name="identityName" value="ref:identityName"/>
    <Arg name="fallbackApprover" value="ref:fallbackApprover"/>
    <Arg name="approvalSet" value="ref:approvalSet"/>
    <Arg name="approvers"/>
    <Arg name="policyViolations" value="ref:policyViolations"/>
    <Arg name="workItemPriority" value="ref:workItemPriority"/>
    <Arg name="workItemComments"/>
    <Arg name="identityRequestId" value="ref:identityRequestId"/>
    <Arg name="identityDisplayName" value="ref:identityDisplayName"/>
    <Arg name="approvalMode" value="ref:approvalMode"/>
    <Arg name="trace" value="ref:trace"/>
    <Arg name="approvalForm"/>
    <Arg name="requireCommentsForDenial" value="ref:requireCommentsForDenial"/>
    <Arg name="approvalEmailTemplate" value="ref:approvalEmailTemplate"/>
    <Arg name="securityOfficerName" value="ref:securityOfficerName"/>
    <Arg name="approverElectronicSignature" value="ref:approverElectronicSignature"/>
    <Arg name="plan" value="ref:plan"/>
    <Arg name="requireCommentsForApproval" value="ref:requireCommentsForApproval"/>
    <Arg name="launcher" value="ref:launcher"/>
    <Description>
      Call the standard subprocess that will handle the built-in
      owner, manager and security officer approval schemes.
    </Description>
    <Return name="approvalSet"/>
    <Return name="plan"/>
    <Return name="workItemComments"/>
    <WorkflowRef>
      <Reference class="sailpoint.object.Workflow" id="7f00010196161e778196166022ec031b" name="Identity Request Approve Identity Changes"/>
    </WorkflowRef>
    <Transition to="Update Ticket Post Approval"/>
  </Step>
  <Step condition="script:(ticketManagementApplication != null)" icon="Task" monitored="true" name="Update Ticket Post Approval" posX="599" posY="8">
    <Arg name="trace" value="ref:trace"/>
    <Arg name="ticketManagementApplication" value="ref:ticketManagementApplication"/>
    <Arg name="project" value="ref:project"/>
    <Arg name="action" value="postApproval"/>
    <Arg name="workItemPriority" value="ref:workItemPriority"/>
    <Arg name="identityRequestId" value="ref:identityRequestId"/>
    <Arg name="source" value="ref:source"/>
    <Arg name="ticketProject"/>
    <Arg name="ticketId"/>
    <Arg name="ticketDataGenerationRule"/>
    <Arg name="ticketPlan"/>
    <Description>
      Call a subprocess to update the ticket in the ticketManagementApplication is non-null.

      You can specify a specific 'ticketDataGenerationRule' here or you can also specify
      it on the application.  It'll be read from the argument first and fall back to the '
      application config.

    </Description>
    <WorkflowRef>
      <Reference class="sailpoint.object.Workflow" id="7f00010196161e778196165f34f90191" name="Manage Ticket"/>
    </WorkflowRef>
    <Transition to="Process Approval Decisions"/>
  </Step>
  <Step action="call:processPlanApprovalDecisions" icon="Task" monitored="true" name="Process Approval Decisions" posX="764" posY="9" resultVariable="plan">
    <Arg name="disableAudit" value="true"/>
    <Arg name="approvalSet" value="ref:approvalSet"/>
    <Arg name="plan" value="ref:plan"/>
    <Transition to="Notify" when="script:approvalSet.hasRejected()"/>
    <Transition to="Recompile Project"/>
  </Step>
  <Step action="call:recompileProvisioningProject" icon="Task" monitored="true" name="Recompile Project" posX="913" posY="5" resultVariable="project">
    <Arg name="requester" value="ref:launcher"/>
    <Arg name="identityName" value="ref:identityName"/>
    <Arg name="workItemPriority" value="ref:workItemPriority"/>
    <Arg name="project" value="ref:project"/>
    <Arg name="source" value="ref:source"/>
    <Arg name="optimisticProvisioning" value="ref:optimisticProvisioning"/>
    <Arg name="plan" value="ref:plan"/>
    <Description>Recompile the provisioning project with the plan.
      The plan may contain modifications from the original plan if
      it was modified during the approval process.
      If you need to pass in provisioner options like "noFiltering"
      or "noRoleDeprovisioning" you must pass them as explicit
      arguments to the call.

      The evaluation options "requester" and "source" are commonly
      set here.

      You can also pass things into the Template and Field scripts by
      defining Args in this step.</Description>
    <Transition to="Provision"/>
  </Step>
  <Step icon="Task" monitored="true" name="Provision" posX="1014" posY="6">
    <Arg name="formTemplate" value="Identity Update"/>
    <Arg name="approvalScheme" value="ref:approvalScheme"/>
    <Arg name="identityName" value="ref:identityName"/>
    <Arg name="fallbackApprover" value="ref:fallbackApprover"/>
    <Arg name="approvalSet" value="ref:approvalSet"/>
    <Arg name="manualActionsEmailTemplate" value="Pending Manual Changes"/>
    <Arg name="workItemComments"/>
    <Arg name="workItemPriority" value="ref:workItemPriority"/>
    <Arg name="project" value="ref:project"/>
    <Arg name="policyViolations" value="ref:policyViolations"/>
    <Arg name="identityRequestId" value="ref:identityRequestId"/>
    <Arg name="policyScheme" value="ref:policyScheme"/>
    <Arg name="splitProvisioning"/>
    <Arg name="saveUnmanagedPlan"/>
    <Arg name="foregroundProvisioning" value="ref:foregroundProvisioning"/>
    <Arg name="noTriggers"/>
    <Arg name="identityDisplayName" value="ref:identityDisplayName"/>
    <Arg name="trace" value="ref:trace"/>
    <Arg name="saveUnmanagedPlan_WithProjectArgument"/>
    <Arg name="recompile" value="false"/>
    <Arg name="optimisticProvisioning" value="ref:optimisticProvisioning"/>
    <Arg name="plan"/>
    <Arg name="flow" value="ref:flow"/>
    <Arg name="launcher" value="ref:launcher"/>
    <Description>
      Call the standard subprocess that will process the
      approval decisions and do provisioning.  This
      includes calling any configured provisioning
      connectors and building manual actions.
    </Description>
    <Return name="project" to="project"/>
    <WorkflowRef>
      <Reference class="sailpoint.object.Workflow" id="7f00010196161e7781961660224c0319" name="Identity Request Provision"/>
    </WorkflowRef>
    <Transition to="Post Provision"/>
  </Step>
  <Step action="script:approvalSet.setAllProvisioned();" icon="Task" monitored="true" name="Post Provision" posX="1110" posY="7">
    <Description>
      Mark all of the items in the approvalset provisioned since these
      are all synchronous activities.
    </Description>
    <Transition to="Update Ticket Post Provision"/>
  </Step>
  <Step condition="script:(ticketManagementApplication != null)" icon="Task" monitored="true" name="Update Ticket Post Provision" posX="1111" posY="115">
    <Arg name="trace" value="ref:trace"/>
    <Arg name="ticketManagementApplication" value="ref:ticketManagementApplication"/>
    <Arg name="project" value="ref:project"/>
    <Arg name="action" value="postProvisioning"/>
    <Arg name="workItemPriority" value="ref:workItemPriority"/>
    <Arg name="identityRequestId" value="ref:identityRequestId"/>
    <Arg name="source" value="ref:source"/>
    <Arg name="ticketProject"/>
    <Arg name="ticketId"/>
    <Arg name="ticketDataGenerationRule"/>
    <Arg name="ticketPlan"/>
    <Description>
      Call a subprocess to update the ticket in the ticketManagementApplication is non-null.

      You can specify a specific 'ticketDataGenerationRule' here or you can also specify
      it on the application.  It'll be read from the argument first and fall back to the '
      application config.

    </Description>
    <WorkflowRef>
      <Reference class="sailpoint.object.Workflow" id="7f00010196161e778196165f34f90191" name="Manage Ticket"/>
    </WorkflowRef>
    <Transition to="Refresh Identity"/>
  </Step>
  <Step action="call:refreshIdentity" condition="ref:doRefresh" icon="Task" monitored="true" name="Refresh Identity" posX="954" posY="114">
    <Arg name="identityName" value="ref:identityName"/>
    <Arg name="provision" value="true"/>
    <Arg name="correlateEntitlements" value="true"/>
    <Arg name="synchronizeAttributes" value="true"/>
    <Description>
      Add arguments as necessary to enable refresh features.  Typically you only want this
      to correlate roles and possibly provision if we notice new assigned roles.
      Note that provisioning will be done in the Identity Refresh workflow so if there
      are any provisioning forms to display we won't feed them directly to the
      current user, they'll have to return to the inbox.
    </Description>
    <Transition to="Notify"/>
  </Step>
  <Step icon="Task" monitored="true" name="Notify" posX="830" posY="114">
    <Arg name="approvalScheme" value="ref:approvalScheme"/>
    <Arg name="identityName" value="ref:identityName"/>
    <Arg name="notificationScheme" value="ref:notificationScheme"/>
    <Arg name="userEmailTemplate" value="ref:userEmailTemplate"/>
    <Arg name="approvalSet" value="ref:approvalSet"/>
    <Arg name="policyViolations" value="ref:policyViolations"/>
    <Arg name="workItemPriority" value="ref:workItemPriority"/>
    <Arg name="source" value="ref:source"/>
    <Arg name="identityDisplayName" value="ref:identityDisplayName"/>
    <Arg name="trace" value="ref:trace"/>
    <Arg name="requesterEmailTemplate" value="ref:requesterEmailTemplate"/>
    <Arg name="securityOfficerName" value="ref:securityOfficerName"/>
    <Arg name="securityOfficerEmailTemplate" value="ref:securityOfficerEmailTemplate"/>
    <Arg name="plan" value="ref:plan"/>
    <Arg name="flow" value="ref:flow"/>
    <Arg name="managerEmailTemplate" value="ref:managerEmailTemplate"/>
    <Arg name="launcher" value="ref:launcher"/>
    <Description>
      Call the standard subprocess that will notify the various
      actors based on notification scheme.
    </Description>
    <WorkflowRef>
      <Reference class="sailpoint.object.Workflow" id="7f00010196161e778196166021f50318" name="Identity Request Notify"/>
    </WorkflowRef>
    <Transition to="end"/>
  </Step>
  <Step action="call:addMessage" monitored="true" name="Exit On Policy Violation" posX="250" posY="225">
    <Arg name="message" value="Failed due to policy violation(s)"/>
    <Arg name="type" value="Error"/>
    <Transition to="end"/>
  </Step>
  <Step action="call:addMessage" monitored="true" name="Exit On Manual Work Items" posX="280" posY="141">
    <Arg name="message" value="Failed due to manual work item(s)"/>
    <Arg name="type" value="Error"/>
    <Transition to="end"/>
  </Step>
  <Step action="call:addMessage" monitored="true" name="Exit On Provisioning Form" posX="352" posY="105">
    <Arg name="message" value="Failed due to provisioning form"/>
    <Arg name="type" value="Error"/>
    <Transition to="end"/>
  </Step>
  <Step catches="complete" icon="Catches" monitored="true" name="Finalize" posX="759" posY="284">
    <Arg name="trace" value="ref:trace"/>
    <Arg name="batchRequestItemId" value="ref:batchRequestItemId"/>
    <Arg name="identityName" value="ref:identityName"/>
    <Arg name="autoVerifyIdentityRequest"/>
    <Arg name="approvalSet" value="ref:approvalSet"/>
    <Arg name="ticketManagementApplication" value="ref:ticketManagementApplication"/>
    <Arg name="project" value="ref:project"/>
    <Arg name="workItemPriority" value="ref:workItemPriority"/>
    <Arg name="identityRequestId" value="ref:identityRequestId"/>
    <Arg name="ticketDataGenerationRule"/>
    <Description>
      Call the standard subprocess that can audit/finalize the request.
    </Description>
    <WorkflowRef>
      <Reference class="sailpoint.object.Workflow" id="7f00010196161e778196166022b7031a" name="Identity Request Finalize"/>
    </WorkflowRef>
    <Transition to="end"/>
  </Step>
  <Step icon="Stop" monitored="true" name="end" posX="830" posY="225"/>
  <Step icon="Default" monitored="true" name="Generic Step" posX="375" posY="11" resultVariable="isCreate">
    <Arg name="plan" value="ref:plan"/>
    <Script>
      <Source>

import sailpoint.object.BatchRequestItem;
import sailpoint.object.BatchRequest;
import java.util.regex.Pattern;
import sailpoint.object.AuditEvent;
import sailpoint.server.Auditor;

AuditEvent ae = new AuditEvent();

System.out.println("=================================================");
boolean isValid = true; // assume valid unless a check fails
String header = null;

if (batchRequestItemId != null) {
    
    BatchRequestItem batchRequestItem = context.getObjectById(BatchRequestItem.class, batchRequestItemId);
    
    if (batchRequestItem != null) {

        BatchRequest batchRequest  = batchRequestItem.getBatchRequest();
        header = (batchRequest != null) ? batchRequest.getHeader() : null;

        // Request data from CSV row (comma-separated string)
        String requestData = batchRequestItem.getRequestData();
        System.out.println("Request Data --- " + requestData);
        System.out.println("Header: " + header);

        // Split into columns
        String[] headers = (header != null) ? header.split(",") : new String[0];
        String[] values = (requestData != null) ? requestData.split(",") : new String[0];

        // Perform validation checks
        for (int i = 0; i &lt; headers.length &amp;&amp; i &lt; values.length; i++) {
            String column = headers[i].trim();
            String value = values[i].trim();

            if ("email".equalsIgnoreCase(column)) {
                boolean validEmail = Pattern.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$", value);
                if (!validEmail) {
                    System.out.println("X - Invalid email format: " + value);
                    isValid = false; // mark invalid
                } else {
                    System.out.println("/ - Valid email: " + value);
                }
            }

            if ("name".equalsIgnoreCase(column)) {
                if (value.length() &lt; 3 || value.length() > 50) {
                    System.out.println("X - Invalid name length: " + value);
                    isValid = false;
                } else {
                    System.out.println("/ - Valid name length: " + value);
                }
            }

            if ("operation".equalsIgnoreCase(column)) {
                if (!"CreateIdentity".equalsIgnoreCase(value)) {
                    System.out.println("X - Invalid operation: " + value);
                    isValid = false;
                } else {
                    System.out.println("/ - Valid operation: " + value);
                }
            }
        }
    }
}

// Log final result
if (isValid) {
    ae.setSource(launcher);
    ae.setTarget(identityDisplayName);
    ae.setApplication("Test");
    ae.setAction(emailSent);
    ae.setServerHost(Util.getHostName());
    Auditor.log(ae);
    System.out.println("/ - BatchRequestItem validation PASSED");
} else {
    ae.setSource(launcher);
    ae.setTarget(identityDisplayName);
    ae.setApplication("Test");
    ae.setAction("emailSent");
    ae.setServerHost(Util.getHostName());
    Auditor.log(ae);
    System.out.println("X - BatchRequestItem validation FAILED");
}

System.out.println("=================================================");

context.commitTransaction();
// Return result
return isValid;

















</Source>
    </Script>
    <Transition to="end" when="return  isCreate == false;"/>
    <Transition to="Create Ticket" when="return isCreate == true;"/>
  </Step>
  <Step icon="Default" monitored="true" name="Generic Step (1)" posX="504" posY="83"/>
  <Step icon="Default" monitored="true" name="Disable Provisioning" posX="136" posY="139">
    <Script>
      <Source>
         import sailpoint.object.ProvisioningPlan;
                import sailpoint.object.ProvisioningProject;
                import sailpoint.workflow.WorkflowContext;
                
          
                log.info("Skipping provisioning policy validation for batch request");
                
                // Set the skip flag in context
                context.put("skipProvisioningPolicy", true);
                
                 // ADD THESE LINES - These actually skip the policy!
                if (project != null) {
                    project.setProvisioningPolicy(null);  // THIS removes the policy
                }
                
                if (plan != null) {
                    plan.setCheckPolicies(false);  // THIS disables policy checking
                }
                

            
                log.info("Successfully configured to skip provisioning policy");
      </Source>
    </Script>
    <Transition to="Generic Step"/>
  </Step>
</Workflow>

I have seen your code, and can see few errors.

Please correct it and update these values.

Declare the variable at the top of your workflow

<Variable name="skipPolicy" initializer="false">
    <Description>Flag to indicate provisioning policy should be skipped</Description>
</Variable>

then for skipping the policy check put, below we are transition to exit section

<Transition to="Generic Step"/> instead of disable one.

The last section,
Remove the below lines, it seems you put it by mistake

update the step to the below.

</Source>
    </Script>
    <Transition to="end" when="return  isCreate == false;"/>
    <Transition to="Create Ticket" when="return isCreate == true;"/>
  </Step>
  <Step icon="Default" monitored="true" name="Disable Provisioning" posX="136" posY="139">
        <Script>
		<Source>
		
            log.error("Processing batch request without provisioning policy");
            
           
            if (plan != null) {
                try {
                    Map args = plan.getArguments();
                    if (args != null) {
                        args.remove("form");
                        args.remove("policy");
                        args.remove("provisioningPolicy");
                    }
                } catch (Exception e) {
                    log.debug("Plan cleanup: " + e.getMessage());
                }
            }
            
            // Set a workflow flag
            workflow.put("skipPolicy", "true");
            
            log.info("Policy references cleared");
        </Source>
    </Script>
    <Transition to="Generic Step"/>
  </Step>
</Workflow>

Please try it, and let me know if it worked for you.

Hi Thiraphat Itamonchai,

if the updated code changes fixed your issue. Can you please mark the post as Solution, as it will help others.

Hi @fewthiraphat ,

I am a bit late on catching this. Here’s attached workflow and Test Rule to test the Workflow for your perusal. I have also attached the output of the workflow from tomcat stdout logs. You might need to configure the stdout to capture it.

Here’s a plain-English rundown of the two files attached.

1) Workflow — “LCM Create and Update test with Batch”

  • Purpose: Run an LCM identity create/update, but when the request comes from BATCH, it skips provisioning policy checks and still proceeds.

  • How it decides to skip: In Initialize, if source == "BATCH", it goes to Disable ProvisioningLog Vars → the normal flow. Otherwise it just logs and continues normally.

  • Disable Provisioning step: Removes any policy/form references from the plan arguments (e.g., form, policy, provisioningPolicy), sets skipPolicy = true, and writes to logs.

  • Log Vars step: Prints the key inputs (identityName, identityDisplayName, flow, source, skipPolicy, batchRequestItemId) and also writes an AuditEvent tagged BatchVars for visibility.

  • Generic Step (CSV validation): If the request came via Batch, it reads the CSV header and row values and does quick checks:

    • email looks like an email,

    • name length is reasonable,

    • operation equals CreateIdentity.
      It logs PASSED/FAILED and only continues if valid.

  • Rest of the path: Standard LCM subflows—build approvals, approve, recompile, provision, optional refresh, and notify.

2) Rule — “Test Launch LCM Batch Workflow (v12p - Print Vars + SkipPolicy)”

  • Purpose: A super-compatible launcher for the workflow that works across different IIQ builds. It prints your inputs, derives or accepts skipPolicy, launches the workflow using several possible APIs, and writes an AuditEvent with the launch variables.

  • Inputs it handles: identityName, identityDisplayName, flow, source, batchRequestItemId, and (optionally) skipPolicy. If skipPolicy isn’t provided, it sets it to true when source == "BATCH".

  • What it prints to stdout: A block with those values (including skipPolicy) before launching, and then Launched workflow case: <id> after launch.

  • How it launches (compatibility tricks):

    1. Tries several context.startWorkflow(...) / context.launch(...) signatures via reflection,

    2. If that fails, it builds a WorkflowCase directly, attaches the workflow + variables, saves it, and tries to start/queue it using WorkflowEngine via reflection (so it doesn’t hard-depend on specific classes).

  • Auditing: Logs an event (Application=Test, Action=LauncherVars) with all the launch details in the Attributes map for maximum version compatibility.

In short:

  • The workflow skips policy when source=BATCH, logs what it’s doing, validates your batch row, and then runs the usual LCM steps.

  • The rule is a robust launcher that prints the variables (including skipPolicy), launches the workflow using whatever API your IIQ supports, and records the inputs in Audit for easy troubleshooting.

    Cheers, @sjagirdar1580

Test_Launch_LCM_Batch_Workflow_RULE_v12p_Print_SkipPolicy.xml (11.7 KB)

LCM_Create_and_Update_test_with_Batch_FULL_FIXED_v3_AuditVars.xml (18.8 KB)


1 Like

Thank you @sjagirdar1580, this is very helpful and a lot of good information.