Recover your deleted CRM data and recreate them using CRM API

Have you ever lost some your business records in Microsoft Dynamics CRM by accidently deleting them? Are you wondering how to recover them re-create them in CRM, without having to go through much of the tedious manual efforts.

Prior to Microsoft Dynamics CRM 2011, we used the “soft-delete” method, where when someone deleted a record, the record will not be actually deleted from the database immediately. Instead the record would be internally marked with IsDeleted = true, and there will be a CRM Deletion Service which will run an Asynchronous System Job once a day, which would actually pick up the records marked with IsDeleted = true and actually delete them from the database. So you could have used workarounds to recover the recently deleted data if it had not yet been deleted by the Deletion Service.

With CRM 2011, there are no more soft deletes in CRM, the record is actually deleted from the database right away. So, this becomes important than ever before. But CRM has the very powerful “Auditing” capability. Provided, you had Auditing turned on for those records, you can look at the Audit logs and find out all the changes that happened on your record including the deletion.

In this blog, I am going to walk you through a simple way with which you can use Audit logs to recover your lost data and recreate them in CRM. Of course, there will be minimal manual effort involved, but since we are using the CRM API for most of the recovery/re-creation work, this will definitely save you a lot of time, especially if you have a heavy volume of records you want to recover.

How do I find the Audit record I need to recover

In the web application, go to Settings->Auditing->Audit Summary View.

You can use the various filters and find the atleast one audit record for the entity you want to recover. Right click the audit record, and say copy a link. This copies the url to Audit Record including the Id. Paste the contents into clipboard, and you can find out the Id of Audit record.

How do I use the sdk to re-create the entity from the Audit record:

Once you have the Audit record’s Id, you can use the following code that uses the CRM API

// _service is the OrganizationService. // Please refer to the samplecodes in crm 2011 SDK on how to create this _service. // Guid of the Audit Record // E1CFF208-277B-E011-BB2B-001F29E1FC88 is the Id of the Audit Record in this example Guid auditId = new Guid(E1CFF208-277B-E011-BB2B-001F29E1FC88); RetrieveAuditDetailsRequest request =new RetrieveAuditDetailsRequest(); request.AuditId = auditId; RetrieveAuditDetailsResponse response = (RetrieveAuditDetailsResponse) _service.Execute(request); AuditDetail auditDetail= response.AuditDetail; Audit audit = (Audit) auditDetail.AuditRecord; EntityReference entityAudited = audit.ObjectId; Guid entityId = entityAudited.Id; string entityLogicalName = entityAudited.LogicalName; // Retrieve the audit records for entity. RetrieveRecordChangeHistoryRequest changeRequest = new RetrieveRecordChangeHistoryRequest(); changeRequest.Target = new EntityReference(entityLogicalName, entityId); RetrieveRecordChangeHistoryResponse changeResponse = (RetrieveRecordChangeHistoryResponse)_service.Execute(changeRequest); AuditDetailCollection details = changeResponse.AuditDetailCollection; for (int count = 0; count < details.Count; count++) { if(typeof(AttributeAuditDetail).Name == details[count].GetType().Name) { AttributeAuditDetail detail = details[count] as AttributeAuditDetail; // This is a safety check to verify // if the audit record is for the delete operation if(detail.NewValue == null && detail.OldValue != null) { Entity entity = detail.OldValue; _service.Create(entity); // The audit records are recorded in the order // from latest to older. So, it’s ok to break since you’ve recreated // from the latest snapshot of the entity, just before deletion break; } } }

Instead, if you’re able to find exact audit record for the delete operation you want to recover, you can simply use the following code to recreate the record, instead of the code described above:

// AACFF208-277B-E011-BB2B-001F29E1FC88 is the Id of the Deletion Audit Record Guid auditId = new Guid(“AACFF208-277B-E011-BB2B-001F29E1FC88”); RetrieveAuditDetailsRequest request =new RetrieveAuditDetailsRequest(); request.AuditId = auditId; RetrieveAuditDetailsResponse response = (RetrieveAuditDetailsResponse) _service.Execute(request); _service.Create(response.AuditDetail.OldValue);

You can use the sdk calls to retrieve the id of the audit record itself without going through the web UI, but to keep this simple, in this example, I’ve used the web UI method to filter out the Audit records to find the one I need to recover. Also if you have a huge volume of data, this becomes handy and you can just find the AuditIds and add to a list and loop through them.

Hope this helps and makes your recovery of data a smooth experience!