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!
PowerShell script
-
- $url = "<site collection URL>"
- $list = "Pages"
- $workFlowName = "Publishing Approval"
- $wfassname = "Page Approval"
-
-
-
- function AddWorkflowToLibraries ($SiteCollection, $ListName, $WfName, $WfAssociationName)
- {
- #Get site object and create blank guid to store workflow template ID
- $site = Get-SPSite $SiteCollection
- [Guid]$wfTemplateId = New-Object Guid
-
- # Get every sub web
- Get-SPWeb -Site $site | ForEach-Object {
- Write-Host -ForegroundColor White -BackgroundColor DarkMagenta "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 ($wfTemplate in $_.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" -BackgroundColor Red -ForegroundColor White
- }
- 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" -ForegroundColor Blue
-
- $_.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 -Identity WorkflowHistoryList -Url $_.Url
- }
- $wfHistory = $_.Lists["Workflow History"]
- $wfHistory.Hidden = $true
- $wfHistory.Update()
- }
- else
- {
- Write-Host "FOUND: Workflow History list" -ForegroundColor green
- $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" -ForegroundColor Blue
- }
- else {
- Write-Host "FOUND: Workflow Tasks list" -ForegroundColor green
- }
- $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-Object Guid
- [bool]$wfFound = $false
-
- foreach ($wf in $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 -ForegroundColor green
- $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 -ForegroundColor Magenta
- }
- #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 -BackgroundColor Cyan -ForegroundColor Red
- }
- }
- }
- else {
- Write-Host -BackgroundColor DarkRed -ForegroundColor White "No"$listName" list found"
- }
- }
-
- #Dispose of Site object
- $site.Dispose()
- }
- function Get-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