Find Failed On Start Workflows

By James|04/29/2020|, ,

Introduction

You may come into work one day and find that your workflows are failing.  Examining the workflow details will reveal "Failed On Start" errors.  Most likely this is due to a patch.  The fix for the patch is to manually add several lines to  the web.config file of your SharePoint web application servers.  In my case, I was replacing our SharePoint 2010 servers that were running Windows Server 2008 R2 with servers running Windows Server 2012 R2.  All patches were applied before the server was added to the SharePoint farm.  As such, the relevant web.config modifications were not in the web.config file.  The end result was the same, workflows failing to start on the new 2012 R2 front end servers.

Cause & Solution

Workflow Foundation (WF) will only run workflows when all the dependent types and assemblies are authorized in the .NET config file (or added explicitly via code) under this tree:

<configuration>
  <System.Workflow.ComponentModel.WorkflowCompiler>
    <authorizedTypes>
      <authorizedType Assembly="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" NameSpace="System.CodeDom" TypeName="CodeBinaryOperatorExpression" Authorized="True" />
      <authorizedType Assembly="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" NameSpace="System.CodeDom" TypeName="CodePrimitiveExpression" Authorized="True" />
      <authorizedType Assembly="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" NameSpace="System.CodeDom" TypeName="CodeMethodInvokeExpression" Authorized="True" />
      <authorizedType Assembly="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" NameSpace="System.CodeDom" TypeName="CodeMethodReferenceExpression" Authorized="True" />
      <authorizedType Assembly="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" NameSpace="System.CodeDom" TypeName="CodeFieldReferenceExpression" Authorized="True" />
      <authorizedType Assembly="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" NameSpace="System.CodeDom" TypeName="CodeThisReferenceExpression" Authorized="True" />
      <authorizedType Assembly="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" NameSpace="System.CodeDom" TypeName="CodePropertyReferenceExpression" Authorized="True" />

The above authorized types are the lines necessary to make SharePoint 2007 and 2010 start running workflows correctly again.  They should be applied to every SharePoint farm server that is running the Microsoft SharePoint Foundation Web Application service.

Post Fix

Once you've fixed your SharePoint farm servers, the next step is to find all the workflows that have failed on start.  The following PowerShell script will crawl your entire portal and report back on "Failed On Start" workflows:

# Title:   FindFailedOnStartWorkflows.ps1
# Version: 1.0, 22 APR 2020
# Author:  James Sanders
# Purpose: Find all workflows that failed on start

# Add the PowerShell Snap-In
Add-PSSnapin Microsoft.SharePoint.PowerShell -EA SilentlyContinue

# Set Variables
$wfFailedOnStart = 0
$wfDetails = ""
$timeStarted = Get-Date

# Enumerate portal looking for workflows that have failed on start
ForEach ($site in (Get-SPSite -Limit All)) {
  Write-Host
  Write-Host "Processing site:" $site.Url
  ForEach ($web in $site.AllWebs) {
    Write-Host "Processing web: " $web.Url
    ForEach ($list in $web.Lists) {
      If ((!($list.Hidden)) -And $list.WorkflowAssociations.Count -ge 1) {
        Write-Host "Processing list:" $list.Title
        ForEach ($item in $list.items) {
          # Find item workflows that have ran but are not in a "Completed" state
          $BadWorkflows = $item.workflows | Where {$_.InternalStatus -ne "Completed"}
          If ($BadWorkflows) {
            # Enumerate problematic workflows
            ForEach ($BadWorkflow in $BadWorkflows) {
              # Only looking for "Failed On Start" workflows, which is determined by Status1 field = 1
              If ($BadWorkflow.xml -match "Status1=""1""") {
                $wfa = $list.WorkflowAssociations | Where {$_.ID -eq $BadWorkflow.AssociationID}
                # Make sure there is not a newer run of the workflow that completed
                If ($item[$wfa.Name] -ne 5) {
                  Write-Host $Badworkflow.ParentItem.ID $wfa.Name "Failed On Start"
                  $wfStatus  = "<a href='$($web.URL)/_layouts/Workflow.aspx?ID=$($BadWorkflow.ParentItem.ID)&List={$($list.ID)}'>Status</a>"
                  $wfDetails += "$($site.RootWeb.Title),$($web.Title),$($list.Title),$($Badworkflow.ParentItem.ID),$($wfa.Name),$wfStatus|"
                  $wfFailedOnStart++
                }
              }
            }
          }
        }
      }
    }
    $web.Dispose()
  }
  $site.Dispose()
}

# Finalize script statistics
$timeFinished = Get-Date
$timeDuration = ("{0:hh\:mm\:ss}" -f ($timeFinished - $timeStarted)).Substring(0,12)

# Display statistics
Write-Host
Write-Host "Failed On Start Workflows: $wfFailedOnStart"
Write-Host
Write-Host "Script started:            $timeStarted"
Write-Host "Script finished:           $timeFinished"
Write-Host "Duration:                  $timeDuration"

$mailMsgServer  = "<YOUR_MAIL_SERVER>"
$mailMsgSubject = "Failed On Start Workflows"
$mailMsgFrom    = "<[email protected]>"
$mailMsgTo      = "<[email protected]>"

$mailMsgBody = ""
$mailMsgBody += "<style>"
$mailMsgBody += ".TR1 {border: 0px; padding: 0px; border-collapse: collapse;}"
$mailMsgBody += ".TD1 {border: 0px; padding: 0px;}"
$mailMsgBody += ".TH2 {border: 1px solid gray; padding: 0px; border-collapse: collapse; background-color: #80ffff;}"
$mailMsgBody += ".TR2 {border: 1px solid gray; padding: 0px; border-collapse: collapse;}"
$mailMsgBody += ".TD2 {border: 1px solid gray; padding: 2px; border-collapse: collapse;}"
$mailMsgBody += "</style>"
$mailMsgBody += "<table>"
$mailMsgBody += "<tr class='TR1'><td class='TD1'>Failed On Start Workflows:</td><td class='TD1'>$wfFailedOnStart</td></tr>"
$mailMsgBody += "<tr class='TR1'><td class='TD1' colspan='2'>&nbsp;<br/></td></tr>"
$mailMsgBody += "<tr class='TR1'><td class='TD1'>Script started:</td><td class='TD1'>$timeStarted</td></tr>"
$mailMsgBody += "<tr class='TR1'><td class='TD1'>Script finished:</td><td class='TD1'>$timeFinished</td></tr>"
$mailMsgBody += "<tr class='TR1'><td class='TD1'>Duration:</td><td class='TD1'>$timeDuration</td></tr>"
$mailMsgBody += "</table><br/>"
If ($wfDetails.Length -gt 0) {
  $mailMsgBody += "<table>"
  $mailMsgBody += "<tr class='TH2'><td class='TD2'>Site Collection</td><td class='TD2'>Web Site</td><td class='TD2'>List</td><td class='TD2'>ID</td><td class='TD2'>Workflow</td><td class='TD2'>Status</td></tr>"
  $wfDetailsLines = $wfDetails.Split("|")
  ForEach ($line in $wfDetailsLines) {
    If ($line.Length -gt 0) {
      $mailMsgBody += "<tr class='TR2'>"
      $wfDetailsItems = $line.Split(",")
      ForEach ($item in $wfDetailsItems) {
        $mailMsgBody += "<td class='TD2'>$item</td>"
      }
    }
    $mailMsgBody += "</tr>"
  }
}

$mailMsgBody += "</table><br/>"
Send-MailMessage -From $mailMsgFrom -to $MailMsgTo -subject $mailMsgSubject -Body $mailMsgBody -SmtpServer $mailMsgServer -BodyAsHTML

 

Modify the following lines to fit your organization:

$mailMsgServer  = "<YOUR_MAIL_SERVER>"
$mailMsgSubject = "Failed On Start Workflows"
$mailMsgFrom    = "<[email protected]>"
$mailMsgTo      = "<[email protected]>"

 

Copyright 2011 - 2024 The Lazy IT Admin | All Rights Reserved
menu-circlecross-circle linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram