FIM 2010 R2 Pre-Requisites

Installing a complete FIM 2010 R2 environment is not an easy task. Lots of things can go wrong. A FIM setup might use almost any number of servers for example. In this post I give you access to scripts and configuration files required to do all FIM 2010 R2 pre-requisites in a typical 4-server FIM deployment.
FIMFourServerSetup

In the FIMScriptsAndCode.zip you will find PowerShell scripts to create service accounts, configure Kerberos, configure SQL ports and aliases among other things. You will also find ini-files to perform unattended setups of the SQL servers used by FIM. Basically everything you need to do before you can start the installation of FIM.

In the Installation folder in the download package you will find a ReadMeFIRST.txt file that explains the order to perform the steps. Please note that many of the scripts and configuration files used requires editing to match the target environment.

In the RulesExtension folder you will find a simple code example showing how to use rules extension in FIM to import the last logon timestamp from AD into FIM. This is one of the things I show in my FIM 2010 R2 Video Course and this is to give the viewers of that a chance to download the example.

FIM Team User Group presentation

At the FIM Team User Group meeting in March I held a session about how to use less code in FIM solutions.
If you have any questions regarding this session please comment on this post.

Finding Managers in FIM 2010

When working with FIM 2010 we often use Reference attributes like the Manager attribute. But in FIM we cannot create a corresponding Set with all referenced Managers. The xPath query simply doesn’t allow this kind of referenced object lookup.

So what if I would like a Set or a Group containing all Managers! How do we solve that problem?

In this post I will show you one way of doing this, but please remember that there are many variations of this you could use.

Add IsManager to Schema

First we add a new boolean attribute “IsManager” to the schema in FIM. Depending on how you plan to use this you might need to add it to both the FIM Service and the FIM Synchronization Service schema.
This step I hope you all know involves creating a binding as well as adding the new attribute to the Filter Permissions.
You will also need to add it to some MPR’s to allow the management of this new attribute.
Ones we have this new boolean attribute creating a Set and/or a Group is now reduced to look at this boolean value.

Manage the IsManager flag

The problem is now to have some kind of activity that sets the IsManager attribute to “true” when a manager is configured on a user.
This can be done using a PowerShell WorkFlow activity. I show you a solution working with the PowerShell Workflow Activity you can download from codeplex.. The PowerShell I use in the activity can be downloaded UpdateIsManager.

PowerShell Activity

Let’s look at the PowerShell script I use to understand what it does and how it works.

First we set the basics like URI and load the FIMAutomation snapin.

set-variable -name URI -value "http://localhost:5725/resourcemanagementservice' " -option constant
if(@(get-pssnapin | where-object {$_.Name -eq "FIMAutomation"} ).count -eq 0) {add-pssnapin FIMAutomation}

We then get the object that has been changed. Note that I use the “/*” in the xPath since I get the object based on ObjectID I cannot get duplicates and don’t need to specify the object type.

$exportObject = export-fimconfig -uri $URI -onlyBaseResources -customconfig ("/*[ObjectID='{0}']" -F $fimwf.TargetID.Guid)

From the modified user we read the Manager attribute to get the “target” for our change.

$target = $exportObject.ResourceManagementObject.ResourceManagementAttributes | Where-Object {$_.AttributeName -eq "Manager"}

We then build the importChange to set the IsManager attribute to true.

$importChange = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportChange
$importChange.Operation = 1
$importChange.AttributeName = "IsManager"
$importChange.AttributeValue = $true
$importChange.FullyResolved = 1
$importChange.Locale = "Invariant"

Finally we import the change on the target user

$importObject = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportObject
$importObject.ObjectType = "Person"
$importObject.TargetObjectIdentifier = $target.Value
$importObject.SourceObjectIdentifier = $target.Value
$importObject.State = 1 
$importObject.Changes = (,$importChange)
$importObject | Import-FIMConfig -uri $URI

If you apply this logic to a MultiValue reference attribute the script needs to be extended with a loop like the one below to apply the change to all referenced objects.

ForEach($value in $target.Values)

The importObject’s ObjectIdentifier would than just be $value within the loop.

The MPR

The MPR to trigger this Workflow is just a simple Request MPR that fires whenever someone changes the Manager attribute on any user.

What about deletes?

As you can see this solution will only make sure that the IsManager is set to true for all referenced managers. But it will not set it to “false” if they are no longer referenced. The problem is that if you were to detect the deletion of a manager you cannot set it to false since it might be referenced on other users. Doing that lookup, to verify this was the “last” reference, is quite costly from a resource perspective and I don’t think it’s a good idea to do it as part of the WorkFlow activity.

I think that a good approach to set the IsManager to “false” is to have a maintenance job running a PowerShell that verifies that all IsManager=”true” indeed still are referenced. That PowerShell will however have to wait for another post, another time.

Summary

Adding small boolean flags to the schema makes filters in Set’s, Group’s and Synchronization Rules very easy to implement. Using a PowerShell Workflow Activity is often the easiest and quickest way of solving workflow needs to make sure these boolean flags are kept up-to-date in FIM 2010.

FIM 2010 R2 4.1.3496.0 introduces error event when searching the portal

After you have updated your FIM 2010 R2 Service & Portal to 4.1.3496.0 you will start to get errors in the eventlog every time someone makes a search in the FIM Portal. This is due to a new feature added in this update that gives you the ability to hide the advanced search option.

The error you will get in the Forefront Identity Management application log is “System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.”
KeyNotFoundException

This error is due to the new feature, described in the 4.1.3496.0 KB article, allowing you to hide the advanced search option.

Solution

To get rid of this error you need to follow the instructions in the KB article and add the boolean HideAdvancedSearchLink attribute and bind it to the Portal Configuration resource.
HideAdvancedSearchLinkBinding
This will get rid of the error message, but in order to use the new feature and manage it you would also need to add the MPR allowing Administrators to set the value.

Credit

This solution I found as an answer in the TechNet forum. Where the answer was submitted by Andrew Weiss.

Schedule FIM 2010 with a sleep option

When scheduling your run profiles in FIM 2010 you sometimes needs to add a short sleep, to allow for the external system to process data. This can for example be required when the FIM Service needs to apply some workflow on the exported data before you import the result.

In this post I will show you one option to do so when using PowerShell script to run the profiles in FIM Synchronization Service.

The scripts I show you snippets of in this post can be downloaded here: ScheduleFIMwSleep.

DeltaRunWithSleep.ps1

I usually use a PowerShell script to schedule the typical run profiles.
In the script I allow for a special “profile” using the syntax “Sleep:X” to make the script sleep for X seconds.

@{
name="FIMService";
profilesToRun=@("Export";"Sleep:30";"Delta Import";"Delta Sync");
};

So whenever it finds this “Sleep” profile it will sleep instead of trying to run an actual run profile.

if($profileName.StartsWith("Sleep"))
{Start-Sleep -Seconds $profileName.Split(":")[1]}
else
{
$result = $MA.Execute($profileName);
if("success".Equals($result.ReturnValue)){} else {$msg = "Error: "+$result}
}

ReloadWithSleep.ps1

A special case of run schedule is when you need to do some kind of reload or initial load of data. This could be just because you deleted a connector space and need to reload or when changing configuration.
If you use this due to migrating or changing configuration you should be aware that you should always run Full Synchronization rather than Delta on all MA’s with configuration changes.
In this run profile I have added that it disables provisioning before running any run profiles and then enables it once it’s done.

#Disable Provisioning
& "$scriptpath/DisableProvisioning.ps1"

#Run Profiles
do {….}

#EnableProvisioning
& "$scriptpath/EnableProvisioning.ps1"

As you can see the actual enabling and disabling is made in two separate PowerShell scripts (EnableProvisioning.ps1 and DisableProvisioning.ps1) that need to reside in the same folder as the script calling.

Hopefully the information in this post makes your scheduling of FIM 2010 easier.

Using a CleanUp MA in FIM 2010

Every now and then a FIM administrator runs into having to do some cleanup in the MetaVerse in FIM. It could be things like deleting objects or “nulling” attributes.

In this post I will show you how you can use a CleanUp MA to assist you in this task. The example I use is to delete all group objects that are missing the accountName attribute.

There are several ways of creating the CleanUp MA. My approach is to use a SQL MA that uses a SQL view of the MetaVerse to filter the objects you would like to “Clean Up”.

WARNING! Before you continue make sure all schedules are turned off and that you make a new backup of the FIMSynchronizationService database.

First let’s create the SQL view. The table you use in the view is the mms_metaverse and the “required” attributes you should use is the object_id and object_type. Object_id is the one you use to join and object_type is for defining the object_type column in the SQL MA. You then add columns and filters as needed to define the objects in the MV that you need to work with. In this example I take group objects where accountName is missing.
CleanUpMA.SQL.View
Then create a simple SQL MA using the view and create a join rule using the object_id attribute.
CleanUpMA.SQL.MA
Configure run profiles for Full Import and Full Synchronization
CleanUpMA.RunProfiles
Run Full Import and Full Sync to join the objects in the CleanUp MA to the objects in the MV.
CleanUpMA.Join
In Metaverse Designer configure a new object deletion setting to delete group objects if they are disconnected from the CleanUp MA.
CleanUpMA.ObjDelRule
If you would like to propagate the deletion to another MA (or MA’s) you can temporary define the deprovisioning setting on that MA to delete objects when disconnected. In my example these groups has an error in the FIM Service MA since they lack the required accountName. These pending provisions will be deleted once the MV object is deleted.
CleanUpMA.FIMMAError
To fire off the deletion just delete the connector space of the CleanUp MA. This will now disconnect and delete the MV object and, in my case, the pending errors in the FIM Service MA.

When done, remember to reset the object deletion rule and deprovisioning settings you changed to its prior setting.
CleanUpMA.ObjDelRuleReset

The CleanUp MA can be kept for future needs. Just change the view as needed and do a Refresh Schema on the CleanUp MA to use it for other purposes when needed.

Building the FIM 2010 R2 SmsServiceProvider.dll

When using Self-Service Password Reset (SSPR) in FIM 2010 R2 it is a common request from my customers to use SMS OTP (One-Time Password) to authenticate the user trying to reset his password.

In one of my earlier posts, Automate SSPR registration in FIM 2010 R2, I described how you can automate the registration process. But in order to use SMS OTP you also need to build a small dll file. At Microsoft TechNet you can find an example on how to build the required SmsServiceProvider.dll.

The problem is that there is a “bug” in the FIM Service that makes it easy to build the dll in a way that does not work. The error you will run into is shown in the eventlog as “System.TypeLoadException: The custom SMS provider DLL does not implement the required interface.“.

The dll is required to have a class that implements the Microsoft.IdentityManagement.SmsServiceProvider.ISmsServiceProvider interface and that class should have a public method called SendSMS as seen in the code snippet below.

namespace XPServices.FIM.SmsServiceProvider
{
    using System;
    using System.Collections.Generic;
    using Microsoft.IdentityManagement.SmsServiceProvider;

    public class SmsServiceProvider : ISmsServiceProvider
    {
        public void SendSms(string mobileNumber, string message, Guid requestId, Dictionary<string, object> deliveryAttributes)
        {
            XPServices.FIM.mySMSProvider.SendSms(mobileNumber, message);
        }
    }
}

When the FIM Service looks at the dll it requires that the ISmsServiceProvider is the FIRST interface. If your SMS service provider uses for example a Web Service and you add the reference to that Web Service in your code it will likely show up first and the FIM Service will give you the error “System.TypeLoadException: The custom SMS provider DLL does not implement the required interface.

The solution is to move all logic and references into a separate class library. As you see in my code above all logic about how to send the SMS is moved into the XPServices.FIM.mySMSProvider class. This will hold the references to any Web Services and FIM Service will not have any trouble enumerating the SmsServiceProvider.dll since it only holds one class and one method. Below is a snippet showing parts of a typical class library in this scenario.

namespace XPServices.FIM
{
    public class mySMSProvider
    {
        static string id;
        static string password;

        public static string SendSms(string userMobileNumber, string message)…
        public static void GetSMSConfig()…
     }
}

When deploying this all we need to do is drop both dll’s in the FIM Service folder (default this is C:\Program Files\Microsoft Forefront Identity Manager\2010\Service\)

Redirect to IdentityManagement site in SPF 2013

It’s a common request, when starting to use the FIM 2010 Portal for self-service, to try to redirect the root url of the FIM portal to the IdentityManagement sub-site. If you have moved to SPF 2013 you will find that none of the methods available in easy to find documentation from Microsoft will work.

Using for example the IIS HTTP Redirect as suggested on the TechNet Wiki. Trying this will however mess-up your site since it will affect your CSS.

On the FIM TechNet site there is also a note close to the bottom of the Installing the FIM 2010 R2 Server Components page about “To redirect the FIM Portal”. This will not work either because SPF 2013 just ignores the default.aspx page.

So how should we do it?
After some investigation I found the clue to the solution in a SharePoint forum thread. The solution was presented by Per Jakobsen.

This is how I have solved it.
Create a document using notepad and call it, for example, RedirectFIM.aspx. The file should have the following content.

<html>
<head>
<title>Redirect to IdentityManagement site</title>
<meta http-equiv="refresh" content="0; url=https://im.company.com/IdentityManagement/default.aspx" />
</head>
<body>
</body>
</html>

Upload this file as a new document to the Shared Documents library in SharePoint.
RedirectFIMUploaded
You can now try that it is working by clicking on it. You should be redirected to our familiar FIM homepage.
FIMHomePageAfterRedirect
When we know it is working we can set it as homepage for the site. Since this is a subsite we need to use PowerShell to do it.
Start the SharePoint 2013 Management Shell and configure the uploaded page as WelcomePage for the root site.

$w = Get-SPWeb https://im.company.com
$root = $w.RootFolder
$root.WelcomePage = "Shared%20Documents/RedirectFIM.aspx"
$root.Update()

If you now access the root site https://im.company.com you will end up being redirected to the IdentityManagement site. If you need to access the root site you can always use the old default home page at https://im.company.com/SitePages/Home.aspx

Managing Office 365 licenses using FIM 2010

When starting to use Office 365 in large scale you soon realize that although DirSync will solve most of your synchronization needs it will not solve the problem of assigning the correct license to different users. In this post I will show you how I solved this problem using FIM 2010 with a PowerShell MA.

The problem at hand was not only to license unlicensed users but to manage licenses in the respect of changing the license and removing the license based on information in FIM.

Background information

The customer has almost 60,000 users in FIM. In that we have 900 staff and a little over 57,000 students.

In FIM we use the employeeType attribute to decide the type of user. In this context we have three different values to consider, Staff, Student and Alumni. Each type should have a different license assigned to them. And since typically a Student will eventually become an Alumni we need to manage that transformation as well.

In FIM we have also created a simple boolean attribute called off365Licensed. This attribute is the main “switch” to decide if you should have a license at all.

Office 365 Licenses

Different subscriptions in Office 365 gives you different licenses to work with so keep in mind that this post only shows one type of subscription. The EDU subscription gives you a couple of “free” licenses to use but in order to use them we need to learn how they look since we actually will need to disable parts of some licenses in most cases.

As an example I will show you the Faculty licenses that are “free”.
You have the STANDARDWOFFPACK_FACULTY and also the PROJECTONLINE_PLAN_1_FACULTY.

But they consist of different parts.
The STANDARDWOFFPACK_FACULTY has four parts in it

  • SHAREPOINTWAC_EDU
  • MCOSTANDARD
  • SHAREPOINTSTANDARD_EDU
  • EXCHANGE_S_STANDARD

The PROJECTONLINE_PLAN_1_FACULTY has three parts in it

  • SHAREPOINT_PROJECT_EDU
  • SHAREPOINTWAC_EDU
  • SHAREPOINTENTERPRISE_EDU

The problem here is that they overlap and both contain SharePoint licenses that cannot be assigned at the same time. So in our scripts we need to disable parts of the licenses that we cannot assign if we also want to assign the other.

PowerShell MA

We decided to use the PowerShell MA developed by Sören Granfeldt.
I do not do Provisioning and De-provisioning in this case, that part I leave to DirSync. In this MA we import the users, join them to the corresponding user in the MetaVerse and then make sure the correct license is assigned.

Below I show you some parts of the scripts involved but please download O365MAScripts to get the complete scripts.

Schema

The Schema script in this case is quite simple. I used the UPN as anchor in this case.

$obj = New-Object -Type PSCustomObject
$obj | Add-Member -Type NoteProperty -Name "Anchor-UPN|String" -Value 1
$obj | Add-Member -Type NoteProperty -Name "objectClass|String" -Value "user"
$Obj | Add-Member -Type NoteProperty -Name 'IsLicensed|Boolean' -Value $true
$Obj | Add-Member -Type NoteProperty -Name 'LicenseType|String' -Value "Staff"
$obj

Import Script

The import script imports the current MsolUsers

$Users = Get-MsolUser -MaxResults 50000 -DomainName company.com

but also checks the current license assigned

if($user.IsLicensed)
{
if($User.Licenses.AccountSkuId[0].EndsWith("FACULTY"))
{$obj.Add("LicenseType", "Staff")}
elseif($User.Licenses.AccountSkuId[0].EndsWith("STUDENT"))
{$obj.Add("LicenseType", "Student")}
elseif($User.Licenses.AccountSkuId[0].EndsWith("ALUMNI"))
{$obj.Add("LicenseType", "Alumni")}
else {$obj.Add("LicenseType", "Unknown")}
}

Export

The export script picks up the users from O365

$msoluser=Get-MsolUser -UserPrincipalName $_.DN
$IsLicensed=$msoluser.IsLicensed

I do not bother to look at the current license of the users since changing licenses involves removing the old license and adding the new license. My script just removes the old licenses and assigns the correct ones.
Removing old licenses can be done in a single line

Set-MsolUserLicense -UserPrincipalName $msolUser.UserPrincipalName -RemoveLicenses $msoluser.Licenses.AccountSkuId

Adding the correct license involves defining the licenses including the excludes discussed earlier in this post.
Please note that before we can assign any licenses we need to set the UsageLocation on the user.

if(!$msoluser.UsageLocation)
{Set-MsolUser -UserPrincipalName $msolUser.UserPrincipalName -UsageLocation $DefaultUsageLocation;}

We then assign the license depending on the employeeType in FIM.

if($LicenseType -eq "Staff")
{
Set-MsolUserLicense -UserPrincipalName $msolUser.UserPrincipalName -AddLicenses $STANDARDWOFFPACK_FACULTY -LicenseOptions $FacultyStnd;
Set-MsolUserLicense -UserPrincipalName $msolUser.UserPrincipalName -AddLicenses $PROJECTONLINE_PLAN_1_FACULTY;
}
elseif($LicenseType -eq "Student")
{
Set-MsolUserLicense -UserPrincipalName $msolUser.UserPrincipalName -AddLicenses $STANDARDWOFFPACK_STUDENT -LicenseOptions $StudStnd;
Set-MsolUserLicense -UserPrincipalName $msolUser.UserPrincipalName -AddLicenses $PROJECTONLINE_PLAN_1_STUDENT;
}
elseif($LicenseType -eq "Alumni")
{
Set-MsolUserLicense -UserPrincipalName $msolUser.UserPrincipalName -AddLicenses $EXCHANGESTANDARD_ALUMNI;
}
else
{
throw "Unknown LicenseType"
}

Synchronization Rule

Finally we need to configure the Outbound Synchronization rule. We need two flows and I need a condition on the LicenseType to only set in on Licensed users.

O365 MA Outbound Synchronization Rule

Office 365 Management Agent Outbound Synchronization Rule

Conclusion

In this post I have showed you one example on how to manage Office 365 licenses. As you can imagine this task can grow substantially if we also were to manage individually selectable licenses in some way. We have discussed this at this particular client, using the FIM portal for self-service to add additional licenses. That would off course require some major changes to current license management.