Assess Your SharePoint 2013 Workflows With Our Nintex Workflow Discovery Script

Microsoft’s recent announcement of the retirement of SharePoint 2013 workflows has caused many organisations to view their workflow platform. While SharePoint 2013 workflows have been a reliable tool for several years, it is clear that the shift to more modern and advanced automation solutions has become necessary.

Nintex has been a leader of workflow automation solutions. In response to Microsoft’s decision, Nintex announced its pathway to transition to Automation Cloud. This move is a strategic decision to provide its customers with a more advanced and modern automation experience. This is in line with the trend towards cloud-based automation solutions. There is also a heap more you can do with this platform that wasn’t available in Nintex on Office 365.

An overview of Nintex Automation Cloud

The Nintex Automation Cloud offers users a comprehensive and user-friendly platform for building, managing, and automating workflows across various applications and services. Its low code and drag-and-drop UI means that non-technical business usersas well as the tech savvy developercan build Nintex automated solutions. The platform offers a range of features, including:

  • Pre-built templates
  • Electronic signatures
  • Multiple states
  • Connectors to popular services such as Office 365, Azure, SharePoint
  • Its own Gateway to access your on-premises environment.

This level of integration enables organisations to streamline their processes, reduce manual tasks, and increase productivity.

Migrating SharePoint 2013 workflows to Nintex Automation Cloud

The migration process from Nintex’s SharePoint/Office 365 tools to the Nintex Automation Cloud is expected to be seamless and straightforward. Nintex has provided guidance and tools to assist customers in the migration process, ensuring that their workflows are seamlessly transferred to the new platform.

As Nintex partners, we have developed an easy-to-use script to assist clients make the move to Nintex Automation Cloud. The first part in tackling any migration or upgrade is to know what you have, and our script answers that question for you.

A close up of a computer screen with complex coding script

What does the script do?

The script’s base function is to audit the workflows across your SharePoint environment by entering a list of sites to scan. The output will describe the workflow name, list (or no list for site workflows), app publisher (to determine if it is Nintex), and when it was last updated.

During a workflow’s lifetime, details on SharePoint sites may change (such as list names, evenlist deletions). If a list is either changed or deleted, the workflow association still exists and has the name of the original list. Our SharePoint 2013 workflows script offers a parameter to check if the list still exists and what its new name is.

Running the script

Before you start, you will need to have these prerequisites installed; 

  1. SharePoint Online SDK: https://www.microsoft.com/en-us/download/details.aspx?id=42038 
  2. PowerShell 7: https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/PowerShell-7.3.4-win-x64.msi 
  3. PnP Powershell 2.1.x. Remove previous version and install new
    • Uninstall-Module PnP.PowerShell -force
    • Install-Module PnP.PowerShell -force
				
					## The following script is provided for informational and entertainment purposes only. The creators and contributors of this script shall ## not be held liable for any errors, omissions, or damages arising from the use, interpretation, or implementation of the content ## contained herein. The users of this script assume all responsibility and risk associated with its usage.

## By accessing or utilizing this script, you acknowledge and agree to release the creators and contributors from any and all liability ## arising from its use. This limited liability statement applies to all individuals or entities who access, view, or utilize this script ## in any form or manner.

## Copyright © 2023 - Propelle Pty Ltd www.propelle.com.au support@propelle.com.au



##Add DLL references if your session requires them
#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" -IgnoreWarnings
#Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.WorkflowServices.dll" -IgnoreWarnings

#Select $false if you want a quick scan, or select $true if you want detailed info (ie. if Library and List names have changed since workflows were created)
$detailedScan = $true
$exportXML = $true

$username = "usename@domain.com"
$password = "password^" 
$secureString = $password | ConvertTo-SecureString -AsPlainText -Force 
$creds = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureString

$sites = @(
    "https://domain.sharepoint.com/sites/Site1",
    "https://domain.sharepoint.com/sites/Site2",
    "https://domain.sharepoint.com/sites/Site3",
    "https://domain.sharepoint.com/sites/Site4",
    "https://domain.sharepoint.com/sites/Site5"
)

$associations = @()
$count = 0

if ($exportXML) {
    $parentFolder = "Workflows-$(Get-Date -Format "yyyy-MM-dd-HH-mm")"
    $supress = New-Item -Path "c:\temp" -Name $parentFolder -ItemType Directory -ErrorAction Ignore
}

foreach($site in $sites) {

    $count++
    Write-Progress -Activity "Reviewing Site Collection" -Status "$($count)/$($sites.Count) - $($site)" -PercentComplete ($count/$sites.Count*100)

    Connect-PnPOnline -Url $site -Credentials $creds

    $ctx = Get-PnPContext

    $Web = $ctx.Web
    $ctx.Load($Web)
    $ctx.ExecuteQuery()

    $WorkflowServicesManager = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager($Ctx, $Web)
    $workflowSubscriptionService  = $WorkflowServicesManager.GetWorkflowSubscriptionService()
    $workflowAssociations = $workflowSubscriptionService.EnumerateSubscriptions()
    $ctx.Load($workflowAssociations)

    if ($exportXML) {
        $workflowDeploymentService = $WorkflowServicesManager.GetWorkflowDeploymentService()
        $workflowDeployments = $workflowDeploymentService.EnumerateDefinitions($true)
        $ctx.Load($workflowDeployments)
    }

    $ctx.ExecuteQuery()

    $wfCount = 0

    foreach ($workflowAssociation in $workflowAssociations) {

        $wfCount++
        Write-Progress -Activity "Reviewing Workflows" -Status "$($wfCount)/$($workflowAssociations.Count) - $($workflowAssociation.PropertyDefinitions["SharePointWorkflowContext.Subscription.DisplayName"])" -PercentComplete ($wfCount/$workflowAssociations.Count*100)
        
        $listTitle = $null
        $listURI = $null
        if ($detailedScan) {
            if ($workflowAssociation.PropertyDefinitions["ListId"]) {
                $list = Get-PnPList -Identity $workflowAssociation.PropertyDefinitions["ListId"] -ErrorAction Ignore
                $listTitle = $list.Title
                $listURI = $list.EntityTypeName
            }
        }
        
        $associations += [PSCustomObject] @{
            WorkflowName                = $workflowAssociation.PropertyDefinitions["SharePointWorkflowContext.Subscription.DisplayName"]
            SiteURL                     = $workflowAssociation.PropertyDefinitions["CurrentWebUri"]
            OriginalListName            = $workflowAssociation.PropertyDefinitions["Microsoft.SharePoint.ActivationProperties.ListName"]
            ListName                    = $listTitle
            ListEntity                  = $listURI
            ModifiedBy                  = $workflowAssociation.PropertyDefinitions["ModifiedBy"]
            Enabled                     = $workflowAssociation.PropertyDefinitions["WSEnabled"]
            AppAuthor                   = $workflowAssociation.PropertyDefinitions["AppAuthor"]
            Created                     = $workflowAssociation.PropertyDefinitions["SharePointWorkflowContext.Subscription.CreatedDate"]
            Modified                    = $workflowAssociation.PropertyDefinitions["SharePointWorkflowContext.Subscription.ModifiedDate"]
        }
    }
    Write-Progress -Activity "Reviewing Workflows" -Completed 

    if ($exportXML) {

        $wfCount = 0
        $supress = New-Item -Path "c:\temp\$($parentFolder)" -Name $($ctx.Web.Title) -ItemType Directory -ErrorAction Ignore

        foreach ($workflowDeployment in $workflowDeployments) {
            
            $wfCount++
            Write-Progress -Activity "Exporting Workflows" -Status "$($wfCount)/$($workflowDeployments.Count) - $($workflowDeployment.DisplayName)" -PercentComplete ($wfCount/$workflowDeployments.Count*100)

            if ($workflowDeployment.Properties["RestrictToType"] -eq "List") {
                $list = Get-PnPList -Identity $workflowDeployment.Properties["RestrictToScope"] -ErrorAction Ignore
                $supress = New-Item -Path "c:\temp\$($parentFolder)\$($ctx.Web.Title)" -Name $list.Title -ItemType Directory -ErrorAction Ignore
                $directory = "c:\temp\$($parentFolder)\$($ctx.Web.Title)\$($list.Title)"
            }
            else {
                $directory = "c:\temp\$($parentFolder)\$($ctx.Web.Title)"
            }

            $xml = $workflowDeployment.Xaml
            $xml | Out-File -FilePath "$($directory)\$($workflowDeployment.DisplayName).xml"
            
        }
        Write-Progress -Activity "Exporting Workflows" -Completed 
    }

}

$associations | Export-Csv -NoTypeInformation -Path "c:\temp\$($parentFolder)\List of Workflows.csv"

				
			
A woman with her hair ties in a yellow scarf sits with her back to the camera, a dual computer screen in front of her. The left screen shows code, the right shows a workflow.
Options

Updating $detailedScan to $true will perform this extra check. However, enabling this will slow the script down as it has to make additional calls for each workflow. If you are scanning a large environment with lots of workflows and you are in a hurry, we recommend setting this to $false.

The script adds the functionality to extract all the workflow definitions as XML files. Updating $exportXML to $true will perform this extract for all workflows.

What else the scripts can help with?

Assist with finding hard coded values

Migrating from one environment to another often requires updates of URLs, domains, and emails. Having the definitions of the workflows in XML means you can easily search for values to find where they are being used rather than trying to open every workflow step manually.

You can also tweak the PowerShell script to include a search function when looking at each XML string on line 108.

Seeing links and accidentally deleted list workflows

When adding links in email actions in Nintex (as an example), once the link is added you can no longer see the formulated URL. Once you have the XML of the workflow definition, you can see exactly what the URL is defined as to help you update when needed.

If you’ve lost your workflow because you accidentally deleted your list, there’s a good chance the association is still in the Workflow Engine and will be extracted to an XML file.

Discover your migration options

The retirement of SharePoint 2013 workflows has prompted many organisations to rethink their workflow automation needs. The Nintex Automation Cloud is an impressive platform with a range of features. Propelle is happy to help customers make this transition to a more modern and efficient workflow automation solution.

Ready to start planning your migration? Reach out today. 

Get Insight!