0 comments

Pass an Array to a PowerShell Script in a TFS Build Definition

Published on Monday, November 26, 2012 in ,

In one my current projects I had to configure a TFS deployment for my customizations I wrote for AD FS and FIM. Setting up a deployment (build) in TFS seems pretty straightforward. The most complex thing I found was the xaml file which contains the logic to actually build & deploy the solutions. I picked a rather default template and cloned it so I could change it to my needs. You can edit such a file with Visual Studio which will give you a visual representations of the various flows, checks and decisions. After being introduced to the content of such a file by a colleague of mine I was still overwhelmed. The amount of complexity in there seems to shout: change me as little as you can.

As I have some deployments which require .NET DLL’s to be deployed on multiple servers I had some options: modify the XAML so it’s capable of taking an array as input and execute the script multiple times, or modify the parameters so I could pass an array to the script. I opted for the second option.

My first attempt consisted of adding an attribute of the type String[] to the XAML for that deployment step. In my build definition this gave me a multi valued parameter where I could enter multiple servers. However in my script I kept getting the value “System.String[]” where I’d expect something along Server01,Server02 This actually made sense, TFS probably has no Idea it needs to convert the input to a PowerShell array.

So I figured if I use a String parameter in the build and if I feed it something like @(“Server01”,”Server02”), which is the PowerShell way of defining an array.

image

Well it did, but not exactly like we want it. The quotes actually screwed it up and it was only available partially in the script. So we had to do some magic. Passing the parameters to the script means you pass though some vb.net code. This is some simple text handling code, and all we need to do for this to work is add some quotes handling magic. Here’s my test console application which tries to take an array as input and make sure I got the required amount of quotes on the output.

image

Here’s the TFS parameter section where we specify the arguments for the scripts. The magic happens in the “servers.Replace” section. We’ll ensure that quotes “survive” be passed along to the PowerShell script.

String.Format(" ""& '{0}\{1}' '{2}' {3} "" ", ScriptsFolderMapping, BuildScriptName, BinariesDirectory, Servers.Replace("""", """"""""))

In the GUI this goes into the “Arguments” field:

image

This allows us to configure the build definition like this. Which is actually pretty simple. Just put the array as you’d put it in PowerShell.

image

P.S. Make sure to either copy paste or count those quotes twice ; )

2 comments

FIM: Calling FIM Automation cmdlets from within a PowerShell Activity

Published on in

I’m currently setting up a FIM solution where the users should be preregistered for Self-Service Password Reset (SSPR). Their email address will be managed in a system outside of FIM, and will be pushed to the correct attribute in the FIM Portal: msidmOneTimePasswordEmailAddress. After some googling I quickly realized that in order for the user to be properly registered, flowing the mail attribute wouldn’t be enough. So Register-AuthenticationWorkflow to the rescue! Using this PowerShell cmdlet you can perform the proper registration from within an administrator perspective. In order to automate this, I combined this with a custom PowerShell activity in the Portal. This activity will execute a PowerShell script with some parameters (attributes from the FIM Portal object) upon execution.

The trigger: whenever the msidmOneTimePasswordEmailAddressattribute is modified, the workflow will be executed.

The script (I left out some logging):

Param($domain,$name,$mail)
Add-PSSNapIn FIMAutomation

try{
    $template = Get-AuthenticationWorkflowRegistrationTemplate –AuthenticationWorkflowName "Password Reset AuthN Workflow"
    $usertemplate = $template.Clone()
    $userTemplate.GateRegistrationTemplates[0].Data[0].Value = $maill

    Register-AuthenticationWorkflow -UserName "$domain\$name" -AuthenticationWorkflowRegistrationTemplate $userTemplate
}
Catch {
    $errorDetail = $_.Exception.Message;
}

However calling this script from within a workflow seemed to result in the following error:

Unexpected error occurred when registering Password Reset Registration Workflow for DOMAIN\USER with email address EMAIL, detailed message: The type initializer for 'Microsoft.ResourceManagement.WebServices.Client.ResourceManagementClient' threw an exception.

In the event log I found the following:

image

In words:

Requestor: Internal Service
Correlation Identifier: e98bcce4-54e7-4fd3-a234-7f7b5c7146d3
Microsoft.ResourceManagement.Service: Microsoft.ResourceManagement.WebServices.Exceptions.UnwillingToPerformException: IdentityIsNotFound
   at Microsoft.ResourceManagement.WebServices.ResourceManagementService.GetUserFromSecurityIdentifier(SecurityIdentifier securityIdentifier)
   at Microsoft.ResourceManagement.WebServices.ResourceManagementService.GetCurrentUser()
   at Microsoft.ResourceManagement.WebServices.ResourceManagementService.Enumerate(Message request)

Some where I found a forum thread or a wiki article which suggested you modified the FIM Service configuration file. The file is located in the FIM Service installation folder and is called Microsoft.ResourceManagement.Service.exe. The section we need to modify:

  • Before: <resourceManagementClient resourceManagementServiceBaseAddress=”fqdn” / > Depending on your installation it can also be localhost.
  • After: <resourceManagementClient resourceManagementServiceBaseAddress=”http://fqdn:5725” / >  Depending on your installation use FQDN or localhost.

After retriggering my workflow I now receive the following error:

image

In words: GetCurrentUserFromSecurityIdentifier: No such user DEMO\s_fim_service, S-1-5-21-527237240-xxxxxxxxxx-839522115-10842

This is easily resolved by adding the FIM Service as a user in the Portal. I’d make sure it’s filtered in the FIM MA or double check no attribute flows can break this AD Account.

Check the following URLs for some more background: