Background
Your organisation is using SharePoint as a collaboration and productivity platform, and your business units have built their solutions on it. As part of business solutions, IT teams have built workflows using SharePoint designer to cater business needs. One of the challenges developers or IT professionals used to have is how to export and import this workflow to other SharePoint sites in case if you are having multiple environments like Dev, Test, UAT and Prod.
In today’s blog post, we will go through it and use PowerShell to export and import workflows across different site collections/tenants.
Solution
PowerShell will come to rescue while dealing with such problems, scripts listed below will help you in doing that task. It is using commands from PnP-PowerShell as well.
You need to export the workflow definition that you have built using SharePoint Designer in your existing site collection. It relies on parameters like URL, Application Client ID, Application Client Secret and Workflow name to connect to SharePoint and extract workflow definition from it and then writes it into a XAML file.
Export.ps1
[code language=”powershell”]
[CmdletBinding(SupportsShouldProcess = $true)]
param (
$Url,
$ClientId,
$ClientSecret,
$WFDefinitionName
)
# include the common script
. "$PSScriptRoot\Common.ps1"
$FilePath = "$PSScriptRoot\WorkFlowDefinition\$($WFDefinitionName).xaml"
Connect-PnPOnline -Url $Url -AppId $ClientId -AppSecret $ClientSecret
Write-Host " "
Write-Host "Connected successfully to: $($Url)" -ForegroundColor Yellow
Get-PnPWorkflowDefinition -Name $WFDefinitionName
<span data-mce-type="bookmark" id="mce_SELREST_start" data-mce-style="overflow:hidden;line-height:0" style="overflow:hidden;line-height:0" ></span>
Save-WorkflowDefinition (Get-PnPContext) $WFDefinitionName $FilePath
[/code]
Once you have successfully exported workflow definition, you need to import it into the destination site. Import function relies on parameters like URL, Application Client ID, Application Client Secret and Workflow name to connect to SharePoint and import workflow definition from the file and then updates it into SharePoint site.
Import.ps1
[code language=”powershell”]
[CmdletBinding(SupportsShouldProcess = $true)]
param (
$Url,
$ClientId,
$ClientSecret,
$WFDefinitionName
)
# include the common script
. "$PSScriptRoot\Common.ps1"
$FilePath = "$PSScriptRoot\WorkFlowDefinition\$($WFDefinitionName).xaml"
Connect-PnPOnline -Url $Url -AppId $ClientId -AppSecret $ClientSecret
Write-Host " "
Write-Host "Connected successfully to: $($Url)" -ForegroundColor Yellow
$ctx = Get-PnPContext
$parentContentTypeId = $null
$wf = Get-PnPWorkflowDefinition -Name $WFDefinitionName
if ($wf -eq $null)
{
# Load workflow definition
Publish-WorkflowDefinition (Get-PnPContext) $FilePath $WFDefinitionName
Add-PnPWorkflowSubscription -Name $WFDefinitionName -DefinitionName $WFDefinitionName -List "YourSharePointListName" -HistoryListName "Workflow History" -TaskListName "Workflow Tasks" -StartOnCreated
}
else
{
Write-Host "Workflow definition $($WFDefinitionName) already exists.." -ForegroundColor Yellow
}
[/code]
Above two import and export commands rely on some PowerShell functions and are references in Common.ps1 and are listed below:
Common.ps1
[code language=”powershell”]
function Save-WorkflowDefinition($ctx, $wfName, $filePath) {
$web = $ctx.Web
$wfm = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager -ArgumentList $ctx, $web
$wfds = $wfm.GetWorkflowDeploymentService()
$wfdefs = $wfds.EnumerateDefinitions($false)
$ctx.Load($wfdefs);
$ctx.ExecuteQuery();
$wdef = $wfdefs | Where-Object {$_.DisplayName -eq $wfName}
if (!$wdef) {
Write-Error "Could not find Workflow definition to Export";
return;
}
$wdef | Export-Clixml $filePath
Write-Host " "
Write-Host "Workflow definition ‘$($wfName)’ exported successfully.." -ForegroundColor Green
}
function Publish-WorkflowDefinition($ctx, $filePath, $wfName) {
$ctx = Get-PnPContext
$web = $ctx.Web
Write-Host " "
Write-Host "Loading Workflow definition: $($filePath)"
$wfLoadedDefinition = Import-Clixml $filePath
$wfDefinition = Get-PnPWorkflowDefinition -Name $wfName
if ($wfDefinition) {
Write-Host "Updating existing workflow definition for $($wfName)"
}
else {
Write-Host "Creating new workflow definition: $($wfName)"
$wfDefinition = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowDefinition -ArgumentList $ctx
}
$xamlActivity = $wfLoadedDefinition.Xaml;
$wfDefinition.DisplayName = $wfLoadedDefinition.DisplayName;
$wfDefinition.Description = $wfLoadedDefinition.Description;
$wfDefinition.Xaml = $xamlActivity;
$wfDefinition.FormField = $wfLoadedDefinition.FormField;
$wfDefinition.SetProperty("ContentTypeId", $wfLoadedDefinition.Properties["ContentTypeId"]);
$wfDefinition.SetProperty("FormField", $wfLoadedDefinition.Properties["FormField"]);
$wfDefinition.RequiresAssociationForm = $wfLoadedDefinition.RequiresAssociationForm;
$wfDefinition.RequiresInitiationForm = $wfLoadedDefinition.RequiresInitiationForm;
$wfDefinition.RestrictToType = $wfLoadedDefinition.RestrictToType;
$wfm = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager -ArgumentList $ctx, $web
$wfDeploymentService = $wfm.GetWorkflowDeploymentService()
$definitionId = $wfDeploymentService.SaveDefinition($wfDefinition)
$ctx.Load($wfDefinition)
$ctx.ExecuteQuery()
Write-Host "Workflow definition saved successfully for workflow: $($wfName)"
$wfDeploymentService.PublishDefinition($definitionId.Value)
$ctx.Load($wfDefinition)
$ctx.ExecuteQuery()
Write-Host " "
Write-Host "Workflow definition ‘$($wfName)’ published successfully.." -ForegroundColor Green
}
[/code]
I hope above set of scripts will help some of you to take SPD workflows around and deploy it across multiple development sites, test sites and/or UAT sites.
Thanks for your article 🙂 It helped me
Hi,
From where do I get the Application Client ID, Application Client Secret ?
Hi, Thanks for the article. I have been able to publish the Workflow in a new site (Sp online), but when trying to associate the workflow with a Document library, its failing ; the “Associated List’ property is showing as null. Please advise urgently.
–> Add-PnPWorkflowSubscription -Name $WFDefinitionName -DefinitionName $WFDefinitionName -List “Test Records” -HistoryListName “Workflow History” -TaskListName “Workflow Tasks” -StartOnCreated -StartOnChanged
$siteContext.ExecuteQuery();