PowerShell Activity: Issues with GUIDs in Workflow Activities and Sync Rules


I recently faced a problem with GUIDs generated in a PowerShell Workflow Activity. As you can see in my previous blog posts I use the FIM PowerShell Workflow Activity a lot of times (nearly most the time).

Currently I’m working on provisioning of user accounts with exchange mailboxes, in addition I have to activate/create the Online Archive for users.

I’m following this blog article from Eihab Isaac for the correct attributes to set, except that I want to do all this with portal sync rules and declarative provisioning.
If you take a look at the article you can see that you have to provide a new GUID to the msExchArchiveGUID attribute in order to get the archive feature to work.

Since I had to write a PowerShell Activity script to determine the correct exchange mailbox and archive database (using the DB with the smallest amount of mailboxes but exclude some DBs that are used for special purposes) I thought it was a good idea to also create the GUID within the script.

At that point the issue came up to me. I concentrate to the GUID creation in this post, leaving out the special things about DB selection of mailbox and archive (maybe another post).

That’s what I’ve done in the activity/script:


$NewGUID = [GUID]::NewGuid()
$fimwf.WorkflowDictionary.Add('ArchiveGUID',$NewGUID)

(Simple create a GUID and pass that data to the workflow dictionary as a string.)

First I created a sync rule with a workflow parameter, like in the screenshot below:

GUIDIssue0

And use that parameter a variable in my outbound sync rule, by first converting it to a binary GUID:

GUIDIssue0a

After that I created a workflow which start with the above PowerShell script, followed by a sync rule activity and passing the GUID string data from the first activity to the next:

GUIDIssue1

After creating the necessary Set and MPR and doing all to trigger that triple I’ve got a PostProcessing Error in my Request Log and the ERE for the user was not created. In addition the eventlog shows the following warning:

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.ResourceManagement.WFActivities.Resolver.GetDisplayStringFromGuid(Guid id, String[] expansionAttributes)
   at Microsoft.ResourceManagement.WFActivities.Resolver.ReplaceGuidWithTemplatedString(Match m)
   at System.Text.RegularExpressions.RegexReplacement.Replace(MatchEvaluator evaluator, Regex regex, String input, Int32 count, Int32 startat)
   at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator)
   at Microsoft.ResourceManagement.WFActivities.Resolver.GetStringAttributeValue(Object attribute)
   at Microsoft.ResourceManagement.WFActivities.Resolver.ResolveEvaluatorWithoutAntiXSS(String match, ResolverOptions resolveOptions)
   at Microsoft.ResourceManagement.WFActivities.Resolver.ReplaceMatches(String input, Boolean useAntiXssEncoding, ResolverOptions resolveOptions)
   at Microsoft.ResourceManagement.Workflow.Hosting.ResolverEvaluationServiceImpl.ResolveLookupGrammar(Guid requestId, Guid targetId, Guid actorId, Dictionary`2 workflowDictionary, Boolean encodeForHTML, String expression)
   at Microsoft.ResourceManagement.Workflow.Activities.SynchronizationRuleActivity.CreateExpectedRuleEntry(String syncRuleName, String synchronizationRuleId, String action)
   at Microsoft.ResourceManagement.Workflow.Activities.SynchronizationRuleActivity.GenerateAddExpectedRuleEntry(ActivityExecutionContext executionContext)
   at Microsoft.ResourceManagement.Workflow.Activities.SynchronizationRuleActivity.Execute(ActivityExecutionContext executionContext)
   at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(T activity, ActivityExecutionContext executionContext)
   at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(Activity activity, ActivityExecutionContext executionContext)
   at System.Workflow.ComponentModel.ActivityExecutorOperation.Run(IWorkflowCoreRuntime workflowCoreRuntime)
   at System.Workflow.Runtime.Scheduler.Run()

You can see in the message that the FIM is trying to resolve the GUID to a portal object, but since that GUID is new and will never be a portal object, the operation fails.

It took me around an hour to find this out, activating debugging on the activity.

So what to do to get around this and pass the GUID to the next activity and therefore to the sync rule?

Since the portal can detect values that looks like a GUID in string, I found it the easiest way to let it not look like a GUID, simple by replacing the with a : which did the trick.

My final script then looks like this:


$NewGUID = [GUID]::NewGuid()
$ArchiveGUID = $NewGUID.Guid.Replace("-",":")
$fimwf.WorkflowDictionary.Add('ArchiveGUID',$ArchiveGUID)

And I added the “ReplaceString” function to the sync rule to format the value back to a string GUID:

GUIDIssue2

Now the activity works like charm, the GUID is passed to the sync rule and the exchange online archive was successfully created for the user.

The conclusion is to be carefully when working with “foreign” GUIDs in portal workflows if you don’t want them to be resolved and ran into the same issue that I did. In most cases the resoling of GUIDs to DisplayNames/Objects is very useful, but not in all.

I don’t know another way to get around this, if you have one let me know and give me a comment.

-Peter

Advertisements

About Peter Stapf
Senior Consultant Identity and Access MVP (Enterprise Mobility)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: