How to publish a Workflow Definition in SharePoint using PowerShell

oday, while working on the PnP Provisioning Engine I had to write some code to publish a new XAML based Workflow Definition in SharePoint, as well as to create a Subscription between the workflow and a target list/library. To make it easier, I wrote a bunch of PowerShell scripting that leverages the Erwin’s PnP PowerShell extensions together with the SharePoint Client Side Object Model and the Workflow Services Manager client library.

Here is a PowerShell excerpt, with in-line comments, that explains how you can create, publish and subscribe to a workflow definition starting from a XAML file.

# Load the WorkflowServicesManager client library (please provide the proper file path …)
[System.Reflection.Assembly]::LoadFrom(“Microsoft.SharePoint.Client.WorkflowServices.dll”)

# Connect to the remote SharePoint Site
Connect-SPOnline “https://tenant.sharepoint.com/sites/TargetSite/”

# Init context variables
$web = Get-SPOWeb
$ctx = $web.Context

# Create a WorkflowServicesManager instance
$wfm = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager -ArgumentList $ctx,$web

# Get a reference to the Workflow Deployment Service
$wfDeploymentService = $wfm.GetWorkflowDeploymentService()

# Load the Workflow XAML
$xamlPath = ‘SampleWorkflowDefinition.xaml’
$xaml = [System.Xml.Linq.XElement]::Load($xamlPath)

# Prepare the Workflow Definition object
$wfDefinition = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowDefinition -ArgumentList $ctx
$wfDefinition.DisplayName = “SampleWorkflow”
$wfDefinition.Description = “This is a sample workflow published using PowerShell”
$wfDefinition.Xaml = $xaml.ToString()

# Save and publish the Workflow Definition object
$definitionId = $wfDeploymentService.SaveDefinition($wfDefinition)
$ctx.Load($wfDefinition)
$ctx.ExecuteQuery()

# Publish the Workflow Definition
$wfDeploymentService.PublishDefinition($definitionId.Value)

# Retrieve IDs of targets (list/library, history, and tasks)
$targetLibrary = $web.Lists.GetByTitle(“Orders”)
$ctx.Load($targetLibrary)

$historyList = $web.Lists.GetByTitle(“Workflow History”)
$ctx.Load($historyList)

$tasksList = $web.Lists.GetByTitle(“Workflow Tasks”)
$ctx.Load($tasksList)

$ctx.ExecuteQuery()

# Associate the Workflow Definition to a target list/library
$wfSubscriptionService = $wfm.GetWorkflowSubscriptionService()
$wfSubscription = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscription -ArgumentList $ctx

# Configure the Workflow Subscription
$wfSubscription.DefinitionId = $definitionId.Value
$wfSubscription.Name = $wfDefinition.DisplayName + ” – Definition”
$wfSubscription.Enabled = $true
$eventTypes = New-Object System.Collections.Generic.List[String]

# Available values are: ItemAdded, ItemUpdated, WorkflowStart
$eventTypes.Add(“WorkflowStart”) $wfSubscription.EventTypes = $eventTypes

$wfSubscription.EventSourceId = $targetLibrary.Id.ToString()
$wfSubscription.SetProperty(“TaskListId”, $tasksList.Id.ToString())
$wfSubscription.SetProperty(“HistoryListId”, $historyList.Id.ToString())

# Publish the Workflow Subscription
$wfSubscriptionService.PublishSubscriptionForList($wfSubscription, $targetLibrary.Id)
$ctx.ExecuteQuery()

And the XAML of the sample workflow is something like that:

< Activity mc:Ignorable="mwaw" x:Class="SampleWF.MTW" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:local="clr-namespace:Microsoft.SharePoint.WorkflowServices.Activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mwaw="clr-namespace:Microsoft.Web.Authoring.Workflow;assembly=Microsoft.Web.Authoring" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
< Sequence>
< Sequence>
< mwaw:SPDesignerXamlWriter.CustomAttributes>
< scg:Dictionary x:TypeArguments="x:String, x:String">
< x:String x:Key="InitBlock">InitBlock-7751C281-B0D1-4336-87B4-83F2198EDE6D< /x:String>
< /scg:Dictionary>
< /mwaw:SPDesignerXamlWriter.CustomAttributes>
< /Sequence>
< Flowchart StartNode="{x:Reference __ReferenceID0}">
< FlowStep x:Name="__ReferenceID0">
< mwaw:SPDesignerXamlWriter.CustomAttributes>
< scg:Dictionary x:TypeArguments="x:String, x:String">
< x:String x:Key="Next">4294967294< /x:String>
< /scg:Dictionary>
< /mwaw:SPDesignerXamlWriter.CustomAttributes>
< Sequence>
< mwaw:SPDesignerXamlWriter.CustomAttributes>
< scg:Dictionary x:TypeArguments="x:String, x:String">
< x:String x:Key="StageAttribute">
StageContainer-8EDBFE6D-DA0D-42F6-A806-F5807380DA4D
< /x:String>
< /scg:Dictionary>
< /mwaw:SPDesignerXamlWriter.CustomAttributes>
< local:SetWorkflowStatus Disabled="False" Status="Stage 1">
< mwaw:SPDesignerXamlWriter.CustomAttributes>
< scg:Dictionary x:TypeArguments="x:String, x:String">
< x:String x:Key="StageAttribute">StageHeader-7FE15537-DFDB-4198-ABFA-8AF8B9D669AE< /x:String>
< /scg:Dictionary>
< /mwaw:SPDesignerXamlWriter.CustomAttributes>
< /local:SetWorkflowStatus>
< Sequence DisplayName="Stage 1">
< local:WriteToHistory Message="Hello World!" />
< /Sequence>
< Sequence>
< mwaw:SPDesignerXamlWriter.CustomAttributes>
< scg:Dictionary x:TypeArguments="x:String, x:String">
< x:String x:Key="StageAttribute">
StageFooter-3A59FA7C-C493-47A1-8F8B-1F481143EB08
< /x:String>
< /scg:Dictionary>
< /mwaw:SPDesignerXamlWriter.CustomAttributes>
< /Sequence>
< /Sequence>
< /FlowStep>
< /Flowchart>
< /Sequence>
< /Activity>

Of course, it is a very simple workflow that simply writes “Hello World!” in the History List, but it can be something more complex, if you like. Enjoy!