Recently I have been working on document lifecycle management project. One of the targets for the project was to try and use out of the box (OOB) SharePoint features rather than develop additional components. I am all for this, it reduces support and maintenance overhead and the technical debt of the solution.
The solution ended up implementing a multiple content types with information management policies for auditing and retention policies.
The retention policy had a number of stages which were:-
- Created date + 1 day make the document into a record
- Created date + X years execute the “Disposition Approval Workflow”
The number of years would vary depending on the type of document.
Before I go any further I should talk about the Disposition Approval Workflow, this is a workflow which has been in SharePoint since SharePoint 2007 and is made available using the Disposition Workflow feature.
The workflow when run against a document has one step. The step creates a task which presents the user with the option to either delete the document or retain it. The user can also provide comments.
What should happen is that if the user chooses to delete the document then the workflow will delete the document.
However, this fails if the document is declared as a record. Unfortunately the out of the box disposition approval workflow which has been designed to provide a mechanism to delete a document cannot delete a document if its a record.
The workflow displays the following error or words to the effect of “Cannot delete the document”
This was a little frustrating so what do we do?
After some thought about the problem I came up with two approaches:-
- redesign the Disposition Approval Workflow to work how we want it to
- add a step to undeclare the document as a record
Thinking back to one of the key targets, keep the amount of custom development to a minimum, I decided to go for the second option.
Unfortunately, there is no expiration action which allows you to undeclare a record. So I looked at the options to create one.
Fortunately there are a couple of reasonable examples, they might be a little lacking in detail but there is enough to understand the process.
So the following solution was built, the solution is made up of the following parts:-
- A class which implements the IExpirationAction interface and perform the action to undeclare a document as a record
- A feature which has a feature receiver which adds the IExpirationAction to the PolicyTemplates
- A class UndeclareRecordExpirationAction is created which implements the IExpirationAction interface as follows:-
- The IExpirationAction interface has a function OnExpiration which passes in the SPListItem to delete and the date that the document has expired on.
- The function implementation would be to check that the document is not already on hold and also that the document isn’t a record already.
- if the document is on hold then an exception is raised so that the process goes no further.
Two static functions were created which register / unregister the ExpirationPolicyAction with SharePoint.
A feature was created which implemented FeatureActivatation and FeatureDeactivation methods. These call into the appropriate static functions in the UndeclareRecordExpirationAction class.
Once the solution is installed and the feature activated then a new policy action appears here:
To configure the policy do the following:-
- Browse to the site collection
- Browse to the site settings page
- Click Site Content Types
- Click on the content type that you wish to apply the policy to
- Click on “Information Management Policy settings”
- Click “Define a policy..”
- Click Ok
- Click Enable Retention
- Add a retention stage…
The information policy was modified so that it has the following steps:-
- Created + 1 day = Declare record (reoccurrence 1 month)
- Created + 6 Years = Undeclare Record (reccurrence 1 year)
- Created + 6 Years = Start Workflow (reoccurence 1 year)
The option to specify how to manage retention on records was set that the same policy was used for both records and non-records.
I set the reoccurrence for the Declare record action to one month so that if a document was undeclared and then the record managers decided not to delete the document through the workflow it would then picked up again.
Testing the solution
The process of testing these expiration policies was a little tricky so I will cover the method that used. Information policies are applied by timer jobs. The following timer jobs are used:-
- Information Management Policy Timer Job
- Expiration Timer job
The expiration timer job does the actual work of applying/running the various steps of a retention policy. By default it runs once a week in SharePoint 2013.
To speed things up I did the following to test/debug the solution.
- Compile the assembly hosting our UndeclareRecordExpirationAction class as a debug build.
- Deploy the solution
- Restart SharePoint Timer Service
- Attach the Visual Studio debugger to the “owstimer.exe” process
- From Central Admin, start the timer job through the monitoring->review job definintions
- Browse to the Expiration Policy Job Definitions
- Click on the “Expiration policy” link for the one associated to the Web Application where your application is hosted and click “Run now”
- Wait for the visual studio debugger to hit the breakpoint
If you are having problems getting the debugger to hit the breakpoint then:-
- Start the SharePoint Management Shell
- From within the PowerShell session
- restart the owstimer service using Restart-Service sptimerv4
- restart IIS using iisreset
The only thing that I may look to do is rather than have two stages for “Undeclare record” and “Starting a workflow” is merge them into two and have a “undeclare record and start workflow action” so that there is less delay with the processing.
I hope people find this useful, please let me know if you do.
Here are links to the code samples:-