locked
How to terminate a specific list workflow using PowerShell Online RRS feed

  • Question

  • Hi All,

    We are working in SharePoint Online sites which have designer workflows associated with its lists.  Based on requirement, we have to make changes in workflow. After the changes, we've stop all the running workflows and restart it.

    A list can have multiple workflows but I need to terminate and restart a specific workflow and not all the workflows.
    Suppose List A is having 2 running workflows say: Workflow 1 & Workflow 2. I need to stop and restart only Workflow 1 for all the items in List A.

    Can anyone suggest a PowerShell Online Script for this?

    Thanks,


    Kunal

    Tuesday, April 11, 2017 7:20 AM

Answers

  • Use "WorkflowSubscriptionId" parameter to terminate particular workflow of the item. Something like below...

    if($WorkflowAssociations[$i].Id -eq $itemWfInstances[$k].WorkflowSubscriptionId)
       {
                try {
                $WorkflowInstanceService.TerminateWorkflow($itemWfInstances[$k])
                write-host $itemWfInstances[$k].WorkflowSubscriptionId 
                    
                      $msg = "Worfklow terminated on " + $ListItems[$j].Id
                      $ClientContext.ExecuteQuery()
                } catch {
                      $msg = "Error terminating workflow on " + $ListItems[$j].Id + " Details: $_"
                }
     
                Write-Host $msg
    }
    Inside "For Loop" of terminate workflow Section...

     
    • Marked as answer by Kunal Basu Wednesday, April 12, 2017 8:49 AM
    Wednesday, April 12, 2017 6:45 AM

All replies

  • Refer Below URL's

    Stop Workflow:

    http://www.rapidcircle.com/powershell-terminate-a-workflow-for-all-items-in-a-list-on-sharepoint-online/

    Start Workflow:

    http://www.rapidcircle.com/powershell-start-a-workflow-for-all-items-a-list-on-sharepoint-online/

    Note : The Above URL Powershell script will stop/start first workflowInstance, In order to stop/Start particular(Your own)workflow you need to do some filter with this parameter"$WorkflowAssociations"

    Try this script:

    Add-Type -Path (Resolve-Path "$env:CommonProgramFiles\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll")
    Add-Type -Path (Resolve-Path "$env:CommonProgramFiles\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll")
    Add-Type -Path (Resolve-Path "$env:CommonProgramFiles\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.WorkflowServices.dll")
    
    # Specify tenant admin and site URL
    $SiteUrl = "<Site URL>"
    $ListName = "<Your List Name>"
    $UserName = "<user Name>"
    $SecurePassword = ConvertTo-SecureString -String "<Password>*" -AsPlainText -Force
     
    # Connect to site
    $ClientContext = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl)
    $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword)
    $ClientContext.Credentials = $credentials
    $ClientContext.ExecuteQuery()
     
    # Get List and List Items
    $List = $ClientContext.Web.Lists.GetByTitle($ListName)
    $ListItems = $List.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery())
    $ClientContext.Load($List)
    $ClientContext.Load($ListItems)
    $ClientContext.ExecuteQuery()
     
    # Retrieve WorkflowService related objects
    $WorkflowServicesManager = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager($ClientContext, $ClientContext.Web)
    $WorkflowSubscriptionService = $WorkflowServicesManager.GetWorkflowSubscriptionService()
    $WorkflowInstanceService = $WorkflowServicesManager.GetWorkflowInstanceService()
    $ClientContext.Load($WorkflowServicesManager)
    $ClientContext.Load($WorkflowSubscriptionService)
    $ClientContext.Load($WorkflowInstanceService)
    $ClientContext.ExecuteQuery()
    # Get WorkflowAssociations with List
    $WorkflowAssociations = $WorkflowSubscriptionService.EnumerateSubscriptionsByList($List.Id)
    $ClientContext.Load($WorkflowAssociations)
    $ClientContext.ExecuteQuery()
     
    # Prepare Start Workflow Payload
    $Dict = New-Object 'System.Collections.Generic.Dictionary[System.String,System.Object]'
     
     Write-Host $WorkflowAssociations.count
    
     for($i=0;$i -lt $WorkflowAssociations.count;$i++){
    
    
     if($WorkflowAssociations[$i].Name -eq "<Your Workflow>"){
    
     
     Write-Host "Workflow Name" $WorkflowAssociations[$i].Name
    
     #Terminate Workflow 
    
     For ($j=0; $j -lt $ListItems.Count; $j++){
     
       $msg = [string]::Format("Killing workflows {0} on ListItemID {1}", $WorkflowAssociations[$i].Name, $ListItems[$j].Id)
       Write-Host $msg
     
       $itemWfInstances = $WorkflowInstanceService.EnumerateInstancesForListItem($List.Id, $ListItems[$j].Id)
       $ClientContext.Load($itemWfInstances)
       $ClientContext.ExecuteQuery()
       for ($k=0;$k -lt $itemWfInstances.Count;$k++)
       {
                try {
                $WorkflowInstanceService.TerminateWorkflow($itemWfInstances[$k])
                      $msg = "Worfklow terminated on " + $ListItems[$j].Id
                      $ClientContext.ExecuteQuery()
                } catch {
                      $msg = "Error terminating workflow on " + $ListItems[$j].Id + " Details: $_"
                }
     
                Write-Host $msg
       }
    }
    
    # Loop List Items to Start Workflow
    For ($k=0; $k -lt $ListItems.Count; $k++){
        $msg = [string]::Format("Starting workflow {0}, on ListItemId {1}", $WorkflowAssociations[$i].Name, $ListItems[$k].Id)
        Write-Host $msg
        #Start Workflow on List Item
        $Action = $WorkflowInstanceService.StartWorkflowOnListItem($WorkflowAssociations[$i], $ListItems[$k].Id, $Dict)
        $ClientContext.ExecuteQuery()
    }
     
     }
     
     }





    • Edited by Dillibabub Tuesday, April 11, 2017 1:26 PM
    Tuesday, April 11, 2017 9:34 AM
  • Hi Dillibub,

    Thanks for the script. But there is one issue.

    The script could able to start a specific workflow but it terminates all the workflows related to that item. I need to terminate and restart a specific workflow.

    Thanks,



    Kunal


    • Edited by Kunal Basu Tuesday, April 11, 2017 1:20 PM
    Tuesday, April 11, 2017 12:58 PM
  • Now try above code...Meanwhile please share your script...Since, the above code working fine in my environment.
    Tuesday, April 11, 2017 1:28 PM
  • Hi Dillibabub,

    Please see the below script. It terminates all the workflows on a list item but starts only a specific workflow (WFTest). I want it to terminate a specific workflow even.

    Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
    Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
    Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.WorkflowServices.dll"

    # Specify tenant admin and site URL
    $SiteUrl = "https://testlsharepoint.sharepoint.com/sites/developer/"
    $ListName = "TestList"
    $UserName = "kunnu@TestlSharePoint.onmicrosoft.com"
    $SecurePassword = Read-Host -Prompt "Enter password" -AsSecureString
     
    # Connect to site
    $ClientContext = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl)
    $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword)
    $ClientContext.Credentials = $credentials
    $ClientContext.ExecuteQuery()
     
    # Get List and List Items
    $List = $ClientContext.Web.Lists.GetByTitle($ListName)
    $camlQuery = new-object Microsoft.SharePoint.Client.CamlQuery;
    $camlQuery.ViewXml = "<View>
    <Query>
     <Where> 
          <Contains>   
           <FieldRef Name='Frequency' /> 
                <Value Type='Choice'>Quarterly</Value>
             </Contains>
           </Where>
     </Query>
    </View>"
    $ClientContext.Load($List)
    $ClientContext.ExecuteQuery()

    $ListItems = $List.GetItems($camlQuery)
    $ClientContext.Load($ListItems)
    $ClientContext.ExecuteQuery()
     
    # Retrieve WorkflowService related objects
    $WorkflowServicesManager = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager($ClientContext, $ClientContext.Web)
    $WorkflowSubscriptionService = $WorkflowServicesManager.GetWorkflowSubscriptionService()
    $WorkflowInstanceService = $WorkflowServicesManager.GetWorkflowInstanceService()
    $ClientContext.Load($WorkflowServicesManager)
    $ClientContext.Load($WorkflowSubscriptionService)
    $ClientContext.Load($WorkflowInstanceService)
    $ClientContext.ExecuteQuery()
    # Get WorkflowAssociations with List
    $WorkflowAssociations = $WorkflowSubscriptionService.EnumerateSubscriptionsByList($List.Id)
    $ClientContext.Load($WorkflowAssociations)
    $ClientContext.ExecuteQuery()
     
    # Prepare Start Workflow Payload
    $Dict = New-Object 'System.Collections.Generic.Dictionary[System.String,System.Object]'
     
     Write-Host $WorkflowAssociations.count

     for($i=0;$i -lt $WorkflowAssociations.count;$i++){


     if($WorkflowAssociations[$i].Name -eq "WFTest"){

     
     Write-Host "Workflow Name" $WorkflowAssociations[$i].Name

     #Terminate Workflow 

     For ($j=0; $j -lt $ListItems.Count; $j++){
     
       $msg = [string]::Format("Killing workflows {0} on ListItemID {1}", $WorkflowAssociations[$i].Name, $ListItems[$j].Id)
       Write-Host $msg
     
       $itemWfInstances = $WorkflowInstanceService.EnumerateInstancesForListItem($List.Id, $ListItems[$j].Id)
       $ClientContext.Load($itemWfInstances)
       $ClientContext.ExecuteQuery()
       for ($k=0;$k -lt $itemWfInstances.Count;$k++)
       {
                try {
                $WorkflowInstanceService.TerminateWorkflow($itemWfInstances[$k])
                      $msg = "Worfklow terminated on " + $ListItems[$j].Id
                      $ClientContext.ExecuteQuery()
                } catch {
                      $msg = "Error terminating workflow on " + $ListItems[$j].Id + " Details: $_"
                }
     
                Write-Host $msg
       }
    }

    # Loop List Items to Start Workflow
    For ($k=0; $k -lt $ListItems.Count; $k++){
        $msg = [string]::Format("Starting workflow {0}, on ListItemId {1}", $WorkflowAssociations[0].Name, $ListItems[$k].Id)
        Write-Host $msg
        #Start Workflow on List Item
        $Action = $WorkflowInstanceService.StartWorkflowOnListItem($WorkflowAssociations[0], $ListItems[$k].Id, $Dict)
        $ClientContext.ExecuteQuery()
    }
     
    }
     
    }


    Kunal


    • Edited by Kunal Basu Tuesday, April 11, 2017 1:53 PM
    Tuesday, April 11, 2017 1:43 PM
  • Use Modified PowerShell Script of mine and let me know...I test in environment and its working fine.

    My Workflow : "WorkflowB"

    Screen shot:


    Tuesday, April 11, 2017 2:52 PM
  • Hi Dillibub,

    That is exactly what I am getting. Can you see 3 instances of workflows getting terminated for ListItemID 17 and single instance for WorkflowB got resumed. It terminated all the workflows running on ListItemID 17 and initiated only WorkflowB.

    What I need is only WorkflowB should get terminated and then to resume. It shouldn't terminate all the workflows running. Can you check on that list item and share a screenshot whether it kills all the workflows or not.

    Thanks,


    Kunal

    Wednesday, April 12, 2017 5:46 AM
  • Use "WorkflowSubscriptionId" parameter to terminate particular workflow of the item. Something like below...

    if($WorkflowAssociations[$i].Id -eq $itemWfInstances[$k].WorkflowSubscriptionId)
       {
                try {
                $WorkflowInstanceService.TerminateWorkflow($itemWfInstances[$k])
                write-host $itemWfInstances[$k].WorkflowSubscriptionId 
                    
                      $msg = "Worfklow terminated on " + $ListItems[$j].Id
                      $ClientContext.ExecuteQuery()
                } catch {
                      $msg = "Error terminating workflow on " + $ListItems[$j].Id + " Details: $_"
                }
     
                Write-Host $msg
    }
    Inside "For Loop" of terminate workflow Section...

     
    • Marked as answer by Kunal Basu Wednesday, April 12, 2017 8:49 AM
    Wednesday, April 12, 2017 6:45 AM
  • Hi Dillibabub,

    Thanks for your most valuable solution. It worked.

    Thanks,


    Kunal

    Wednesday, April 12, 2017 8:50 AM