Powershell Activity

I have been working on a FIM 2010 workflow activity that will run powershell cmdlets and scripts, and I’m now ready to share the code with you lucky people. The activity should work with both local and remote powershell, bearing in mind the various limitiations that seem to occur when running remote powershell commands through code.

Note: If you’re looking for a ready-made PowerShell activity then go to http://fimpowershellwf.codeplex.com/.

General Provisos

I will start by saying that I’m sharing this as an example and not as supported code. Please do take the time to understand it and modify it as appropriate to your environment. While I do have a production application for this coming up soon I have so far only used it in the lab and may well need to work on it more. This post will remain the place for information about the activity and I will update here if something changes.

Server Setup

If you’re planning on using Remote Powershell then, unless you have WIndows 2008R2 on both the FIM server and the remote server, you will need to make sure the prerequsites are in place. See the Enabling Remote Powershell section in this post.

About the Activity

Lookup Strings

I’ve managed to get the activity using lookup strings like [//Target/Email]. At the moment I only support //Target and //Requestor. I haven’t yet worked out how to do a nice string concatenator with a lookup button like you see on the OOB activities so you have to type the strings yourself.

Using the Activity with Local Powershell

For local powershell it is assumed that the FIM Service account has the rights to run the cmdlet/script. If you need to use a different account then I recommend using a script along with a secure password file to inject the credential.

Using the Activity with Remote Powershell

For remote powershell you also need to fill in the name of the remote server, and the username and password to use when connecting. The remote script will run within the environment of this connection account.

There are a number of points to be aware of when using this activity for remote powershell:

  • The way you enter the server name appears to be relevant. When I enter the FQDN or ip address it works. When I enter a server alias I get “Access Denied”.
  • If you modify the workflow you have to re-enter the password.
  • Certain commands don’t work at all through remote powershell, eg., start-transcript and (apparently) the Exchange 2007 cmdlets.
  • Certain commands don’t work through remote powershell when run through code, eg., write-host.
  • The servers at each end must be set up to support remote powershell! If you can’t do it directly from powershell then don’t expect this activity to do it.

Error Reporting

Errors should be reported as a PostProcessingError in the Search Request page of the FIM Portal. In some cases I write extra information to the event log.

Plugins

I originally had a field to enter a powershell plugin that should be loaded before running the command. I took it out because I figured that would be better done in a script, but the code is still in there commented out if you want to put it back in.

Writing a suitable powershell script

You need to take some care with the powershell scripts you write to go with this activity. First, see the comments the Remote Powershell section above for cmdlets I know should be avoided.

The activity will return the last error thrown by the script so it’s a good idea to make the script stop on the first fatal error it encounters. Setting $ErrorActionPreference = “stop” is a start.

Also my code only understands parameters if they have a “-” at the front, like with normal powershel cmdlets. This means you must use PARAM when defining script arguments. If you use ARG it won’t work.

See below for a sample test script.

Installing

You are going to have to compile the project into the GAC yourself and then add the AIC in the FIM Portal. See here for a walkthrough.

If you don’t re-sign the project or change any names then the AIC settings are as follows:

Activity Name FIM.CustomWorkflowActivitiesLibrary.Activities.PowershellActivity
Assembly Name FIM.CustomWorkflowActivitiesLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f36c0cc61ccb2b4f
Is Action Activity yes
Type Name FIM.CustomWorkflowActivitiesLibrary.Activities.WebUIs.PowershellActivitySettingsPart

Testing

Make a Workflow

Once you’ve installed the activity, and restarted IIS, you should be able to access it from the Workflow builder. More explanation about how to fill in the form is higher up in this post.

Create MPRs and Sets to trigger the Workflow

I made a set based on an attribute, then two MPRs on “Transition In” and “Transition Out” of the set. Then it was simple matter of toggling the appropriate attribute on a user so it transitioned in and out of the set.

Test Powershell Script

Here’s a test script I’ve been using. You can see the way I call it in the Remote Powershell picture above. If you run it locally the FIM Service account will need rights to modfy user accounts in AD.

Param($username, $modifier)

$ErrorActionPreference = "stop"

if ($username -eq "") {throw "Username parameter must be provided."}
if ($modifier -eq "") {throw "Modifier parameter must be provided."}

$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = "LDAP://mydomain.local"
$objSearcher.PageSize = 1000
$objSearcher.Filter = "(&(objectClass=user)(sAMAccountName= $username))"
$objSearcher.SearchScope = "Subtree"

$user = $objSearcher.findone()
if ($user.count -eq 0)
	{throw "No user found with username=" + $username}

$userDN = $user.path

$user = [ADSI]$userDN

$user.Put("extensionAttribute1",$modifier)
$user.SetInfo()

And finally, the code

Here’s the whole solution. I added this activity on to my existing LoggingLibrary solution so you’ll find both here.

Download here

A last word

Like I said, I’m still learning this stuff, and this activity is not in production so I may find problems. If you do have feedback please comment here.

31 Replies to “Powershell Activity”

  1. This is really awesome!
    I’ve had the idea of creating a PS activity for a long time but haven’t found the time to do it.

    I haven’t looked at the code yet but I hope you do use the ResolveGrammarActivity for resolving expressions even though it’s not supported!? You can also use it to resolve [//WorkflowData/*] expressions as well that is a way of sharing information between activities.

    Another good thing could be to encrypt the remote password when it’s stored to XAML/XOML otherwise it could be read in clear text by anyone with rights to it.

    //Henrik

  2. Hi Henrik. I did try to use the ResolveGrammarActivity but couldn’t get it going, and once I discovered the documentation said “not supported” I moved on to ReadResource. However, feel free to take the code and improve on it! I was worried about the clear text password, so that is a great suggestion.

    And hi to Derek and Brad too – thanks for your comments!

  3. I agree with all of the others. This is awesome. I was just thinking of moving my clients powershell code out of the MA extensions and into WF. This will save me TONS of time.

  4. This is great example..
    I have a question thou.. When I run the code I get the following error.
    am I missing something? I am new to this and learning..

    Could not load type ‘System.Management.Automation.PowerShell’ from assembly ‘System.Management.Automation, Version=1.0.0.0, Culture=neutral,
    PublicKeyToken=31bf3856ad364e35

  5. I got it working, I was missing few dll files.
    however when I use the option to run the local powershell on the server
    I pass in the parameters as mentioned above.
    -user [//Target/AccountName] -requestor [//Requestor/AccountName]

    and I am calling a test powershell to write those to a file and this is what its writing
    “[//Target/AccountName]”
    “[//Requestor/AccountName]”
    literally.

    How can I get the accountName and the attributes that got modified into the powershell?

    Thanks,
    Krish

  6. same problem… this activity send to powershell [\\Target\AccountName] but not real user account name
    where ReadResourceActivity located? how can i configure it?

  7. Well what do you know – that’s an old version of the code there without the ReadResourceActivity. I’ve uploaded a new version which also has another activity in it to generate a unique value (there’s another post on that after this one). Sorry about the confusion!

  8. This is great Carol. I’m able to run the PowerShell scripts with no problem. Although, I do have a promlem when trying to access the FIM Web Service. the script works fine when run from the console, but when it is kicked off via the workflow, I get the following error:

    “The type initializer for ‘Microsoft.ResourceManagement.WebServices.Client.ResourceManagementClient’ threw an exception.”

    It doesn;t have any more detail than that in the FIM request or the event log. It gets thrown as soon as I try to do an export-fimconfig to get a user object.

    Have you run into any issues like that in yor testing?

    I assume that you are using this with PowerShell scripts that hit the web service. (since that makes anything possible) 🙂

    Thanks,

    Mark

  9. Actually I haven’t tried running any FIM cmdlets this way. I wrote this so I could run MSOnline powershell cmdlets, which is all I used it for so far.

  10. Here’s an update to my previous post. If I enable Powershell remoting and add the server informaiton to point to the localhost with the proper credentials, it works fine. Any idea why that would be different?

    Thanks,

    Mark

  11. I appreciate your quick response. I’ll just go with the remoting for now. This opens up a whole new world of possibilities. 🙂

    I do understand your issues with MSOnline. I’ll probably start using this for some extra Live@edu functionality.

    Thanks,

    Mark

  12. Sorry for all of the questions, but here’s one more.

    Have you been able to pass the \\Target\ObjectID to the PowerShell script? String attributes get passed just fine, but when I try to pass the ObjectID it throws an error. The script never gets called. the error is: “Conversion from type ‘UniqueIdentifier’ to type ‘String’ is not valid.”.

    Thanks again,

    Mark

  13. All set now. I just put in a quick check for the objectid attr adn added a ToString(). Everything is working great now.

    Thanks for this,

    Mark

  14. It doesn’t surprise me – this code was a pretty basic first attempt. I’m planning a brushed up copy to put on codeplex or msdn so I’ll see if I just need to stick a .ToString in there somewhere.

  15. Trying out your PS Workflow activity.
    Getting error “Object reference not set to an instance of an object”.
    When debugging I put a break at where I should get the Target info
    “replace = (string)TargetResource[“AccountName”];”
    and find that the CurrentRequest object looks alright, but all Target and Requestor Properties are “null”. Not sure if they are supposed to or what might be wrong.
    Any ideas on how I should debug this problem?

  16. Hi Carol, Thanks so much for putting this together. I’ve been successful in adding the powershell activity to the workflows, but can’t seem to get the ps1 to run via WF. I can run the script manually but receive a PostProcessingError on the update of the set that transitions the users in and out to kick off the PS WF and then another PostProcessingError on the System Event Request.

  17. Hi Carol!
    First.. GREAT work. I missed something like this!

    But. Im experiencing the same problem as Opper. Im getting a “PostProcessingError” on update of the SET, and also a System Event Request that has a Remark that says: “Invalid URI: The hostnamre could not be parsed.”

  18. Alright. I got it working! It seems that your have to delete the value in remote and user if you gonna run a local script. (The guide text that is in there by default). 🙂

    Thanks Carol! This is a really cool WF!

  19. Glad to hear you’re getting there. It’s hard for me to offer a workflow that will work in every environment – I’m really just sharing my experiences in learning how to develop them. Also have a look at my BPOS powershell activity (link at the top) because I much prefer now the method I used there, where I generate the arguments using the built in Function Evaluatr and then save them to a workflowdata variable. It’s easier than trying to resolve targtes and requestors inside the custom activity. Also have a look at Craig Martin’s powershell activity on codeplex: http://fimpowershellwf.codeplex.com/

  20. This is great and I am working with it in my lab to remove all Group membership for users as they are terminated. The script also creates a text file with all the groups before it removes them in case we need to recreate the account.

    But, I’m calling this in a workflow that has other steps as well like modifying the DN to move the user to a deactive user OU, Add some text to the Info attribute. The problem i have is that once my powershell activity calls the script and runs successfully, it doesn’t seem to allow any other workflow steps to run after the powershell activity.

    Anyone else have this issue or is it my script (pasted below)?

    Thanks.

    Param(
    $adcn,
    $ad_container
    )
    $ldappath = “LDAP://CN=” + $adcn + “,” + $ad_container
    $account = [ADSI]($ldappath)

    $ginfofile = “d:\FIMlog\Disabled_account_memberof\”+$account.displayName+”-{0:yyyyMMdd-HHmm}.txt” -f (get-date)
    $account.memberOf | out-file -filePath $ginfofile

    ForEach ($GroupDN In $Account.memberOf)
    {
    $usrGroup = [ADSI](“LDAP://” + $GroupDN)
    $usrGroup.Remove($Account.ADsPath)
    }
    exit

  21. My last post I should have done on the BPOS section as that is the activity I’m using to run this script but running it on localhost.

  22. It’s been a while since I did this stuff, buty I was definitely running other activities after the powershell – particulalry notifications. As long as you don’t throw an exception it should be okay. Is there anything in the FIM event log?

  23. Carol, just a note to say great job on this and the rest of the custom activity articles! I have found them more helpful than anything MSDN has published. Now if you could just do these in C#, they would be perfect :-). Thanks again for sharing this with the community.

  24. Thanks, that’s nice of you to say 🙂 There is a VB to C# converter out there which is pretty good…

Comments are closed.