The Enumerate Resources Activity (Microsoft.ResourceManagement.Workflow.Activities.EnumerateResourcesActivity) is used by Custom Workflows in FIM 2010 R2 to search for and retrieve objects in the FIM Portal/Service database using an XPath Filter. You will need to use this in place of the Read Resource Activity in situations where you do not already know the Resource ID of the object you wish to retrieve, or when you wish to retrieve multiple objects.
In some cases, you may simply want to use the activity to determine whether an object already exists (such as in a workflow that Generates a Unique Value or which generates automated role-based groups), but in most cases if you are searching for objects in the FIM Portal, we may want to do something with the objects returned. Now, unlike the Read Resources Activity, the Enumerate Resources Activity does not return a property with the results of its search – instead, we are able to nest activities inside the Enumerate Activity which execute for each object returned by the search filter (conceptually, you can think of this as a foreach on the results record).
Now, there are two complications with how to use the results returned. The first of these is that there is a bug in the Activity Designer for the Enumerate Resources Activity which means that you can’t nest an activity inside the Enumerate activity using the designer, and so have to do it manually. The second, is that you can only nest a single activity inside of the Enumerate Activity, and so you will need to use a Sequence Activity if you want to run multiple activities. The solution to both of these will be covered below.
In this example, we’re going to assume that a Department object (a custom object type created to hold organisational information) has been modified, and we now need to search for all users that have a string value for their Department attribute which matches the DisplayName of the Department object, and update the Manager attribute on each user. Note that if the user’s Department field was actually a reference value (as in Method 4 of our Populating RCDC Dropdowns example), you might search directly for a reference to the Department object (this will be covered below).
Step 1: Add a new Activity to your FIM Custom Activity Library

Step 2: Give that activity an appropriate name, in this case EnumerateResourcesExample.cs

Step 3: Add the relevant activities into the workflow In this example, we have added the Current Request Activity, a Read Resource Activity, an Enumerate Resources Activity, a Sequence Activity, an Update Resource Activity and two code activities

Note: The last Code Activity and the Update Resource Activity are nested in the Sequence Activity, which will in turn need to be nested manually inside the Enumerate Resource Activity by editing the designer directly. Refer to Step 7.
Step 4: Give the activities meaningful names.

Step 5: Double click each of the code blocks to promote the bindable properties for the code blocks.

Step 6: Right click on the Update Resource Activity and select Promote the bindable properties on the update activity.

Note: Unlike my Update Resource Activity Example, we are unable to assign the properties of the Update Resources Activity object directly and so must bind some Dependency Properties to the Activity. You’ll see how we use those later. Once you’ve created the dependency properties, you’ll see them generated in your activity source code:
public static DependencyProperty UpdateDepartmentUser_ActorId1Property = DependencyProperty.Register("UpdateDepartmentUser_ActorId1", typeof(System.Guid), typeof(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity)); [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [BrowsableAttribute(true)] [CategoryAttribute("Parameters")] public Guid UpdateDepartmentUser_ActorId1 { get { return ((System.Guid)(base.GetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity.UpdateDepartmentUser_ActorId1Property))); } set { base.SetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity.UpdateDepartmentUser_ActorId1Property, value); } } public static DependencyProperty UpdateDepartmentUser_ApplyAuthorizationPolicy1Property = DependencyProperty.Register("UpdateDepartmentUser_ApplyAuthorizationPolicy1", typeof(System.Boolean), typeof(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity)); [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [BrowsableAttribute(true)] [CategoryAttribute("Parameters")] public Boolean UpdateDepartmentUser_ApplyAuthorizationPolicy1 { get { return ((bool)(base.GetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity.UpdateDepartmentUser_ApplyAuthorizationPolicy1Property))); } set { base.SetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity.UpdateDepartmentUser_ApplyAuthorizationPolicy1Property, value); } } public static DependencyProperty UpdateDepartmentUser_ResourceId1Property = DependencyProperty.Register("UpdateDepartmentUser_ResourceId1", typeof(System.Guid), typeof(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity)); [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [BrowsableAttribute(true)] [CategoryAttribute("Parameters")] public Guid UpdateDepartmentUser_ResourceId1 { get { return ((System.Guid)(base.GetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity.UpdateDepartmentUser_ResourceId1Property))); } set { base.SetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity.UpdateDepartmentUser_ResourceId1Property, value); } } public static DependencyProperty UpdateDepartmentUser_UpdateParameters1Property = DependencyProperty.Register("UpdateDepartmentUser_UpdateParameters1", typeof(Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateRequestParameter[]), typeof(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity)); [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [BrowsableAttribute(true)] [CategoryAttribute("Parameters")] public Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateRequestParameter[] UpdateDepartmentUser_UpdateParameters1 { get { return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateRequestParameter[])(base.GetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity.UpdateDepartmentUser_UpdateParameters1Property))); } set { base.SetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivity.UpdateDepartmentUser_UpdateParameters1Property, value); } }
Step 7: Add the Microsoft.ResourceManagement references to your activity, as well as System.Collections.Generic so we can use the List Class for the UpdateRequestParameter object.

Step 8: Initialise the Read Resource Activity to read the target department (in this case, we’re assuming that the MPR which triggered the workflow occurred after a change to a Department object).

Step 9: Initialise the Enumerate Resources Activity. This is where we define the XPath Filter to search the FIM Portal database.

Note: If your user object had a Department reference field, you could configure your XPath Filter to search for all users with a reference, like this:

Step 10: For each object returned by the Enumerate Resources Activity, configure the Update Resource Activity to update the Manager attribute to the manager of their department.

Note: If a Code Activity was nested directly in the EnumerateResourcesActivity, we could pass the sender to the GetCurrentIterationItem method. However, because the sender object is the Sequence Activity, we actually need to call the Parent object of that to get the correct resource returned. If we were to just pass the sender, in this example, we would get a null value returned.
Step 11: Add another class to the project to create a basic UI for this activity, with the following code:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.ResourceManagement.Workflow.Activities; using Microsoft.IdentityManagement.WebUI.Controls; using FIMSpecialist.DemoLibrary.Activities; namespace FIMSpecialist.DemoLibrary.WebUIs { public class EnumerateResourcesActivityExampleUI : ActivitySettingsPart { public override System.Workflow.ComponentModel.Activity GenerateActivityOnWorkflow(SequentialWorkflow workflow) { if (!this.ValidateInputs()) { return null; } EnumerateResourcesActivityExample enumerateExample = new EnumerateResourcesActivityExample(); return enumerateExample; } public override void LoadActivitySettings(System.Workflow.ComponentModel.Activity activity) { EnumerateResourcesActivityExample enumerateExample = activity as EnumerateResourcesActivityExample; if (null != enumerateExample) { } } public override ActivitySettingsPartData PersistSettings() { ActivitySettingsPartData data = new ActivitySettingsPartData(); return data; } public override void RestoreSettings(ActivitySettingsPartData data) { if (null != data) { } } public override void SwitchMode(ActivitySettingsPartMode mode) { bool readOnly = mode == ActivitySettingsPartMode.View; } public override string Title { get { return "Enumerate Resources Activity Example"; } } public override bool ValidateInputs() { return true; } } }
And that’s it. From here, configure your Workflow in the FIM Portal, and setup an MPR to execute the workflow when a Department object’s manager field is modified.
Final code for EnumerateResourcesActivityExample.cs is as follows:
using System; using System.ComponentModel; using System.ComponentModel.Design; using System.Collections; using System.Linq; using System.Workflow.ComponentModel; using System.Workflow.ComponentModel.Design; using System.Workflow.ComponentModel.Compiler; using System.Workflow.ComponentModel.Serialization; using System.Workflow.Runtime; using System.Workflow.Activities; using System.Workflow.Activities.Rules; using Microsoft.ResourceManagement.WebServices.WSResourceManagement; using Microsoft.ResourceManagement.Workflow.Activities; using Microsoft.ResourceManagement.WebServices; using System.Collections.Generic; namespace FIMSpecialist.DemoLibrary.Activities { public partial class EnumerateResourcesActivityExample : SequenceActivity { // This is the guid for the FIM Service built-in admin account. // We will use it to execute each of our workflow activities. const string FIMAdminGuid = "7fb2b853-24f0-4498-9534-4e10589723c4"; public EnumerateResourcesActivityExample() { InitializeComponent(); } private void InitialiseReadDepartment_ExecuteCode(object sender, EventArgs e) { // Set the Actor ID for the Read Activity to the FIM Admin GUID ReadDepartment.ActorId = new Guid(FIMAdminGuid); // Set the Resource to retrieve as the currently requested object. // Note, you could also set this to the target ID of the containing workflow ReadDepartment.ResourceId = CurrentRequest.CurrentRequest.Target.GetGuid(); // Get the Manager attribute from the Department reference. ReadDepartment.SelectionAttributes = new string[] { "DisplayName", "Manager" }; } private void InitialiseSearchUsers_ExecuteCode(object sender, EventArgs e) { // Get the object that was read using the Read Activity Resource into a ResourceType object // In a real-world workflow, you should check that ReadDepartment.Resource isn't null ResourceType department = ReadDepartment.Resource; // Get the DisplayName for the group string displayName = (string)department["DisplayName"]; // Initialise the search for users whose department match the current department SearchDepartmentUsers.ActorId = new Guid(FIMAdminGuid); SearchDepartmentUsers.XPathFilter = String.Format("/Person[Department='{0}'", displayName); // SearchDepartmentUsers.XPathFilter = String.Format("/Person[DepartmentRef='{0}'", department.ObjectID.GetGuid()); } private void InitialiseUpdateUser_ExecuteCode(object sender, EventArgs e) { // Get the current object being processed by the Enumerate Resources Activity ResourceType currentUser = EnumerateResourcesActivity.GetCurrentIterationItem(((CodeActivity)sender).Parent) as ResourceType; // Put the Department object into a Resource Type object ResourceType department = ReadDepartment.Resource; // Get the manager reference from the object (again, you should check that it exists) // The manager reference in this case is stored as a UniqueIdentifier type. UniqueIdentifier manager = (UniqueIdentifier)department["Manager"]; UpdateDepartmentUser_ActorId1 = new Guid(FIMAdminGuid); UpdateDepartmentUser_ResourceId1 = currentUser.ObjectID.GetGuid(); // Create a list of UpdateRequestParameter objects ListupdateRequestParameters = new List (); // Add the Manager for this department to the Update Parameters list updateRequestParameters.Add(new UpdateRequestParameter("Manager", UpdateMode.Insert, manager)); // Convert the update parameters list into an array of UpdateRequestParameter objects and assign it // to the UpdateParameters property of the Update Resource Activity UpdateDepartmentUser_UpdateParameters1 = updateRequestParameters.ToArray (); } public static DependencyProperty UpdateDepartmentUser_ActorId1Property = DependencyProperty.Register("UpdateDepartmentUser_ActorId1", typeof(System.Guid), typeof(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample)); [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [BrowsableAttribute(true)] [CategoryAttribute("Parameters")] public Guid UpdateDepartmentUser_ActorId1 { get { return ((System.Guid)(base.GetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample.UpdateDepartmentUser_ActorId1Property))); } set { base.SetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample.UpdateDepartmentUser_ActorId1Property, value); } } public static DependencyProperty UpdateDepartmentUser_ApplyAuthorizationPolicy1Property = DependencyProperty.Register("UpdateDepartmentUser_ApplyAuthorizationPolicy1", typeof(System.Boolean), typeof(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample)); [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [BrowsableAttribute(true)] [CategoryAttribute("Parameters")] public Boolean UpdateDepartmentUser_ApplyAuthorizationPolicy1 { get { return ((bool)(base.GetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample.UpdateDepartmentUser_ApplyAuthorizationPolicy1Property))); } set { base.SetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample.UpdateDepartmentUser_ApplyAuthorizationPolicy1Property, value); } } public static DependencyProperty UpdateDepartmentUser_ResourceId1Property = DependencyProperty.Register("UpdateDepartmentUser_ResourceId1", typeof(System.Guid), typeof(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample)); [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [BrowsableAttribute(true)] [CategoryAttribute("Parameters")] public Guid UpdateDepartmentUser_ResourceId1 { get { return ((System.Guid)(base.GetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample.UpdateDepartmentUser_ResourceId1Property))); } set { base.SetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample.UpdateDepartmentUser_ResourceId1Property, value); } } public static DependencyProperty UpdateDepartmentUser_UpdateParameters1Property = DependencyProperty.Register("UpdateDepartmentUser_UpdateParameters1", typeof(Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateRequestParameter[]), typeof(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample)); [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] [BrowsableAttribute(true)] [CategoryAttribute("Parameters")] public Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateRequestParameter[] UpdateDepartmentUser_UpdateParameters1 { get { return ((Microsoft.ResourceManagement.WebServices.WSResourceManagement.UpdateRequestParameter[])(base.GetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample.UpdateDepartmentUser_UpdateParameters1Property))); } set { base.SetValue(FIMSpecialist.DemoLibrary.Activities.EnumerateResourcesActivityExample.UpdateDepartmentUser_UpdateParameters1Property, value); } } } }
Hi Ross I caught your article in search of a solution I need
I am walking through http://msdn.microsoft.com/en-us/library/windows/desktop/ff859524(v=vs.100).aspx = Walkthrough: Create a Logging Custom Activity and Deploy it to the FIM Portal
After completing step 3 = Add the following code to RequestLoggingActivity.cs after the class constructor
I get DependencyProperty with red underline.. which is stopping me binding to existing member .. I get the same DependencyProperty with red underline if I use the snippet to create WF dependency property
I am running VS2008 and have added all the R2 references…
I have installed ALL FIM components with FIM Sync, FIM Portal, pwd reg, pwd reset portal all working on the same Hyper-V Server 2008 R2 under windows 8
Stalling at such an early point in exploring workflows (:
Can you help please?
TIA
Nigel
Thanks Ross.. yep it was a newbie mistake.. moving forward now with the PD I had deferred for so many years when working for XXXXX
Hope you are well
Nigel
There’s nothing like getting your hands dirty with FIM! Can be a bit tricky at first, but once you get the hang of it, you’ll love it.
High Ross !
Thanks for your tutorials, very very helpful !
I’m having a hard time getting this one working though.
When the Workflow is executed, I get the error : NullReferenceException : object reference not set to an instance of an object
The code block triggering the error is :
InitialiseUpdateUser_ExecuteCode(object sender, EventArgs e)
{
ResourceType currentSet = EnumerateResourcesActivity.GetCurrentIterationItem(((CodeActivity)sender).Parent) as ResourceType;
I may be wrong but I guess that it’s because the Parent Object is null in this case.
In fact, in your tutorial, you spoke about the need to manually add the SequenceActivity as a child Activity to The EnumerateResourceActivity but you didn’t specify how.
Then since I couldn’t do it, the SequenceActivity has no Parent wich triggers the NullReferenceException.
My question therefore is :
How do you nest the SequenceActivity inside the EnumerateResource Activity ?
Thanks !
Hey Ross,
I’ve tried implementing a workflow that uses the same approach of adding a sequence activity as a child of the EnumerateResourcesActivity, and the sequence activity contains a code activity and an UpdateResourceActivity (same as what you have described above); however, the sequence activity does not seem to behave as I would expect.
The behavior that I’m seeing is that the code activity is executed for each resource returned by the enumeration activity, and only after the code activity has been executed for each resource is the update activity run, again once for each resource returned by the enumeration.
This causes problems with the above code as the code activity is setting the resource ID and UpdateRequestParameters that are bound to the UpdateResourceActivity, but the next time the code activity is executed, it overwrites the previous values before the update request is sent to FIM.
The end result is that there will be X update requests sent to FIM after the code activity is executed for each result, but all requests are exactly the same as the resource ID and the attributes to be updated will all be what was set during the last execution of the code activity.
This really is counter intuitive, in my opinion, as I would expect the entire sequence activity to execute for each resource (i.e. the sequence activity is the body of a foreach loop).
Have you seen similar behavior when using the EnumerateResourcesActivity with a sequence activity as a child?
Cheers,
Mark
Hi Ross,
I am trying to follow this code and are getting stuck at the sequenceAcivity. I am having the same problem as you did where the “numerateResourcesActivity.GetCurrentIterationItem” is returning Nothing.
I have tried both the “source” (which I know is wrong) & the “source.parent” (as stated).
I think what I am missing is this bit:
Note: The last Code Activity and the Update Resource Activity are nested in the Sequence Activity, which will in turn need to be nested manually inside the Enumerate Resource Activity by editing the designer directly. Refer to Step 7.
But your Step 7 only talks about adding references.
btw.. I’m doing this in vb (not my decision)
Thanks for any pointers.
best regards,
Nigel
Hi Ross,
As i am using the same workflow in my project, but i am getting the below mentioned error in WorkflowStatusDetail.
EXCEPTION DATA\r\n\r\nMESSAGE: Object reference not set to an instance of an object.\r\n\r\n**METHOD:Void InitialiseUpdateUser_ExecuteCode(System.Object, System.EventArgs)\r\n\r\n**METHOD:Void RaiseEvent(System.Workflow.ComponentModel.DependencyProperty, System.Object, System.EventArgs)\r\n\r\n**METHOD:System.Workflow.ComponentModel.ActivityExecutionStatus Execute(System.Workflow.ComponentModel.ActivityExecutionContext)\r\n\r\n**METHOD:System.Workflow.ComponentModel.ActivityExecutionStatus Execute(T, System.Workflow.ComponentModel.ActivityExecutionContext)\r\n\r\n**METHOD:System.Workflow.ComponentModel.ActivityExecutionStatus Execute(System.Workflow.ComponentModel.Activity, System.Workflow.ComponentModel.ActivityExecutionContext)\r\n\r\n**METHOD:Boolean Run(System.Workflow.ComponentModel.IWorkflowCoreRuntime)\r\n\r\n**METHOD:Void Run()\r\n\r\n