I wanted to follow up the BPOS Powershell Activity with an explanation of why I’m running some of the powershell actions in the Authorization phase.
The roll back problem
I was thinking about the best way to roll back a change in the Portal if the powershell failed. Say I add a forwarding address in the Portal, triggering the BPOS Powershell Activity to run the relevant cmdlet, but the cmdlet returned a failure status. I now have incorrect data in the Portal: a forwarding address appears to be set but in reality this is not the case.
If you’re running the powershell in the Action phase the data has already been committed to the database so for a failure you will actually have to roll back the change. Unfortunately this is not so simple. By this time you don’t know the previous state of the changed attribute (or attributes), and you can’t get that information from the Request object. The only sure way would have been to run a custom activity in the AuthZ phase which writes the previous values to custom attributes on the Request object and … no I can’t go on, my brain is saying “YUCK” too loudly to continue.
About the only thing you can do is clear the attribute if the change failed. This will in fact work fine for the forwarding address, where there either is an address or there isn’t, but won’t be applicable to all cases.
So run the powershell before committing the change
And now to the AuthZ phase. Here the change is not yet committed and so, if the powershell fails, we can throw an error and prevent the change. In fact you can look at it like this: our powershell activity is actually authorizing the change to the database, based on whether it succeeds or fails.
But (and there’s always a But) it’s much trickier to get at the changed attribute(s) in the AuthZ phase. Beacuse they’re not yet written to the Target you have to get them from the Request object and that’s not nearly so straight-forward. It’s even trickier when there are reference attributes involved (as in the forwarding address example). In any case, more custom activity writing will be necessary.
Here’s my compromise: For BPOS powershell activities, I run activities which add stuff in the Action phase, and activities which remove stuff in the AuthZ phase.
The big advantage from a pure workflow pov is that I only ever need to use attributes already written to the Target. When doing a remove I’m interested in the “before” values, and for an add it’s the “after” values.
Going back to the forwarding address, if I change the forwarding object then I actually have to run a Remove on the old value, followed by an Add on the new value.
Which brings me to another advantage: by running the Remove in the AuthZ phase and the Add in the Action phase I can ensure they run in that order. Important!
And also, from a general functionality perspectve, I think it bad to let people think something is deleted when it is not.
I am also managing BPOS mailbox delegations in the FIM Portal so let’s work through some scenarios.
A delegation is added which gives Full Access to a mailbox. The powershell fails for some reason. Using the “Clear Attribute on Failure” option in my BPOS Powershell Activity I still create the delegation object, but I empty all its settings, and I send a Failure Notification email.
Now imagine an existing delegation is changed. In the AuthZ phase I remove all the previous permissions, and then in the Action phase I add all the current permissions. This makes the workflow nice and simple – I actually don’t care which attributes were changed because I remove-all and then add-all based on the pre- and post-change state of the Target.
Finally a delegation is deleted. And again the powershell fails for some reason* but this time, as we were running the Remove in the AuthZ phase, the change is not committed and it’s still clear that the delagation exists.
*Note: I’ve never seen the powershell cmdlets randomly fail, there’s always a good reason – but best to be prepared right?
The one big problem with this approach is that any failure in the AuthZ phase will result in an “Access Denied” error. I do write a detailed message to the Request object, so the real reason if there if the user knows how to find it, but still, it would be nice to be able to tailor this message.
Make sure you think through the failure scenarios when designing your FIM Portal activities. In some cases the AuthZ phase is ideal for actions as no roll back is required should the action fail – but in other cases the uncomitted data in this phase increases the complexity of the Workflow. It is important as ever to weigh up functionality against simplicity, try to be consistent, and remember that someone other than you may have to support this system one day.