Wednesday, 24 August 2011

Creating a retention policy to start a workflow in SharePoint 2010 using PowerShell

The script in this article was inspired by this one from Yaroslav Pentsarskyy, where he uses PowerShell to create a retention policy in SharePoint 2010. This works well for the built-in expiration actions (see, but I thought it was worth publishing a revised script for creating a retention policy to start a workflow as it requires a few extra properties in the policy XML.

The scenario for this script was that I wanted to create a retention policy on a specific content type associated with the Pages library on a number of sites. The workflow itself was associated directly to the Pages library and not to a site content type. The retention policy must start the workflow for each page, 20 days after it is created in the Pages library.

The workflow was created in SharePoint Designer and called “Review Page” - all it does is set a Status column to Expired. I then assigned the workflow to the “Content Page” content type on the Pages library of a site (see this article for details on how to do this in PowerShell) with the association name “Review Page Test”, as shown below:

Workflow to content type

We can now use PowerShell to create a retention policy to start this workflow for any page associated with the “Content Page” content type 20 days after it is created in the Pages library. Before the script can be run, you will need to load the following function in a PowerShell console with the SharePoint add-ins loaded:

function Update-IMPStartWorkflow($siteURL, $wfAssociationName, $listName, $contentType, $WfStartColumn)

    #Get web object
    $web = Get-SPWeb $siteURL
    write-host "Examining site:"$web.Title"at"$web.ServerRelativeUrl -ForegroundColor green
        #Do the following if a list exists with the name specified by the user - e.g., Pages
        if ($web.Lists[$ListName]) {

            write-host $web.Title"has a list called"$ListName -ForegroundColor green
            #Get the list
            $list = $web.Lists[$ListName]
            #Create list policy if one does not exist already
            #$policy = [Microsoft.Office.RecordsManagement.InformationPolicy.ListPolicySettings]($list)
            #if (!$policy.ListHasPolicy)
            #    $policy.UseListPolicy = $true
            #    $policy.Update()
            #Get the content type
            $ct = $list.ContentTypes[$contentType]
            #Get the Workflow template (parent association) ID from the association name
            $wfAssociationId = $ct.WorkflowAssociations.GetAssociationByName($wfAssociationName, 1033).ParentAssociationId.ToString()
            #Get the start column internal name and Id
            $fieldId = $list.Fields[$WfStartColumn].Id.ToString()
            $fieldName = $list.Fields[$WfStartColumn].InternalName
            #Create a new policy
            [Microsoft.Office.RecordsManagement.InformationPolicy.Policy]::CreatePolicy($ct, $null)
            $newPolicy = [Microsoft.Office.RecordsManagement.InformationPolicy.Policy]::GetPolicy($ct)    
            #Generate policy XML using the values required,
            #injecting column and workflow details from the variables assigned above
            $newPolicyFeatureXml = "<Schedules nextStageId=`"2`">"+
            "<Schedule type=`"Default`">"+
            "<data stageId=`"1`">"+
            "<formula id=`"Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Formula.BuiltIn`">"+
            "<action type=`"workflow`" id=`""+$wfAssociationId+"`" />"+
            #Add retention policy      
            $newPolicy.Items.Add("Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration", $newPolicyFeatureXml)
            write-host "Added retention policy to start workflow"$wfAssociation.Name"on content type"$ct.Name"for list"$list.Title"in site"$web.Title
            #Report if the site does not have the list specified by the user
            write-host $web.Title"does not have a list called"$listName -ForegroundColor red
        write-host "There has been an error:"$_ -ForegroundColor red
        #Dispose of the Web object

Note that the important part of this script is where you generate the XML for the policy and assign it to the $newPolicyFeatureXml variable. This XML defines the properties required for setting the event, action and recurrence details.

If you need to set a recurrence on the policy, then you can add some extra properties to the "<data stageId=`"1`">"+ line. For example, to set a recurrence period of every 1 day, replace this line with the following XML:

"<data stageId=`"1`" recur=`"true`" offset=`"1`" unit=`"days`">"+

Once the function has been loaded, it can be called with the following command to create a retention policy for the “Content Page” content type, on the Pages library of the site http://portal, to start the workflow with the association name “Review Page Test”:

Update-IMPStartWorkflow -siteURL http://portal -wfAssociationName "Review Page Test" -listName "Pages" -contentType "Content Page" -WfStartColumn "Created"

The Information Management Policies administration page on the Pages library for the “Content Page” content type should now look as follows:

Retention Policy

Another thing to note is how the workflow association ID is injected into the XML. An early draft of my script used the following line to get the workflow association ID:

$wfAssociationId = $ct.WorkflowAssociations.GetAssociationByName($wfAssociationName, 1033).Id.ToString()

However, running the script produced an “Invalid retention stage defined” error message in the Information Management Policies administration page against the retention policy:


To resolve this I needed to use the Parent Association ID (the workflow template) rather than the Association ID (the workflow instance), as follows:

$wfAssociationId = $ct.WorkflowAssociations.GetAssociationByName($wfAssociationName, 1033).ParentAssociationId.ToString()

I have added this information to the article in case you run into the same error message either in PowerShell or C# code and are looking for a solution…


  1. Phil, I am trying to run your script, but I get the following error: There has been an error: You cannot call a method on a null-valued expression. Ideas? It finds the site and the library, but then throws the error.

  2. Hi,

    I have same issue for OOTB SPD workflow.
    I only have one action in SPD i.e send email , i also tried to set the description column some value. but it still says invalid retention stage defined.????