What you need / What you've got?
- Pretty obvious, when a user edits/changes a page, you need someone to check its all good before it goes live! Aka Publishing Approval
- You can use the "Publishing site with workflow" template or enable it manually or set it up in your custom site definition.
- BUT...you've got an entire site collection full of web sites and you need to do it "en-mass" … step up Powershell.
- A common scenario could be you were working in Stage or Pre-go live and having Approval workflow just isn't practical or required. Now its live...you need and want it.
What you need to do to SharePoint...
- Enable Moderation on the library (that is Content Approval in UI)
- Enable Minor Versions (that’s is 1.1, 1.2 etc)
- Create the Workflow History list and enable the Workflow History feature (hiding this list is optional, but I think its best, showing the list offers nothing to the user, you can access the same history looking at the workflow status screen, which is far more usefully presented)
- Create the Workflow Tasks list
- Associate the "Publishing Approval" workflow to the library
- Set the properties on the WorkFlow association
- This is your choice, but I have set AllowManual to true, AutoStartCreate and Change to false
- Add the association
- You would be forgiven in thinking that’s it, job done...but you will find that the even though the workflow is there, it doesn't the "major check-in" property enabled so the experience for the user is different i.e they have to choose the non-default option to fire the workflow.
- You need to set the property DefaultContentApprovalWorkflowId to the id of the Workflow association object, what tricked me up...even though in the UI the property is in the workflow with the other workflow properties, but this property is on the library.
- Still not done...now, the workflow is firing great, but every status is "Rejected". Why? Because you need to Update the workflow association data.
- For this I cheated and setup 1 workflow on the pages library, with the correct actions and Approvers group, then went into SharePoint Manager and grabbed the xml from there.
- Also I set the Enabled property to true and call WorkflowAssociations.Update(myAssociation) to set both new properties…
- Yes, that’s it...you are actually done now!!!
The Magic
This script is 99% influenced by this post http://bit.ly/AcOa2s, I’ve butchered it and added the extra stuff required… FYI: http://get-spscripts.com is a great resource for SharePoint PowerShell scripts...the scripts published are always of high quality, well commented and explained - bookmark it if you don't like thrashing.
The crazy colours and rather OTT output is my fault!
I’ve also put the params at the top – not overly user friendly, but this is perfect for my requirements…you can easily change that!
$url="<site collection URL>" $list="Pages" $workFlowName="Publishing Approval" $wfassname="Page Approval" functionAddWorkflowToLibraries ($SiteCollection, $ListName, $WfName, $WfAssociationName) { #Get site object and create blank guid to store workflow template ID $site=Get-SPSite$SiteCollection [Guid]$wfTemplateId=New-ObjectGuid # Get every sub web Get-SPWeb-Site$site | ForEach-Object { Write-Host-ForegroundColorWhite-BackgroundColorDarkMagenta"WEB: "$_.Title$_.Url #Do the following if a list exists with the name specified by the user - e.g., Pages if ($_.Lists[$ListName]) { Write-Host"PROCESS:"$listName"list" # # Get list and set version properties # $list=$_.Lists[$ListName] $list.EnableModeration =$true $list.EnableMinorVersions =$true $list.Update() #Go through each workflow installed in the site to find the correct ID foreach ($wfTemplatein$_.WorkflowTemplates) { if ($wfTemplate.Name -eq$WfName) { $wfTemplateId=$wfTemplate.Id } } # #SETUP WORKFLOW HISTORY LIST # $wfTemplate=$_.WorkflowTemplates[$wfTemplateId] if($wfTemplate-eq$null) { Write-Host"ERROR: Workflow '"$WfName"' with ID '"$wfTemplateId"' NOT found"-BackgroundColorRed-ForegroundColorWhite } else { #Check if the site already has a workflow history list - if not, create it if(!$_.Lists["Workflow History"]) { Write-Host"CREATE: Workflow History list"-ForegroundColorBlue $_.Lists.Add("Workflow History", "A system library used to store workflow history information that is created in this site. It is created by the Publishing feature.", "WorkflowHistory", "00BFEA71-4EA5-48D4-A4AD-305CF7030140", 140, "100") if (!$_.Features["00BFEA71-4EA5-48D4-A4AD-305CF7030140"]) { Enable-SPFeature-IdentityWorkflowHistoryList-Url$_.Url } $wfHistory=$_.Lists["Workflow History"] $wfHistory.Hidden =$true $wfHistory.Update() } else { Write-Host"FOUND: Workflow History list"-ForegroundColorgreen $wfHistory=$_.Lists["Workflow History"] } # #Check if the site already has a workflow tasks list - if not, create it # if(!$_.Lists["Workflow Tasks"]) { $_.Lists.Add("Workflow Tasks", "This system library was created by the Publishing feature to store workflow tasks that are created in this site.", "WorkflowTasks", "BF611337-1591-49f4-BF42-CE7BE53852D8", 107, "100") Write-Host"CREATE: Workflow Tasks list"-ForegroundColorBlue } else { Write-Host"FOUND: Workflow Tasks list"-ForegroundColorgreen } $wfTasks=$_.Lists["Workflow Tasks"] # #new up workflow association (extra associated data can be added if you have it) # $wfAssociation= [Microsoft.SharePoint.Workflow.SPWorkflowAssociation]::CreateListAssociation($wfTemplate, $WfAssociationName, $wfTasks, $wfhistory) $wfAssociation.AllowManual =$true #$wfAssociation.AllowAsyncManualStart = $true $wfAssociation.AutoStartChange =$false $wfAssociation.AutoStartCreate =$false # #Check to see if the association has already been added to the list # [guid]$wfId=New-ObjectGuid [bool]$wfFound=$false foreach ($wfin$list.WorkflowAssociations) { if ($wf.Name -eq$wfAssociation.Name) { $wfId=$wf.Id write-host"FOUND: Workflow"$wf.Name"already exists on"$list.Title"list in site"$_.Title-ForegroundColorgreen $wfFound=$true } } #If association is already there, ignore the add (and optionally delete it) if ($wfFound-eq$true) { #Command to remove existing workflow from list before adding new one, if required #$list.WorkflowAssociations.Remove($wfId) write-host"REMOVE: Workflow"$wfAssociation.Name"from"$list.Title"in site"$_.Title-ForegroundColorMagenta } #else, add it to the workflow association to the list else { #Create the association $list.WorkflowAssociations.Add($wfAssociation) | Out-Null #Set the association data (for approvers and approval steps $wfAssociation.AssociationData =Get-AssociationData #enable is not available until its associated. $wfAssociation.Enabled =$true $list.WorkflowAssociations.Update($wfAssociation) $list.DefaultContentApprovalWorkflowId =$wfAssociation.Id $list.Update() write-host"CREATE: Workflow"$wfAssociation.Name"to"$list.Title"in site"$_.Title-BackgroundColorCyan-ForegroundColorRed } } } else { Write-Host-BackgroundColorDarkRed-ForegroundColorWhite"No"$listName" list found" } } #Dispose of Site object $site.Dispose() } functionGet-AssociationData() { return"<dfs:myFields xmlns:xsd=`"http://www.w3.org/2001/XMLSchema`" xmlns:dms=`"http://schemas.microsoft.com/office/2009/documentManagement/types`" xmlns:dfs=`"http://schemas.microsoft.com/office/infopath/2003/dataFormSolution`" xmlns:q=`"http://schemas.microsoft.com/office/infopath/2009/WSSList/queryFields`" xmlns:d=`"http://schemas.microsoft.com/office/infopath/2009/WSSList/dataFields`" xmlns:ma=`"http://schemas.microsoft.com/office/2009/metadata/properties/metaAttributes`" xmlns:pc=`"http://schemas.microsoft.com/office/infopath/2007/PartnerControls`" xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`"><dfs:queryFields /><dfs:dataFields><d:SharePointListItem_RW><d:Approvers><d:Assignment><d:Assignee><pc:Person><pc:DisplayName>Approvers</pc:DisplayName><pc:AccountId>Approvers</pc:AccountId><pc:AccountType>SharePointGroup</pc:AccountType></pc:Person></d:Assignee><d:Stage xsi:nil=`"true`" /><d:AssignmentType>Serial</d:AssignmentType></d:Assignment></d:Approvers><d:ExpandGroups>false</d:ExpandGroups><d:NotificationMessage /><d:DueDateforAllTasks xsi:nil=`"true`" /><d:DurationforSerialTasks xsi:nil=`"true`" /><d:DurationUnits>Day</d:DurationUnits><d:CC /><d:CancelonRejection>true</d:CancelonRejection><d:CancelonChange>true</d:CancelonChange><d:EnableContentApproval>true</d:EnableContentApproval></d:SharePointListItem_RW></dfs:dataFields></dfs:myFields>" } AddWorkflowToLibraries$url$list$workFlowName$wfassname