Sunday, February 7, 2016

Stop/Start workflow for SharePoint Online using PowerShell Script

With SharePoint Online, PowerShell is as a connected bridge so that it itself brings a big dedication. I always think about PS script whenever get a new request.

Start/Start workflow for list item of large list is one of tasks that I have been worked on and it was so excited. This article is just sharing the script code with a little explanation to avoid the error while it's executing.

Common Script

$username = "YOUR_TENANTACC" 
$password = "YOUR_PASS" 
$url = "YOUR_SITE_URL"

$securePassword = ConvertTo-SecureString $Password -AsPlainText -Force 

# the path here may need to change if you used e.g. C:\Lib.. 
Add-Type -Path "c:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll" 
Add-Type -Path "c:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll" 
Add-Type -Path "c:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.WorkflowServices.dll" 

# connect/authenticate to SharePoint Online and get ClientContext object.. 
$clientContext = New-Object Microsoft.SharePoint.Client.ClientContext($url) 
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $securePassword) 
$clientContext.Credentials = $credentials 

$web = $clientContext.Web
$clientContext.Load($web)
$clientContext.ExecuteQuery()

$lists = $web.Lists
$clientContext.Load($lists)
$clientContext.ExecuteQuery()

$lst = $lists.GetByTitle("YOUR_LIST")
$clientContext.Load($lst)
$clientContext.ExecuteQuery()

#get all workflow subscription in your web/sub-site
$wfServicesManager = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager($clientContext, $web)

$wfSubscriptionService = $wfServicesManager.GetWorkflowSubscriptionService()
$wfSubscriptions = $wfSubscriptionService.EnumerateSubscriptions()
$wfInstanceSevice = $wfServicesManager.GetWorkflowInstanceService()

$clientContext.Load($wfSubscriptions)
$clientContext.Load($wfInstanceSevice)
$clientContext.ExecuteQuery()

#initalize the parameters for workflow
$dictionary = New-Object 'system.collections.generic.dictionary[string,object]'
$dictionary.Add("YOUR_VARIABLE", "YOUR_VALUE")

#in case, if you need to start workflow on some items, you could execute the query and start on those items    
$qry = New-Object Microsoft.SharePoint.Client.CamlQuery
$qry.ViewXML = "<View><Query><Where>YOUR_QUERY</Where></Query></View>"
                
$items = $lst.GetItems($qry)
$clientContext.Load($items)
$clientContext.ExecuteQuery()

$srb = $wfSubscriptions | Where-Object { $_.Name -eq "YOUR_WORKFLOW_NAME" }

Start Workflow

$cnt = 0

foreach($itm in $items)
{
    $workflowInstances = $wfInstanceSevice.EnumerateInstancesForListItem($lst.ID, $itm.ID)
    $clientContext.Load($workflowInstances)
    $clientContext.ExecuteQuery()

    # bypass the item which the workflow instance was started
    $instance = $workflowInstances | Where-Object { $_.WorkflowSubscriptionId -eq  $srb.Id -and $_.Status -ne "Started" }
    
    if ($instance -ne $null)
    {
        $resultid = $wfInstanceSevice.StartWorkflowOnListItem($srb, $itm.Id, $dictionary)
        $clientContext.ExecuteQuery()
        Write-Host "Started workfkow [" $srb.Name  "] on item ["  $itm.Id  "]: " $resultid.Value -foregroundcolor Green
        Start-Sleep -s 1
        $cnt++
    }
}

Write-Host $cnt " are effected - Done!"

Stop Workflow 

$cnt = 0

foreach($itm in $items)
{
    $workflowInstances = $wfInstanceSevice.EnumerateInstancesForListItem($lst.ID, $itm.ID)
    $clientContext.Load($workflowInstances)
    $clientContext.ExecuteQuery()

    # bypass the item which the workflow instance was started
    $instance = $workflowInstances | Where-Object { $_.WorkflowSubscriptionId -eq  $srb.Id -and $_.Status -eq "Started" }
    
    if ($instance -ne $null)
        {
            $wfInstanceSevice.CancelWorkflow($instance)
            $clientContext.ExecuteQuery()
            Write-Host "Cancel Workfkow [" $instance.Id  "] on item ["  $itm.Id  "] " $instance.Status -foregroundcolor Red
            $cnt++
            Start-Sleep -s 1
        }
}

Write-Host $cnt " are effected - Done!"

Notes
  • Regarding to limitation on SharePoint Online, it only can start 5 workflows instance in a second. So, it should be delayed 1 second for each loop statement.
  • Just start a workflow if the workflow instance did not start and stop workflow if the workflow instance is running.

2 comments:

Unknown said...

I know this is an old post but I am so close but I can't get this working.
*I successfully get the items to go thorough but my variable for $wfSubscriptions.Count always comes back as 0 but I have 2 workflows on the list. If you're still monitoring this please suggest what I can try to get this working.

Rhygar said...

I have the same problem as Douglas