Users unable to loop - Site Workflow UDA

Automation Master
Automation Master
5 4 2,241


In our organisation we have the nintex workflow actions tightly controlled as follows:

  • Untrained users:  no access to any actions
  • Trained users:  access to subset of actions
  • SharePoint support users:  full access to all actions

The reason for this is governance (which I will get round to blogging about one day I am sure).  We do not allow the trained users any actions that can loop that with poor configuration could maybe bring down the environment or affect the performance in some way.


These trained users almost always have a requirement for a "reminder" workflow of sorts, to notify people when a document is due for review, or if a task is outstanding and x days overdue (like many users on the community).  Anyone on the community with this requirement will have been sent by me to my blog post Site Workflow - Document Review Date Approaching Reminders‌ or to the solution on Nintex Xchange™Document Review Reminder Process‌.  However, these users are not allowed any looping actions so are unable to use the for each and so, at the moment, have to come to SharePoint support staff to get the solution they require.

Solution - Site Workflow UDA

Inspired by Nintex Xchange™‌ and a UDA solution posted by Vadim Tabakman‌ I decided to see if I could create a site workflow UDA whereby the UDA could do the looping for the user and it therefore wouldn't matter that they do not have access to the actions inside the UDA.  This is one of the best things about UDAs - it's a fantastic way of empowering your users to do something cool without "letting" them develop it themselves.  This way you have control of these more complex actions and can be confident that the environment won't be impacted by their configuration.  Well, if they do impact environment performance, then you know who is to blame - haha.

I called the UDA "Notification Date Reached UDA" and configured it as follows:


List NameTextInputThe name of the list that the items need to be pulled from when meeting the date specified, I.e. "Procedures"
Date Field NameTextInputThe name of the date field in the {List Name} to compare with the specified date
Email SubjectTextInputSubject of email to be sent
Email To FieldTextInputThe name of the column used to locate the recipient of email
Email MessageTextInputBody of email to be sent
ErrorTextOutputTo be used to store any error messages
Number of Days AfterNumberInputIf date comparison is not for today, but for x number of days after the event
Number of Days BeforeNumberInputIf date comparison is not for today, but for x number of days before the event


vCollReturnedIDsCollectionInside the UDA, the query list of the specified list name will return 0 or more items and store the IDs into the collection
vDateComparisonDate and TimeThe date calculated based on the parameters above to compare with the list and filter the returned items
vTextCurrentIDSingle line of textThe current item in the collection (stored as text for the CAML query) used to query the given list name to find the {Email To Field} value
vTextNotificationContactSingle line of textUsed to store the value for {Email To Field}


I do some checking of the "number of days after" and "number of days before" parameters.  If both are zero then it would indicate that the user would like to match for items where {Date Field Name} = today's date.  So in this instance I set variable value vDateComparison = Common:CurrentDate.  If both parameters are not zero then it would imply that the user either wants to send a notification x days before the {Date Field Name}, or x days after.  This logic does just that:

OK, so now we have our comparison date I go ahead and query the specified list matching where the specified date field = specified date.  I do this using CAML query and return the IDs into the collection variable vCollReturnedIDs:

Using for each to loop through my collection, I use the current item in the collection (vTextCurrentID) and query the specified list again to get the specified {Email To Field}. This is again done with a CAML query as follows and outputs the variable vTextNotificationContact:

Still in the for each I send an email to the variable value returned using the subject and message body specified in the parameters.  Job done.

Using this UDA

To use the UDA I created a brand new site workflow, added the UDA and configured it as follows:

and the list looked like this:

When I run the site workflow today (20/02/2017) I get three emails!


Ok so this is early days and there are many! 

  1. The fact that I need to use the internal names in my parameters (because of the CAML query).  I don't want these users to loop for fear they don't understand looping, so do I think they will know how to find the internal name of a column?!
  2. This is only bringing back some dynamic data from the list - the rest is static.  This could be extended to suit and pull additional information about the item due for review - but there doesn't seem to one size fits all approach when I have no idea what sort of list it will be used on
  3. At this point I have only set it up for either a date before or a date after.  In reality most people want to remind before the date, remind on the date, and remind after the date!  This can be easily overcome.
  4. (enter yours in the comments)

The solution will be posted on ‌ shortly.

Automation Master
Automation Master

Well written, Cassy! I think this will help folks who follow similar governance. (Which is also very well done. And you know how I feel about that  )

Automation Master
Automation Master

‌ I have some ideas on that - we need to get our agreed ideas on governance on here somewhere.

Cloud Wanderer

Image result for jurassic park clever girl meme

Automation Master
Automation Master

Cool stuff.

A quick thought. Give the workflow designer a little utility to find the internal name. You could deploy it as an app that they can add to their site and then they type the name of their list in and it returns the Display Names vs Internal Names. You can do this with some Javascript.

<input type="text" id="ListName" value="Tasks"></input>
<button onclick='GetFieldList()'>Get Field List</button>

<script type="text/javascript">

function GetFieldList()
  var listname = document.getElementById("ListName").value;
  var ctx = SP.ClientContext.get_current();
  this.web = ctx.get_web();
  this.list = web.get_lists().getByTitle(listname);
  this.fields = this.list.get_fields();

  ctx.executeQueryAsync(Function.createDelegate(this, this.getListInfoSuccess), Function.createDelegate(this, this.getListInfoFail));

function getListInfoSuccess(sender, args)
        var fieldEnumerator = this.fields.getEnumerator();
        var results="";
        while (fieldEnumerator.moveNext()) {
            var oField = fieldEnumerator.get_current();
            if (!oField.get_hidden())
            results+= oField.get_title()
                + " - " + oField.get_internalName()
                + " - " + oField.get_hidden()
                + "\n";
function getListInfoFail(sender, args)
alert('Something failed. Error:'+args.get_message());   


There's a number of ways to retrieve this info. Just depends on how slick you want to be here.