Symptoms

After you install the following October security updates for Microsoft SharePoint Server, some Microsoft SharePoint 2010 workflow scenarios might be blocked. Additionally, "6ksbk" event tags are logged in SharePoint Unified Logging System (ULS) logs. 

Cause

To strengthen the security of SharePoint workflows, SharePoint now supports only UTF-8 character encoding for workflow .xoml files. 

Note: SharePoint workflow tools such as SharePoint Designer, Microsoft Visual Studio, and Nintex create workflow .xoml files using UTF-8 character encoding by default. Customers won't be affected by this security improvement unless they've manually edited their workflow .xoml files and converted them into a different character encoding. This issue is documented in this KB article on the extremely rare possibility that customers may have chosen to do this.

Workaround

If you've manually edited a workflow .xoml file and converted it into a character encoding other than UTF-8, you'll need to re-edit the file to convert it back to UTF-8. Make sure the file's XML declaration defines the encoding as UTF-8, save the file in the UTF-8 character encoding format with your text editor, and then redeploy it.

The following PowerShell script can be used in the SharePoint Management Shell to scan the workflow .xoml files in a SharePoint site collection to determine if they're affected by this change. The IsGoodWorkflow output will be True for workflow .xoml files that use UTF-8 character encoding and are compatible with this change. The IsGoodWorkflow output will be False for workflow .xoml files that aren't using UTF-8 character encoding and need to be modified.

<#
.SYNOPSIS
    Script to check character encoding of workflow .xoml files found in a site collection.
.DESCRIPTION
    This script checks the character encoding of workflow .xoml files found in a site collection based
    on the security improvement documented here: https://support.microsoft.com/topic/sharepoint-2010-workflows-might-be-blocked-by-enhanced-security-policy-kb5020238-eb91e24d-eea4-4490-a281-86503adc8b27
    
    This could be altered to take an SPWebApplication object, iterate through all SPSite objects in the Sites SPSiteCollection,
    and then iterate through all SPWeb subsites in the AllWebs SPWebCollection.

.EXAMPLE
    Get-WorkflowStatusForSite -SiteCollectionUrl https://sharepoint

.EXAMPLE
    Get-WorkflowStatusForSite -SiteCollectionUrl https://sharepoint -IgnoreSubSites
.INPUTS
    None
.OUTPUTS
    PSCustomObject with Site, Web, WorkflowFileName and IsGoodWorkflow Result

    Site                         Web                            WorkflowFileName       IsGoodWorkflow
    ----                         ---                            ----------------       --------------
    SPSite Url=http://sharepoint http://sharepoint/WorkflowTest 2010 Log Workflow.xoml           True
    SPSite Url=http://sharepoint http://sharepoint/WorkflowTest Another Test Log.xoml            True
.NOTES
    Version .1
#>
param(
    [Parameter(Position=2,HelpMessage="The site collection URL to validate.")]
    [string]$SiteCollectionUrl, 
    [Parameter(Position=3,HelpMessage="Ignore subsites below the top-level site in the site collection.")]
    [switch]$IgnoreSubSites
)

function IsGoodWorkflow
{
    param
    (
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [System.Xml.XmlReader]$xmlReader
    )

    try {
        $xDoc = [System.Xml.Linq.XDocument]::Load($xmlReader)

        if ($null -ne $xDoc -and $null -ne $xDoc.Declaration -and $null -ne $xDoc.Declaration.Encoding)
        {
            if ($xdoc.Declaration.Encoding.ToLower() -ne "utf-8")
            {
                return $false
            }
        }
    }
    catch
    {
        return $false
    }
        

    return $true
}

function CheckWorkflowFile
{
    param
    (
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [Microsoft.SharePoint.SPFile]$SPFile
    )

    $xmlReader = [System.Xml.XmlReader]::Create($SPFile.OpenBinaryStream())

    if ($null -ne $xmlReader)
    {
        $isGood = $xmlReader | IsGoodWorkflow

        $xmlReader.Close()
        $xmlReader.Dispose()
        
        return [PSCustomObject]@{
            Site = $SPFile.Item.Web.Site
            Web = $SPFile.Item.Web.Url
            WorkflowFileName = $SPFile.Name
            IsGoodWorkflow = $isGood
            }
    }
}

function CheckWorkflowsForWeb
{
    param
    (
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [Microsoft.SharePoint.SPWeb]$SPWeb
    )

    write-host "Checking $SPweb"
    $WorkflowsList = $SPWeb.Lists["Workflows"]

    $results = @()

    if ($WorkflowsList)
    {
        Write-Host "Found: " $WorkflowsList.Title

        foreach ($listItem in $WorkflowsList.Items)
        {
            if ($listItem.File -and $listItem.File.Name.ToLower().EndsWith(".xoml"))
            {
                Write-Host "Found Workflow: " $listItem.File.Name
                $results += (CheckWorkflowFile $listItem.File)
            }
        }
    }
    return $results
}

function CheckWorkflowsForSite
{
    param
    (
    [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
    [Microsoft.SharePoint.SPSite]$SPSite,
    [switch]$IgnoreSubSites
    )
    
    $results = @()

    if ($IgnoreSubSites)
    {
        $SPWeb = $SPSite.RootWeb

        $results += CheckWorkflowsForWeb $SPWeb

        $SPWeb.Dispose()
    }
    else
    {
        foreach ($SPWeb in $SPSite.AllWebs)
        {
            $results += CheckWorkflowsForWeb $SPWeb
            $SPWeb.Dispose()
        }
    }
    
    return $results
}

if ([string]::IsNullOrEmpty($SiteCollectionUrl))
{
    $SiteCollectionUrl = Read-Host "Please provide a site collection URL (Default: http://sharepoint)"
    if ([String]::IsNullOrEmpty($SiteCollectionUrl))
    {
        $SiteCollectionUrl = "http://sharepoint"
    }
}

$SPSite = Get-SPSite $SiteCollectionUrl -ErrorAction SilentlyContinue

if ($null -eq $SPSite)
{
    Write-Host "Site collection $SiteCollectionUrl not found." -ForegroundColor Red
    return;
}

$results = CheckWorkflowsForSite $SPSite

# Dispose of the Site
$SPSite.Dispose()

# Results can be exported to a CSV or manipulated
$results

Change history

The following table summarizes some of the most important changes to this topic.

Date

Description

November 22, 2022

Added a note in the "Cause" section and updated the "Workaround" section with a PowerShell script to scan the workflow .xoml files.

Need more help?

Want more options?

Explore subscription benefits, browse training courses, learn how to secure your device, and more.

Communities help you ask and answer questions, give feedback, and hear from experts with rich knowledge.