Tag Archives: 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!

Eric Oszakiewski

Eric Oszakiewski is a professional software developer based in Scottsdale, AZ with over 37 years of IT experience, and 19 years Native American Gaming experience. He is currently working as a .Net/SharePoint Development Lead for General Motors.

More Posts - Website

Follow Me:
TwitterFacebookLinkedInYouTube

Moving a SharePoint 2010 Web using PowerShell

One of the tasks I have at my workplace is to “migrate” SharePoint sites from one parent site to another as projects are closed out.  I wanted a solution to keep all of the business’s active project sites separate from their “archived” ones.  The problem arose when that “archive” has to happen.  You can’t just “move” a website in SP2010 (or at least, not in any way I’ve found or researched).  You can, however, export and import the site, so that’s what I did.  However, given the fact Microsoft will be moving away from STSADM in future builds of SharePoint, now was as good a time as any to start applying PowerShell.  Here’s what I came up with (save the following as a .ps1 file and run in the SharePoint 2010 Management Shell):
cls
# Prompt the user for the source project name URL fragment
#
$input = Read-Host "Enter the website (ex: http://portal/site)"
#
# Set variables
#
$sourceURL = $input
$web = Get-SPWeb $sourceURL
$web = $sourceWeb.Name
$targetURL = "http://portal/archive/"+$sourceName
$title = $web.Title
#
# Let's begin
#
Write-Host "Extracting source URL"
#
# Export the source site to the desktop
#
Export-SPWeb $sourceURL -Path "C:userspublicdocumentstemp.cmp" -Force -IncludeUserSecurity -IncludeVersions all -NoFileCompression -NoLogFile
#
# In PowerShell, we need to create the website first, then import it. This is a by-design security feature
# built into PowerShell.
#
Write-Host "Migrating site to target URL"
New-SPWeb $targetURL -Template "STS#0"
#
# Update the target title
#
$web = Get-SPWeb $targetURL
$web.Title = $title
$web.Update()
#
# Import the same site, overwriting the existing one we just made
#
Import-SPWeb $targetURL -Path "C:userspublicdocumentstemp.cmp" -UpdateVersions Overwrite -Force -IncludeUserSecurity -NoFileCompression -NoLogFile
Write-Host "Removing source site"
#
# Remove the source site
#
Remove-SPWeb $sourceURL -Confirm:$false
Write-Host "Completed"

This exported everything into a temporary location, including versioning and user security, created the target website using the default Template (STS#0 — you can substitute for whatever template you’re using, just make sure they match), then imports to the target location, overwriting everything and including original user security and versioning, and finally removes the original site.

I’m sure someone’s thought of a better or more efficient way of doing this, but this one is quick and works for me.  Hope it helps someone!

Eric Oszakiewski

Eric Oszakiewski is a professional software developer based in Scottsdale, AZ with over 37 years of IT experience, and 19 years Native American Gaming experience. He is currently working as a .Net/SharePoint Development Lead for General Motors.

More Posts - Website

Follow Me:
TwitterFacebookLinkedInYouTube

New code library site

I created a basic code library site to host all of the code snippets I’ve gathered and/or created over time. Go here to visit the site.

It’s pretty basic and empty right now, I’ll dress it up a little more as time goes on. I’m also trying to determine a better way of sub-categorizing the code in each of the language tabs. I welcome suggestions. Enjoy!

Eric Oszakiewski

Eric Oszakiewski is a professional software developer based in Scottsdale, AZ with over 37 years of IT experience, and 19 years Native American Gaming experience. He is currently working as a .Net/SharePoint Development Lead for General Motors.

More Posts - Website

Follow Me:
TwitterFacebookLinkedInYouTube