Nintex Workflow – PowerShell Find Workflows that contain a Specific Action Part 4

Nintex Workflow – PowerShell Find Workflows that contain a Specific Action Part 4 – Vadim Tabakman

This is Part 4 from the previous post on PowerShell Find All Workflows and Export or Republish.

We now have the ability to find all our workflows, export them to file and also to republish them. 

The next step, is to find which workflows use a specific action.  Let’s say you have a Call Web Service action and you have typed in the credentials into this action.  The credentials have no changed.  You need to update each workflow that uses this action, but you have many many workflows and finding which workflow uses this action would take a long time.

What we need, is to have the ability to type in an action name, and get a list of all the sites, lists and workflow names that use this particular action.

Changes to the PowerShell Script

The way to export and publish a workflow is via a web service call to the site where the workflow lives.  The Nintex Workflow web service url looks like this :

http://[siteurl]/_vti_bin/NintexWorkflow/Workflow.asmx

You can find some more information about this web service in the Nintex Workflow 2010 SDK.

Here is what the script looks like now.#
# AllWorkflows Script
#
# Version: 4.3
#
# This script was written as a starting off point for performing logic to all Nintex Workflows
# in your farm environment.
# I do not claim that this is 100% perfect and you should be careful using it in a production environment.
#
# USAGE
# =====
# Run the script to Find Workflows with an Action:
#   .\AllWorkflowsV4.ps1 -nwoperation FindWorkflowsWithAction -nwlogin domain\username -nwpassword password -nwaction “actionname”
# eg. to find all the workflows that contain the Math operation action
#   .\AllWorkflowsV4.ps1 -nwoperation FindWorkflowsWithAction -nwlogin domain\username -nwpassword password -nwaction “Math operation”
# Run the script to Export:
#   .\AllWorkflowsV4.ps1 -nwoperation ExportAll -nwlogin domain\username -nwpassword password
# Run the script to Republish:
#   .\AllWorkflowsV4.ps1 -nwoperation RepublishAll -nwlogin domain\username -nwpassword password
#
# History
# =======
# v4.3 – updated thes script to handle parameters better
#        It now support this format
#        -paramname paramvalue
#        nwoperation
#        nwlogin
#        nwpassword
#        nwtimeout
#        nwaction
# v4.2 – added support for non-list workflows (site, reusable, sitecollection reusable)
#        add hashtable to store already made web service connections (don’t need to connect again)
#

Param(
    [parameter(Mandatory=$true)]
    [alias(“nwoperation”)]
    $operation,
    [parameter(Mandatory=$true)]
    [alias(“nwlogin”)]
    $login,
    [alias(“nwpassword”)]
    $password,
    [alias(“nwtimeout”)]
    $timeout = 100000,
    [alias(“nwaction”)]
    $actionname)

[IO.Directory]::SetCurrentDirectory((Convert-Path (Get-Location -PSProvider FileSystem)))

# accept SSL Certificates if this is an SSL call
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

$siteHashTable = @{};

# build the credential object
$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($login,$secpasswd);

# check if we are in the same location as the nwadmin.exe
if(Test-Path(“.\nwadmin.exe”))
{
  # find all the workflows and store them in a variable
  $foundworkflows = .\nwadmin -o FindWorkflows

  # read the contents of the NWAdmin -o FindWorkflows
  # $foundworkflows = get-content “C:\Program Files\Nintex\Nintex Workflow 2010\workflows.txt”

  foreach($line in $foundworkflows)
  {
    if($line.StartsWith(“Active at “))
    {
      # get the site url
      $site = $line.Replace(“Active at “,””);
    }
    if($line.StartsWith(“– “))
    {
      # get the list name
      $list = $line.Replace(“– “,””);
    }
    if($line.StartsWith(“—- “))
    {
      try
      {
        # get the workflow name
        $workflowname = $line.Replace(“—- “,””);

        $webserviceurl = $site + “/_vti_bin/NintexWorkflow/Workflow.asmx”
        $knownSite = $siteHashTable.ContainsKey($webserviceurl);
        if($knownSite -eq $true)
        {
          # echo ‘This is a known site’;
          $page = $siteHashTable.Get_Item($webserviceurl);
        }
        else
        {
          # get web service proxy
          $page = New-WebServiceProxy -Uri $webserviceurl -Credential $credential;
          $page.Url = $webserviceurl;
          $page.Timeout = $timeout;
          # ($page | Get-Member -Name ExportWorkflow).definition;

          # echo ‘Adding site to hash table’;
          $siteHashTable.Add($webserviceurl,$page);
        }

        # export workflow
        if($list -eq “Site Workflow”)
        {$exportedworkflow = $page.ExportWorkflow($workflowname,$list,’Site’);}
        elseif($list -eq “Reusable workflow template”)
        {$exportedworkflow = $page.ExportWorkflow($workflowname,$list,’Reusable’);}
        elseif($list -eq “Site collection reusable workflow template”)
        {$exportedworkflow = $page.ExportWorkflow($workflowname,$list,’GloballyReusable’);}
        else
        {$exportedworkflow = $page.ExportWorkflow($workflowname,$list,’List’);}

        switch($operation)
        {
          “RepublishAll”
          {
            # republish this workflow
            if($list -eq “Site Workflow”)
            {$publishresult = $page.PublishFromNWFXml($exportedworkflow,””,$workflowname,$True);}
            elseif($list -eq “Reusable workflow template”)
            {$publishresult = $page.PublishFromNWFXml($exportedworkflow,””,$workflowname,$True);}
            elseif($list -eq “Site collection reusable workflow template”)
            {$publishresult = $page.PublishFromNWFXml($exportedworkflow,””,$workflowname,$True);}
            else
            {$publishresult = $page.PublishFromNWFXml($exportedworkflow,$list,$workflowname,$True);}              
          }
          “ExportAll”
          {
            $localfile = “{0}\{1}.nwf” -f [IO.Directory]::GetCurrentDirectory(),$workflowname;
            # $message = “Exporting workflow to – {0}” -f $localfile;
            # echo $message;
            $stream = [System.IO.StreamWriter] $localfile;
            $stream.WriteLine($exportedworkflow);
            $stream.close();
          }
          “FindActionsUsed”
          {
            $actions = [regex]::matches($exportedworkflow, “(?<=TLabel&gt;)[\w ]+(?=&lt;/TLabel)”);
            $arrayUniqueActions = @();

            # iterate through each action found
            foreach($action in $actions)
            {
              $arrayUniqueActions = $arrayUniqueActions + $action.Value;
            }
            $arrayUniqueActions = $arrayUniqueActions | select -uniq;
            $arrayUniqueActions;
          }
          “FindWorkflowsWithAction”
          {
            $actions = [regex]::matches($exportedworkflow, “(?<=TLabel&gt;)[\w ]+(?=&lt;/TLabel)”);

            # iterate through each action found
            foreach($action in $actions)
            {
              if($action.Value -eq $actionName)
              {
                $message = “{0} – {1} – {2}” -f $site,$list,$workflowname;
                echo $message;
                break;
              }
            }
          }
          default
          {
            echo “No operation”;
            break;
          }
        }
      }
      catch
      {
        $message = “Site – {0}” -f $webserviceurl;
        echo $message;
        $message = “List – {0}” -f $list
        echo $message;
        $message = “Workflow – {0}” -f $workflowname
        echo $message;
        # if ($_.Exception.InnerException) {
        #   echo $_.Exception.InnerException.message;
        # }
        # Write-Error (“Error – ” + $_);
        # $error[0];
        # echo $_.Exception.Message;
        # $_.Exception;
    # $_.Exception.Message[0];
        $exportedworkflow = “”;

        # end the loop (end the script) when an exception occurs
        break;
      }

      # only do this for the first workflow
      # break;
    }
  }
}
else
{
  echo “NWAdmin doesn’t exist.  Change directory to where NWAdmin.exe lives.”;
}

I’ve added a new operation named “FindWorkflowsWithAction”.  What this script does, is it finds each workflow from the NWAdmin command, then connects to the web service running on that site and makes a call to the ExportWorkflow web method, and then it runs some Regular Expression over the exported workflow, to interrogate it and find out which actions it contains.

How to run this PowerShell Script

Put the script file in to : c:\Program Files\Nintex\Nintex Workflow 2010

To run this script, open the SharePoint 2010 Management Shell. 

Change directories to c:\Program Files\Nintex\Nintex Workflow 2010

Run the script to Find Workflows with an Action:

   .\AllWorkflowsV4.ps1 -nwoperation FindWorkflowsWithAction -nwlogin domain\username -nwpassword password -nwaction “actionname”

eg. to find all the workflows that contain the Math operation action

   .\AllWorkflowsV4.ps1 -nwoperation FindWorkflowsWithAction -nwlogin domain\username -nwpassword password -nwaction “Math operation”

Run the script to Export:

   .\AllWorkflowsV4.ps1 -nwoperation ExportAll -nwlogin domain\username -nwpassword password

Run the script to Republish:

   .\AllWorkflowsV4.ps1 -nwoperation RepublishAll -nwlogin domain\username -nwpassword password

Output

The output of this script call will be:

[siteurl] – [listname] – [workflowname]

This should be enough to get you to your workflow.

Conclusion

This works on the title of the action.  I generally don’t change the title of my actions.  If I need to add some text to it to make my workflow more legible, I added it to the bottom label.  So if you changed the title, this script won’t find the action.  Instead, you may need to consider looking at the assembly name in the exported workflow.

You should now be able to find which workflow contains a specific action.

Don’t be afraid to tweak this to add more features that you may need.

If you find that you get timeouts (eg. publishing large worfklows), there is a -nwtimeout parameter you can use to increase the timeout.

Notes

29th Aug 2012 (v4.3) – add better support for parameters and web service timeout.

28th Aug 2012 (v4.2) – add support for Site Workflow, Reusable Workflow Templates and Site Collection Reusable Workflow Templates.

This script has not been tested with FBA or CBA.

28th Aug 2012 (v4.1) – I added some more error handling to this script.  It will now stop the script on the first exception it gets, and it will output the web service url, the list and the workflowname.  I’ve also added a line to accept SSL certificates.  I have tested this with an SSL site, but only one. Let me know if you find anything.

If you come across an exception, and you want to test this out for a single specific site/list/workflow, then you can try this script.  But you will need to type in the login, password, webservice url, list and workflowname:

try
{
  [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

  $login = “”;
  $password = “”;
  $webserviceurl = “”;
  $list = “”;
  $workflowname = “”;

  $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
  $credential = New-Object System.Management.Automation.PSCredential($login,$secpasswd);
  $webserviceurl = $webserviceurl
  $page = New-WebServiceProxy -Uri $webserviceurl -Credential $credential;
  $page.Url = $webserviceurl;
  $exportedworkflow = $page.ExportWorkflow($workflowname,$list,’List’);
  $publishresult = $page.PublishFromNWFXml($exportedworkflow,$list,$workflowname,$True);
}
catch
{
  echo $_;
}

Downloads

Nintex Workflow 2010 : v2.3.5.0

Download the AllWorkflowsV4 PowerShell script

Download the PublishSingleWorkflow PowerShell script

Leave a Reply

Your email address will not be published. Required fields are marked *