Friday, August 4, 2017

Update content type workflow association approver through PowerShell


I had a requirement to update an approver on a SharePoint workflow which was setup on Document Content Type at the library level. The workflow has been there since SharePoint 2010 and we upgraded to 2013 around 3 years ago. This was an OOB workflow created in UI  (not through SPD) with single task approver with CC user added (see the XML snippet below)

When I opened up workflow settings and in the "Change Workflow" page, I am not seeing plain "Approval" workflow template which is the actual workflow template used but not "Approval - SharePoint 2010". Also the text box is disabled/greyed out and the system isn't letting me change the template throwing the error prompt. Not sure if this is by design or a bug in SharePoint.  


Change workflow page -  Selection is disabled
System don't let you change the template

Anyways, I needed to update the workflow approver with a new employee because the existing one was leaving. When I figured I can't update through UI then I tried through SharePoint Designer which wasn't letting me do it either. So I have chosen PowerShell route to tweak the workflow association properties. 

Association Data in XML


PowerShell snippet.

Just retrieve the list content type's workflow association data which is an xml string and update the approver values.

             $web = Get-SPWeb "http://<SharePoint web URL>"                    
        $list = $web.Lists | Where-Object { $_.Title -eq 'List Title' }                       
        $ListWorkFlowAssns =  $list.WorkflowAssociations        
        foreach($ctype in $list.ContentTypes)
        {
            if ($ctype.Name -eq "Document")
            {                
                $wa = $ctype.WorkflowAssociations.GetAssociationByName("My Approval", $web.UICulture)
                if ($wa -ne $null)
                {                                                                                  
                    $parsedXml = [System.Xml.Linq.XElement]::Parse($wa.AssociationData)                
                    $nodes = $parsedXml.Descendants() | Where-Object {($_.Name.LocalName -eq "Reviewers")}                                    
                    $accountId = $nodes[0].Descendants() | Where-Object {($_.Name.LocalName -eq "AccountId")}
                    $displayName = $nodes[0].Descendants() | Where-Object {($_.Name.LocalName -eq "DisplayName")}
                    $accountId.SetValue("Domain\UserName") # replace value with the new approver AD username
                    $displayName.SetValue("User Full Name") # replace value with the new approver AD Full Name                 
                    $wa.AssociationData = $parsedXml.ToString()
                    $ctype.WorkflowAssociations.Update($wa)               
                    
                }               
            }            
        }

        $list.Update()




I made sure no current instances are running and no new instances are created while I am making these changes. 






Note: If you are following the same approach, please put additional checks and filters while updating. You don't want to update other content types mistakenly or workflow association properties that you are not intended.