Tuesday 23 July 2013

Attach workflow to all webs

So I've made my own custom approval state machine workflow and now I need to attach it to everyone of my subsites. how do I accomplish this? Well any time you're face with a cumbersome amount of pointing and clicking you have two alternatives:

  • Feature event receiver 
  • PowerShell

Now as I learned the hard way you're event receiver has a 2 minute time out, so in my case where I'm attaching a workflow to three libraries on every subsite and creating a custom task list it really didn't pan out. Instead I ended up moving my logic out of my visual studio project and into a powershell script. I'm going to break this script down into Five sections.

Section One (Start up)

#get the site url to deploy workflow to
param($siteUrl=$(read-host "Please provide web app url of the list to be delete (EG:'http://Wingtip'):"))

#ensure that user provided site url parameter
if($siteUrl -eq $null -or $siteUrl -eq '')
{
    throw "You must specify your server name. Value provided was null/empty."
}

#function to load SharePoint Powershell snap in
function LoadSharePointPowerShellEnviroment
{
 #clear the screen of pevious output
 Clear-Host
 write-host "Setting up Powershell enviroment for Sharepoint" -foregroundcolor Blue
 Add-PSSnapin "Microsoft.Sharepoint.PowerShell" -ErrorAction SilentlyContinue
 Write-host "Sharepoint PowerShell Snapin loaded." -foregroundcolor Green
}

#call sharepoint plugin function

LoadSharePointPowerShellEnviroment

Section Two(Declare Constants)

#get site using parameter
$site = Get-SPSite($siteUrl)

#get the rootweb of the site
$rootWeb = $site.RootWeb

#ensure that approval workflow has unique name
$workFlowName = "Approval_" +  [System.DateTime]::Now.ToString()

#specify the approval task list name
$TASKLISTNAME = "Approval Tasks"

#specify the task list description
$listDescription = "Task list for ccw custom approval tasks"

#reference approval task list definition, deployed through VS project
$TaskListTemplate= $rootWeb.ListTemplates["Page Approval Task List Definition"]

#specify OOTB workflow history list, every site has one
$HISTORYLISTNAME = "Workflow History"

#approval workflow ID, specified in elements file of workflow
$APPROVALWORKFLOWID = [GUID]"64f076cb-a5f8-4ee7-9ef4-54820d291886"

#reference workflow using workflow ID

$wfTemplate = $rootWeb.WorkflowTemplates[$APPROVALWORKFLOWID]

Section Three(Create list function)

#Create List Instance function
function createListInstance($web, $listName, $listDescription)
{
      #make sure list doesn't already exist
      if($web.Lists.TryGetList($listName) -eq $null)
      {
            #create list with no spaces
            $listGuid = $web.Lists.Add($listname.Replace(" ",""), $listDescription, $TaskListTemplate)
           
            #grab the list, change the name to the original parameter passed to the function
            $list = $web.Lists[$ListGuid]
            $list.title = $listName
            $list.Update()
      }
      else
      {
            Write-Host $listName + "was not created on web" + $web.Url -ForegroundColor Red;
      }
      $web.Dispose()

}

Section Four(Attach workflow function)

#attach workflow to web
function addApprovalWorkflow($web, $listname)
{
      #get the library you want to attach the workflow to
    $library = $web.Lists.TryGetList($listname)
   
      #ensure library exists
    if($library -ne $null)
    {
            #reference tasklist, and histrory list on web
        $taskList = $web.Lists[$TASKLISTNAME]
        $historyList = $web.Lists[$HISTORYLISTNAME]
       
            #create a workflow association refer to
        $workflowAssociation = [Microsoft.SharePoint.Workflow.SPWorkflowAssociation]::CreateListAssociation($wfTemplate, $workflowName, $taskList, $historyList);
       
            #set the properties of the workflow assocation
        $workflowAssociation.Name = $workFlowName
        $workflowAssociation.AllowManual = $true
        $workflowAssociation.AutoStartChange = $true
        $workflowAssociation.AutoStartCreate = $true
       
            #attach the workflow association to the Library
        $temp = $library.WorkflowAssociations.Add($workflowAssociation);
        $workflowAssociation.Enabled = $true;
            $web.Dispose()
    }

}

Section Five(Main)

#itterate through all subsites
$webs = $site.AllWebs
foreach ($web in $webs)
{
      #ignore the search site
      if($web.Title -eq "Search")
      {
            continue
      }
     
      Write-Host $web.Url
      #create the task list
      createListInstance $web $TASKLISTNAME $listDescription
     
      #Attach the approval wf to libraries
      addApprovalWorkflow  $web "Pages"
      addApprovalWorkflow  $web "Images"
    addApprovalWorkflow  $web "Documents"
    $web.Dispose()
}
$rootWeb.Dispose()
$site.Dispose()


write-host "Complete" -ForegroundColor Blue