Thursday, February 11, 2016

MIM 2016 lab on Windows 7

Rebecca Croft's excellent walkthrough on setting up a FIM 2010 R2 lab on Windows 7 is still helpful for installing MIM 2016 on Windows 7.  Here are a few notes/differences from my experience.
Thanks again to Rebecca and best of luck to you readers!

CShark is now IDMware

Heads up; I've renamed my blog from 'CShark' to 'IDMware'.  Seems more appropriate, considering the amount of code I've written for identity projects over the years.  And I hope to publish more of that code to the community.  Depends on my work schedule, of course.  :)

Cheers!

Tuesday, January 26, 2016

Lessons learned - FIM_TemporalEventsJob

Here are some lessons learned while troubleshooting the titular SQL Agent job.  If you think to yourself, "Self, why would I ever need to care about this?" then you're either (a) lucky or (b) blissfully ignorant.  Don't worry though, you can blame FIM for your ignorance.  ;)  This is one of those features of FIM that won't actually tell you that something's wrong until you stumble upon the fact that, for example, your managers stopped getting notifications when contractor accounts expired.

So, where do you start troubleshooting such a problem?  Well, the keyword "expiration" may trigger thoughts of whether you remembered to renew your car's registration, but in FIMLand it should make you think, "temporal set."  And how are temporal events triggered?  Well, one way is when a datetime attribute on a user is updated and it falls into the scope of a temporal set.  But think about the other way that temporal events are triggered: the user's datetime attribute has been the same for several weeks, and now it's been long enough that the user now satisfies some expiration criteria.  If you've never had to consider how that happens, then I envy you!  But if you really want to know, or if you've read this far and feel like you can't turn back now, then I'll tell you that those events are triggered by a SQL Agent job that's installed with the FIM Service product.

If you run SQL Server Management Studio (SSMS) and connect to the database engine on the FIM SQL server, you can expand the SQL Server Agent -> Jobs branch, right click on FIM_TemporalEventsJob and select View History.  If you see all green checkmarks, then congratulations on keeping your set criteria simple enough for FIM to handle!  However, if you see red icons like below, then congratulations on giving FIM a challenge!  (But unfortunately you're going to have to fix it.)




Lesson 1: FIM_TemporalEventsJob SQL Agent job continues after error in step 1, but fails if error in step 2

The steps of the FIM_TemporalEventsJob SQL Agent job are shown below.  The first lesson I learned in this troubleshooting exercise is that, if the job encounters an error in step 1, the job still continues on to the next step.  However, if an error is encountered in step 2, the job is stopped and the last two steps aren't executed.  (And in case you're not SQL literate, the steps below all execute SQL stored procedures.)

Step 1
EXECUTE [fim].[TriggerTemporalEvents] @extendedOutput = 0
Step 2
EXECUTE [fim].[MaintainSets]
Step 3
EXECUTE [fim].[MaintainGroups]
Step 4
EXECUTE [fim].[OptimizeSetMembershipConditionsUsingPartitions]

Step 1 sample error

Here's an example of an error that you might see in step 1 of the job history.  If you've got a keen eye, you may ask yourself, "What the heck is a SetKey???"  Don't worry, keep reading... 

Executed as user: DOMAIN\SVC-SQLAgent. Reraised Error 50000, Level 16, State 1, Procedure TriggerTemporalEvents, Line 667, Message: <_x0040_failedTable SetKey="6062948" ErrorMsg="Reraised Error 50000, Level 16, State 1, Procedure ReRaiseException, Line 37, Message: Reraised Error 8623, Level 16, State 1, Procedure ?, Line 2, Message: The query processor ran out of internal resources and could not produce a query plan. This is a rare event and only expected for extremely complex queries or queries that reference a very large number of tables or partitions. Please simplify the query. If you believe you have received this message in error, contact Customer Support Services for more information."/> [SQLSTATE 42000] (Error 50000).  The step failed.

Step 2 sample error

Here's a similar error that you might see in step 2 of the job history.  This is essentially the same error, but it occurred in a different stored procedure.

Executed as user: DOMAIN\SVC-SQLAgent. Reraised Error 50000, Level 16, State 1, Procedure MaintainSets, Line 556, Message: <Failures><_x0040_failedSetCorrections SetKey="6062948" ErrorMessage="Reraised Error 8623, Level 16, State 1, Procedure ?, Line 2, Message: The query processor ran out of internal resources and could not produce a query plan. This is a rare event and only expected for extremely complex queries or queries that reference a very large number of tables or partitions. Please simplify the query. If you believe you have received this message in error, contact Customer Support Services for more information."/></Failures> [SQLSTATE 42000] (Error 50000).  The step failed.

Lesson 2: Step 2 (fim.MaintainSets) will continue after individual errors

Okay, we've learned that the job will continue after errors in step 1 but not step 2.  But what about the substeps within each step?  I.e., if an error occurs while evaluating one set, will it stop or continue to evaluate the rest of the sets?  The answer is that it will evaluate *all* sets, even if one set causes an error.

To prove that to myself, I added some print statements to the fim.MaintainSets stored procedure and ran it manually...

Sample of adding print statements to fim.MaintainSets procedure

SUCCESS: @setKey                         = 2732
SUCCESS: @setKey                         = 2733
SUCCESS: @setKey                         = 2734
...
SUCCESS: @setKey                         = 6062663
SUCCESS: @setKey                         = 6062802
SUCCESS: @setKey                         = 6062814
FAIL: @setKey                         = 6062948
SUCCESS: @setKey                         = 6063066
SUCCESS: @setKey                         = 7185483
SUCCESS: @setKey                         = 7185525
...
SUCCESS: @setKey                         = 10711150
SUCCESS: @setKey                         = 11024517
SUCCESS: @setKey                         = 11596415

Lesson 3: Find problematic set

Okay, so how do you find which set is causing the problem?  In the error message above we saw a "SetKey," but what the heck do you do with that?  That's a great question, because all identifiers in the FIM Service are GUIDs.  Well, the FIM product group certainly did you no favors here.  In order to find the problematic set, you have to run a SQL query against the FIMService database:

SELECT
    s.SetKey
    ,o.ObjectID
    ,x.DisplayName
FROM [fim].[Set] s
join fim.[Objects] o on s.SetKey = o.ObjectKey
CROSS APPLY
(
    SELECT
        ValueString as DisplayName
    FROM fim.ObjectValueString ovs
    join fim.AttributeInternal ai on ai.[Key] = ovs.AttributeKey
    WHERE Name = 'DisplayName'
    and ovs.ObjectKey = o.ObjectKey
) x
where s.SetKey = '6062948'

Et voila!  Here's your problematic set!

SetKey
ObjectID
DisplayName
6062948
0DD436A3-C7B5-4D9E-974C-B24E546ED789
Contractor Extended Date 56 days without login

"Great!  Thanks Joe!  ...  Wait, how do I fix it???"  Well, this is out of scope of this blog post, but here are a few web resources to help you.  Good luck!




Wednesday, December 30, 2015

AddMembersToSet.ps1




How to use:
. C:\PS\FIMPowerShell.ps1; . C:\PS\AddMembersToSet.ps1; Import-Csv "C:\PS\PersonsOfInterest.csv" | select 'Resource ID' | % { AddMembersToSet -IdentifierName 'ObjectID' -SetIdentifier '7ee30a29-ca1c-463f-a4ff-0375020b8843' -PersonIdentifiers $_.'Resource ID'  -Verbose }

PersonsOfInterest.csv

"Display Name","Account Name","Resource ID"
"Garth Maul","GMaul","e330d85f-effd-442b-b78f-d6f7681a44e7"
"Sky Walker","SWalker","291959a2-4794-402b-a5f4-f8734326fbe6"
"Don Solo","DSolo","e2ae68a9-6b54-43d7-acb8-6b3ed6a82e45"


AddMembersToSet.ps1

$DefaultUri = "http://localhost:5725"
function AddMembersToSet
{
       [CmdletBinding()]
    PARAM($SetIdentifier, $PersonIdentifiers, $IdentifierName="Email", $Uri = $DefaultUri, [switch]$WhatIf)
    END
    {
        Write-Verbose "`$ResolveSet = ResolveObject-ObjectType 'Set' -AttributeName $IdentifierName -AttributeValue$SetIdentifier"
        $ResolveSet = ResolveObject -ObjectType "Set" -AttributeName $IdentifierName -AttributeValue $SetIdentifier
        $ResolveSet | Import-FIMConfig -Uri $Uri
             Write-Verbose "`$ResolveSet: "
             $ResolveSet
        $ImportObjects = $NULL
        $AddedMembers = $NULL
        foreach($PersonIdentifier in $PersonIdentifiers)
        {
                    Write-Verbose "`$ImportObject = ResolveObject -ObjectType 'Person'-AttributeName $IdentifierName -AttributeValue $PersonIdentifier"
            $ImportObject = ResolveObject -ObjectType "Person" -AttributeName $IdentifierName -AttributeValue $PersonIdentifier
                    $ImportObject | Import-FIMConfig -Uri $Uri
                    Write-Verbose "`$ImportObject: "
                    $ImportObject
            if($AddedMembers -eq $NULL)
            {
                $AddedMembers = @($ImportObject.SourceObjectIdentifier)
            }
            else
            {
                $AddedMembers += $ImportObject.SourceObjectIdentifier
            }
            if($ImportObjects -eq $NULL)
            {
                $ImportObjects = @($ImportObject)
            }
            else
            {
                $ImportObjects += $ImportObject
            }
        }
       
        $ModifyImportObject = ModifyImportObject -TargetIdentifier $ResolveSet.TargetObjectIdentifier -ObjectType "Set"
        $ModifyImportObject.SourceObjectIdentifier = $ResolveSet.SourceObjectIdentifier
             Write-Verbose "`$ModifyImportObject: "
             $ModifyImportObject
       
        foreach($AddedMember in $AddedMembers)
        {
            $newValue = $AddedMember
            #The followingline adds all of the Person resources to the Set (if not commented out).
            AddMultiValue -ImportObject $ModifyImportObject -AttributeName "ExplicitMember" -NewAttributeValue $newValue -FullyResolved 0
            #The followingline removes all of the Person resources from the Set (if not commented out).
            #RemoveMultiValue-ImportObject $ModifyImportObject -AttributeName "ExplicitMember"-NewAttributeValue $newValue -FullyResolved 0
        }
        $ImportObjects += $ModifyImportObject
             if (!$WhatIf) {
              #The following line will update the Setobject with the added members (if not commented out).
                    $ImportObjects | Import-FIMConfig -Uri $Uri
                #$ImportObjects | % { Import-FIMConfig$_ -Uri $Uri; Break }
             } else {
              #The following line returns a referenceto the ImportObject collection (if not commented out).
              $ImportObjects
             }
    }
}

Monday, November 9, 2015

How to: fix unexpected-error (not supported)

Obligatory disclaimer: This method of fixing your FIM Sync database manually is not supported; use at your own risk! As always, back up your FIM Sync database before attempting any such operation.

Now that we've got that out of the way, I wouldn't be blogging about this if it hadn't worked.

A little bit of background: I troubleshot this error back in 2012, so I'm working from my notes. I believe the 'unexpected-error' showed up in the run history, but I can't remember if FIM Sync actually crashed; maybe this will help someone out there anyway. At the time, I recall troubleshooting an actual crash of miiserver.exe, so unfortunately I don't remember if we had tried storechk.exe before I fixed the database with this hack.  Anyway, here goes...

I've pasted the event log entry at the bottom of this post for reference.  General steps to fix are:

1. Enumerate orphaned CS-MV links
2. Save off orphaned links
3. Delete CS records
4. Delete links
5. Full import from affected MAs
6. Full syncs as necessary


1. Enumerate orphaned CS-MV links

select cs.ma_id, ma.[ma_name] ,count(*) as [count],min([initial_import_error_date]) as [min initial import error date]
from dbo.mms_connectorspace cs
join [dbo].[mms_management_agent] ma
on ma.[ma_id] = cs.[ma_id]
join (

SELECT [mv_object_id]
,mv.[object_id] as [mv.object_id]
      ,[cs_object_id]
      ,[lineage_id]
      ,[lineage_date]
  FROM [FIMSynchronizationService].[dbo].[mms_csmv_link] csmv

full outer join [FIMSynchronizationService].[dbo].[mms_metaverse] mv

on mv.[object_id] = csmv.[mv_object_id]
where mv.[object_id] is null
)b
on b.cs_object_id = cs.object_id
group by cs.ma_id, ma.[ma_name]
order by count(*) desc

ma_name
count
min initial import error date
SQL - Roles
764
10/17/12 6:43 AM
SQL - Virtual
348
NULL
SQL - 3rd party
277
10/16/12 8:16 PM
SQL - Principal
277
10/16/12 8:09 PM
AD-LDS - Partners
251
10/16/12 9:06 PM
SQL - Groups
238
10/16/12 8:07 PM
SQL - SSO
238
10/16/12 8:08 PM
SQL - Mapping
2
10/17/12 5:27 AM
SQL - User gen
2
10/17/12 5:43 AM
AD - Primary
2
10/17/12 3:51 AM
ECMA - Java
1
10/17/12 3:40 AM
ECMA - Web services
1
10/17/12 3:47 AM

2. Save off orphaned links
SELECT [mv_object_id]
,mv.[object_id] as [mv.object_id]
      ,[cs_object_id]
      ,[lineage_id]
      ,[lineage_date]
into #wehackedit
  FROM [FIMSynchronizationService].[dbo].[mms_csmv_link] csmv
full outer join [FIMSynchronizationService].[dbo].[mms_metaverse] mv
on mv.[object_id] = csmv.[mv_object_id]
where mv.[object_id] is null

3. Delete CS records

delete from dbo.mms_connectorspace
where object_id in
(
select cs_object_id from #wehackedit
)

4. Delete links

delete from dbo.mms_csmv_link
where mv_object_id in
(
select [mv_object_id] from #wehackedit
)

Event log

Event Type:    Error
Event Source:    MIIServer
Event Category:    Server
Event ID:    6301
Date:        10/18/2012
Time:        12:17:53 AM
User:        N/A
Computer:    FIMSYNC01
Description:
The server encountered an unexpected error in the synchronization engine:

"BAIL: MMS(7924): sproc.cpp(1198): 0x80230405 (The operation failed because the object cannot be found)
BAIL: MMS(7924): imgbldr.cpp(1216): 0x80230405 (The operation failed because the object cannot be found)
BAIL: MMS(7924): imgbldr.cpp(1078): 0x80230405 (The operation failed because the object cannot be found)
BAIL: MMS(7924): imgbldr.cpp(3145): 0x80230405 (The operation failed because the object cannot be found)
BAIL: MMS(7924): mvobj.cpp(199): 0x80230405 (The operation failed because the object cannot be found)
BAIL: MMS(7924): nsmvimp.cpp(274): 0x80230405 (The operation failed because the object cannot be found)
BAIL: MMS(7924): csobj.cpp(2062): 0x80230405 (The operation failed because the object cannot be found)
BAIL: MMS(7924): synccore.cpp(555): 0x80230405 (The operation failed because the object cannot be found)
BAIL: MMS(7924): synccoreimp.cpp(118): 0x80230405 (The operation failed because the object cannot be found)
BAIL: MMS(7924): synccoreimp.cpp(5842): 0x80230405 (The operation failed because the object cannot be found)
BAIL: MMS(7924): synccoreimp.cpp(2224): 0x80230405 (The operation failed because the object cannot be found)
ERR: MMS(7924): synccoreimp.cpp(2240): 0x80230405 - CS to MV to CS synchronization failed 0x80230405: [U12345678]
BAIL: MMS(7924): synccoreimp.cpp(2076): 0x80230405 (The operation failed because the object cannot be found)
ERR: MMS(7924): syncmonitor.cpp(2502): SE: Rollback SQL transaction for: 0x80230405
MMS(7924): SE: CS image begin
MMS(7924): <cs-object cs-dn="U12345678" id="{3FDD7506-5A93-4572-A60C-D22F4F46BEFC}" object-type="person">
  <unapplied-export>
    <delta operation="none" dn="U12345678">
      <anchor encoding="base64">EgAAAFUANgAyADAANAAyADEAMQA0AA==</anchor>
    </delta>
  </unapplied-export>
  <escrowed-export>
    <delta operation="none" dn="U12345678">
      <anchor encoding="base64">EgAAAFUANgAyADAANAAyADEAMQA0AA==</anchor>
    </delta>
  </escrowed-export>
  <unconfirmed-export>
    <delta operation="none" dn="U12345678">
      <anchor encoding="base64">EgAAAFUANgAyADAANAAyADEAMQA0AA==</anchor>
    </delta>
  </unconfirmed-export>
  <pending-import>
    <delta operation="none" dn="U12345678">
      <anchor encoding="base64">EgAAAFUANgAyADAANAAyADEAMQA0AA==</anchor>
    </delta>
  </pending-import>
  <synchronized-hologram>
    <entry dn="U12345678">
      <anchor encoding="base64">EgAAAFUANgAyADAANAAyADEAMQA0AA==</anchor>
      <primary-objectclass>person</primary-objectclass>
      <objectclass>
        <oc-value>person</oc-value>
      </objectclass>
      <attr name="DepartmentId" type="string" multivalued="false">
        <value>4321</value>
      </attr>
      <attr name="EmployeeId" type="string" multivalued="false">
        <value>U12345678</value>
      </attr>
      <attr name="UserId" type="string" multivalued="false">
        <value>U12345678</value>
      </attr>
    </entry>
  </synchronized-hologram>
  <anchor encoding="base64">EgAAAFUANgAyADAANAAyADEAMQA0AA==</anchor>
  <connector>1</connector>
  <connector-state>normal</connector-state>
  <seen-by-import>1</seen-by-import>
  <rebuild-in-progress>0</rebuild-in-progress>
  <obsoletion>0</obsoletion>
  <need-full-sync>0</need-full-sync>
  <placeholder-parent>0</placeholder-parent>
  <placeholder-link>0</placeholder-link>
  <placeholder-delete>0</placeholder-delete>
  <pending>0</pending>
  <ref-retry>0</ref-retry>
  <rename-retry>0</rename-retry>
  <sequencers>
    <current>
      <batch-number>31008</batch-number>
      <sequence-number>1529595</sequence-number>
    </current>
    <unapplied>
      <batch-number>31008</batch-number>
      <sequence-number>1529595</sequence-number>
    </unapplied>
    <original>
      <batch-number>31008</batch-number>
      <sequence-number>1529595</sequence-number>
    </original>
  </sequencers>
  <import-delta-operation>none</import-delta-operation>
  <export-delta-operation>none</export-delta-operation>
  <pending-ref-delete>0</pending-ref-delete>
  <ma-id>{410910BB-AACB-41A5-B622-7F40F246D26C}</ma-id>
  <ma-name>SQL - Roles</ma-name>
  <partition-id>{BA290343-1315-40EF-96AF-32A2D0069B36}</partition-id>
  <import-errordetail first-occurred="2012-10-17 06:45:38.283" date-occurred="2012-10-18 07:08:11.347" retry-count="16" error-type="unexpected-error">
    <import-status>
    </import-status>

  </import-errordetail>
  <mv-link lineage-id="{F434C74C-B9B8-4BCD-858B-B221447E1FC7}" lineage-type="provisioning-rules" lineage-time="2012-09-08 07:14:07.080">{9FC0E55D-F64C-4237-9255-8B3C9756C4CE}</mv-link>
  <last-import-delta-time>2012-10-18 06:14:51.587</last-import-delta-time>
  <last-export-delta-time>2012-10-16 07:36:12.437</last-export-delta-time>
</cs-object>

MMS(7924): SE: CS image end
Microsoft Identity Integration Server 3.3.0118.0"

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.