{"id":905,"date":"2010-09-03T11:37:56","date_gmt":"2010-09-03T11:37:56","guid":{"rendered":"https:\/\/www.wapshere.com\/missmiis\/?p=905"},"modified":"2012-12-11T04:20:24","modified_gmt":"2012-12-11T04:20:24","slug":"powershell-activity","status":"publish","type":"post","link":"https:\/\/www.wapshere.com\/missmiis\/powershell-activity","title":{"rendered":"Powershell Activity"},"content":{"rendered":"<p>I have been working on a FIM 2010 workflow activity that will run powershell cmdlets and scripts, and I&#8217;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.<!--more--><\/p>\n<blockquote><p>Note: If you&#8217;re looking for a ready-made PowerShell activity then go to <a href=\"http:\/\/fimpowershellwf.codeplex.com\/\">http:\/\/fimpowershellwf.codeplex.com\/<\/a>.<\/p><\/blockquote>\n<h3>General Provisos<\/h3>\n<p>I will start by saying that I&#8217;m sharing this as an <em>example <\/em>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.<\/p>\n<h3>Server Setup<\/h3>\n<p>If you&#8217;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 <strong>Enabling Remote Powershell<\/strong> section in <a href=\"https:\/\/www.wapshere.com\/missmiis\/running-remote-powershell-scripts-from-vb-net\">this post<\/a>.<\/p>\n<h2>About the Activity<\/h2>\n<h3>Lookup Strings<\/h3>\n<p>I&#8217;ve managed to get the activity using lookup strings like [\/\/Target\/Email]. At the moment I only support \/\/Target and \/\/Requestor. I haven&#8217;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.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/customwf\/ps_lookupstrings.JPG\" alt=\"\" \/><\/p>\n<h3>Using the Activity with Local Powershell<\/h3>\n<p>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 <a href=\"http:\/\/blogs.technet.com\/b\/robcost\/archive\/2008\/05\/01\/powershell-tip-storing-and-using-password-credentials.aspx\">secure password\u00c2\u00a0file<\/a> to inject the credential.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/customwf\/ps_local.JPG\" alt=\"\" \/><\/p>\n<h3>Using the Activity with Remote Powershell<\/h3>\n<p>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.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/customwf\/ps_remote.JPG\" alt=\"\" \/><\/p>\n<p>There are a number of points to be aware of when using this activity for remote powershell:<\/p>\n<ul>\n<li>The way you enter the server name appears to be relevant. When I enter the FQDN or ip address\u00c2\u00a0it works. When I enter a server alias I get &#8220;Access Denied&#8221;.<\/li>\n<li><strong>If you modify the workflow you have to re-enter the password.<\/strong><\/li>\n<li>Certain commands don&#8217;t work at all through remote powershell, eg., start-transcript and (apparently) the Exchange 2007 cmdlets.<\/li>\n<li>Certain commands don&#8217;t work through remote powershell when run through code, eg., write-host.<\/li>\n<li>The servers at each end must be set up to support remote powershell! If you can&#8217;t do it directly from powershell then don&#8217;t expect this activity to do it.<\/li>\n<\/ul>\n<h3>Error Reporting<\/h3>\n<p>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.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/customwf\/ps_error.JPG\" alt=\"\" \/><\/p>\n<h3>Plugins<\/h3>\n<p>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.<\/p>\n<h3>Writing a suitable powershell script<\/h3>\n<p>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.<\/p>\n<p>The activity will return the <em>last<\/em> error thrown by the script so it&#8217;s a good idea to make the script stop on the first fatal error it encounters. Setting $ErrorActionPreference = &#8220;stop&#8221; is a start.<\/p>\n<p>Also my code only understands parameters if they have a &#8220;-&#8221; at the front, like with normal powershel cmdlets. This means<em> you must use PARAM<\/em> when defining script arguments. If you use ARG it won&#8217;t work.<\/p>\n<p>See below for a sample test script.<\/p>\n<h2>Installing<\/h2>\n<p>You are going to have to compile the project into the GAC\u00c2\u00a0yourself and then add the AIC in the FIM Portal. See <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ff859524.aspx\">here<\/a> for a walkthrough.<\/p>\n<p>If you don&#8217;t re-sign the project or change any names\u00c2\u00a0then the AIC settings are as follows:<\/p>\n<table>\n<tbody>\n<tr>\n<td>Activity Name<\/td>\n<td>FIM.CustomWorkflowActivitiesLibrary.Activities.PowershellActivity<\/td>\n<\/tr>\n<tr>\n<td>Assembly Name<\/td>\n<td>FIM.CustomWorkflowActivitiesLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f36c0cc61ccb2b4f<\/td>\n<\/tr>\n<tr>\n<td>Is Action Activity<\/td>\n<td>yes<\/td>\n<\/tr>\n<tr>\n<td>Type Name<\/td>\n<td>FIM.CustomWorkflowActivitiesLibrary.Activities.WebUIs.PowershellActivitySettingsPart<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Testing<\/h2>\n<h3>Make a Workflow<\/h3>\n<p>Once you&#8217;ve installed the activity, and restarted IIS,\u00c2\u00a0you 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.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/customwf\/ps_wfactivity.JPG\" alt=\"\" \/><\/p>\n<h3>Create MPRs and Sets to trigger the Workflow<\/h3>\n<p>I made a set based on an attribute, then two MPRs on &#8220;Transition In&#8221; and &#8220;Transition Out&#8221; of the set. Then it was\u00c2\u00a0simple matter of toggling the appropriate attribute on a user so it transitioned in and out of the set.<\/p>\n<h3>Test Powershell Script<\/h3>\n<p>Here&#8217;s a test script I&#8217;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.<\/p>\n<pre>Param($username, $modifier)\r\n\r\n$ErrorActionPreference = \"stop\"\r\n\r\nif ($username -eq \"\") {throw \"Username parameter must be provided.\"}\r\nif ($modifier -eq \"\") {throw \"Modifier parameter must be provided.\"}\r\n\r\n$objDomain = New-Object System.DirectoryServices.DirectoryEntry\r\n$objSearcher = New-Object System.DirectoryServices.DirectorySearcher\r\n$objSearcher.SearchRoot = \"LDAP:\/\/mydomain.local\"\r\n$objSearcher.PageSize = 1000\r\n$objSearcher.Filter = \"(&amp;(objectClass=user)(sAMAccountName= $username))\"\r\n$objSearcher.SearchScope = \"Subtree\"\r\n\r\n$user = $objSearcher.findone()\r\nif ($user.count -eq 0)\r\n\t{throw \"No user found with username=\" + $username}\r\n\r\n$userDN = $user.path\r\n\r\n$user = [ADSI]$userDN\r\n\r\n$user.Put(\"extensionAttribute1\",$modifier)\r\n$user.SetInfo()<\/pre>\n<h3>And finally, the code<\/h3>\n<p>Here&#8217;s the whole solution. I added this activity on to my existing LoggingLibrary solution so you&#8217;ll find both here.<\/p>\n<p><a href=\"https:\/\/www.wapshere.com\/dl\/FIM.CustomWorkflowActivitiesLibrary.zip\">Download here<\/a><\/p>\n<h3>A last word<\/h3>\n<p>Like I said, I&#8217;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.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have been working on a FIM 2010 workflow activity that will run powershell cmdlets and scripts, and I&#8217;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&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[42,23,30,45],"tags":[],"class_list":["post-905","post","type-post","status-publish","format-standard","hentry","category-fim-2010","category-powershell","category-vbnet","category-workflow"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pkp1o-eB","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/905","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/comments?post=905"}],"version-history":[{"count":12,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/905\/revisions"}],"predecessor-version":[{"id":965,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/905\/revisions\/965"}],"wp:attachment":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/media?parent=905"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/categories?post=905"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/tags?post=905"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}