CRM 2011 –Automatically Enable/Disable Plug-ins and Workflows

Roshan Mehta, 17 June 2013

I have recently built a data migration tool for Microsoft Dynamics CRM 2011. Before the migration runs, it is important to deactivate all active workflow and plug-in steps so that we prevent our custom business logic from executing which could potentially slow down the migration process. Once the migration is complete, we can reactivate the workflow and plug-in steps so that the system functions as expected.

The first step is to obtain the ID of the current system user which can be done using the following code snippet. We will need this to assign workflows at a later stage.

private static Guid GetSystemUserId()
{
    Guid userId = Guid.Empty;
    string domainName = "mydomain\user";

    QueryExpression query = new QueryExpression { EntityName = "systemuser" };
    query.Criteria.AddCondition("domainname", ConditionOperator.Equal, domainName);

    EntityCollection results = _sdk.RetrieveMultiple(query);
    if (results.Entities.Count > 0)
    {
        userId = results[0].Id;
    }

    return userId;
}

Next, we need to retrieve all active workflow processes by querying the workflow entity. We only want to retrieve workflows where the statecode is “1” (active), the statuscode is “2” (published) and the type is “1” (definition).

private static List<Guid> GetActiveWorkflowIds()
{
    List<Guid> activatedWorkflowIds = new List<Guid>();

    QueryExpression query = new QueryExpression { EntityName = "workflow" }; 
    query.Criteria.AddCondition("statecode", ConditionOperator.Equal, 1);   
    query.Criteria.AddCondition("statuscode", ConditionOperator.Equal, 2);
    query.Criteria.AddCondition("type", ConditionOperator.Equal, 1);

    EntityCollection results = _sdk.RetrieveMultiple(query);
    activatedWorkflowIds = results.Entities.ToList().Select(e => e.Id).ToList();

    return activatedWorkflowIds;
}

We also need all active plug-in steps by querying the sdkmessageprocessingstep entity. It is important to filter on plug-ins that we have developed ourselves so that we don’t retrieve any of the built-in platform plug-in steps.

private static List<Guid> GetPluginIds()
{
    List<Guid> pluginIds = new List<Guid>();

    QueryExpression query = new QueryExpression { EntityName = "sdkmessageprocessingstep" };    
    query.Criteria.AddCondition("name", ConditionOperator.BeginsWith, "Frostys");  

    EntityCollection results = _sdk.RetrieveMultiple(query);
    pluginIds = results.Entities.ToList().Select(e => e.Id).ToList();

    return pluginIds;
}

Before we can change the status of workflows from active to inactive (or vice versa), we must first assign each of the workflows to ourselves, hence the need to obtain the systemuserid in the first step of the process.

private static void AssignWorkflows(Guid systemUserId)
{
    _workflowIds.ForEach(w =>
    {
        _sdk.Execute(new AssignRequest 
        {
            Assignee = new EntityReference("systemuser", systemUserId),
            Target = new EntityReference("workflow", w)
        });
    });
}

The last step of the process is to change the status of the workflows and plug-in steps. This is done using the SetStateRequest. I have created a method called ToggleProcessState which takes in a boolean parameter to indicate whether we are disabling or enabling the plug-in and workflow steps.

private static void ToggleProcessState(bool disable)
{
    // workflow stateCode = 0 and statusCode = 1 (inactive), stateCode = 1 and statusCode = 2 (active) 
    // plugin stateCode = 1 and statusCode = 2 (inactive), stateCode = 0 and statusCode = 1 (active) 

    int wfStateCode = disable ? 0 : 1;
    int wfStatusCode = disable ? 1:  2;
    int pluginStateCode = disable ? 1 : 0;
    int pluginStatusCode = disable ? 2 : 1;

    // workflows 
    _workflowIds.ForEach(w =>
    {
        _sdk.Execute(new SetStateRequest 
        {
            EntityMoniker = new EntityReference("workflow", w),
            State = new OptionSetValue(wfStateCode),
            Status = new OptionSetValue(wfStatusCode)
        });
    });

    _pluginIds.ForEach(p =>
    {
        _sdk.Execute(new SetStateRequest 
        {
            EntityMoniker = new EntityReference("sdkmessageprocessingstep", p),
            State = new OptionSetValue(pluginStateCode),
            Status = new OptionSetValue(pluginStatusCode)
        });
    });
}

It is important to note that this process can take some time depending on the number of workflows and plug-in steps you have in the system.