Stop and restart specific item workflows in SharePoint 2010 Using Powershell

Stop and restart specific item workflows in SharePoint 2010 Using Powershell

While sending our company in a paperless direction, I found that as I published updated workflows to a library old versions were not only still running (as expected) but becoming corrupt, almost like they were getting “stale”. These stale workflows would behave abnormally the more I published changes to the same workflow. Since these were approval-style workflows, where various selected staff were supposed to complete task items, things weren’t getting completed, and the workflows were seeming to be sitting there, doing nothing.

The example here is applying to employee appraisals. With over 3000 employees, finding these “stuck” workflows on items, terminating them, then restarting them is not something anyone wants to do. So I came up with this Powershell script I run on the server that stops all old running instances of any workflows on the affected item, then prompts to restart the most recent version of the same workflow.

cls
$fc = $host.UI.RawUI.ForegroundColor
$web = "";
$host.UI.RawUI.ForegroundColor = "Yellow"
$site = Get-SPSite "";
$manager = $site.WorkFlowManager;
$targetweb = Read-Host "Enter the full URL of the site where the item is hosted";
$targetlist = Read-Host "Enter the name of the List where you want to search for the item";	
$itemname = Read-Host "Item name you are looking for? (partial name ok)";
write-Output "";

try 
{
	$web = Get-SPWeb $targetweb; 
	if($?)
	{}
	else
	{
	$host.UI.RawUI.ForegroundColor = "Red"
	write-Output "Cannot connect to that site, please try again";
	$host.UI.RawUI.ForegroundColor = $fc
	}
}
catch{}
$cnt = 0;
$web.AllowUnsafeUpdates = $true;      

#List Name  
$list = $web.Lists[$targetlist];  
$cnt = 0;
	
$host.UI.RawUI.ForegroundColor = $fc

# Iterate through all Items in List and all Workflows on Items.           
foreach ($item in $list.Items) 
{ 
	if($item["Title"] -like "*"+$itemname+"*")
	{ 
		foreach ($wf in $item.Workflows) 
		{  
			if(($wf.InternalState -ne "Completed") -and $wf.InternalState -ne "Cancelled"))
			{
				#Show status
				$x = $wf.ItemName.TrimEnd();
				write-Output $x;
				$cnt = $cnt + 1;
			}
			if($cnt -ne 0) 
			{
				$results = "This item has " + $cnt.tostring() + " workflows running.";
				write-Output "";
				write-Output $results;
				$host.UI.RawUI.ForegroundColor = "Red"
				$input = Read-Host "Do you want to stop all running workflows for this item and restart a new one? (Y/N)";
				$host.UI.RawUI.ForegroundColor = $fc
				if($input -ne "Y" -and $input -ne "y" -and $input -ne "YES" -and $input -ne "Yes" -and $input -ne "yes")
				{
					$cnt = 0;
				}
				else 
				{
					$cnt = 0;
					foreach ($wf in $item.Workflows) 
					{  
						if($wf.InternalState -ne "Completed" -and $wf.InternalState -ne "Cancelled")
						{
							# Stop workflow
						[Microsoft.SharePoint.Workflow.SPWorkflowManager]::CancelWorkflow($wf);  
							$cnt = $cnt + 1;
						}
					}
					# Restart the workflow
					#
					$association = $list.WorkFlowAssociations | where {$_.Name -eq ""}
					$association.AllowAsyncManualStart = $true
					$association.AllowManual = $true
					$data = $association.AssociationData;
					$newwf = $manager.StartWorkflow($item, $association, $data);
					$host.UI.RawUI.ForegroundColor = "Yellow"
					$results = $cnt.tostring() + " workflow(s) stopped & 1 new workflow restarted";
					write-Output "";
					write-Output $results;
					$host.UI.RawUI.ForegroundColor = $fc
					$cnt = 0;
				}
			} 
		}
	}
}
$web.Dispose();
$site.Dispose();
write-Output "";

The result was a nice, clean console UI that prompted for every item similar to the name I provided in the beginning, doing a fuzzy search and allowing me to either respond yes or no for each item. Any outstanding workflows for that selected item are terminated, and a new one is started. Note this is designed to work on lists/libraries with one workflow, such as an approval workflow. You may need to modify this code slightly for lists/libraries with multiple workflows, to make sure you terminate the correct one. Enjoy!

4 thoughts on “Stop and restart specific item workflows in SharePoint 2010 Using Powershell

  1. There is a typo in the code on line 41. It is missing opening brackets for the if clauses.
    should be:
    if(($wf.InternalState -ne “Completed”) -and $wf.InternalState -ne “Cancelled”)

  2. Are there any tricks to importing other libraries before running? Runs with error when I attempt to run it, never prompts for input.

    1. Hmm, I’m running on the actual SharePoint server using PowerShell for SharePoint, which in reality all it’s doing is pre-loading the SharePoint libraries for PowerShell. If you’re having this problem when running from the SharePoint 2010 server and using the SharePoint PowerShell environment, I would want to make sure you’re using at least PS v2.0 or higher. If you’re using Windows PowerShell and trying to run this, you may need to launch your PowerShell application like so:

      C:WindowsSystem32WindowsPowerShellv1.0powershell.exe -version 2.0 -NoExit ” & ‘ C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14CONFIGPOWERSHELLRegistration\sharepoint.ps1 ‘

      This will launch the SharePoint environment within PowerShell, which should resolve the issue. Please let me know either way if this helps or if I misunderstood.

Comments are closed.

Comments are closed.