Building a good schedule for FIM 2010 and MIM 2016 Synchronization Service is a crucial part of every design.
In this post I will show you an example of the PowerShell script I use to schedule the Synchronization Service.
TaskScheduler
This script uses a few techniques that I have found useful.

  • Running Parallel Pofiles
  • Custom Profile to add Sleep option
  • Custom Profile to add Script option

Parallel Profiles

Using the capability in PowerShell to start background jobs I can run some profiles in Parallel.
Please note that it is NOT supported to run any profiles that include Synchronization in parallel with other profiles.
Since a typical flow in scheduling is…

  1. Import
  2. Synchronize
  3. Export

and the Import and Export can be done in parallel I have three sections in the script. The first and last section allows for parallel execution and the middle one is for sequential runs.

Sleep Option

I have added the Sleep:seconds as a profile option. It is useful when you know it’s a good idea for the service to wait a few seconds before moving to the next step. It could be some SQL actions or WF actions you know are happening that will take a few seconds to complete.

Script Option

The Script:ScriptToRun option is very useful it could be scripts to fire some SQL StoredProcedure or as in the example running the WaitForWF.ps1 to make sure all FIMService WorkFlows are finished before we continue.

PowerShell Script

############
# PARAMETERS
############

$scriptpath = Split-Path $MyInvocation.MyCommand.Path #Used to call other scripts

$ImportAsJob = 
@(
	@{
		MAName="HR";
		ProfileToRun="Full Import";
	};

    @{
		MAName="FIMService";
		ProfileToRun="Delta Import";
	};

    @{
		MAName="AD";
		ProfileToRun="Delta Import";
	};
);


$SyncProfilesOrder = 
@(
	@{
		MAName="HR";
		profilesToRun=@("Delta Sync");
	};

    @{
		MAName="FIMService";
		profilesToRun=@("Export";"Sleep:15";"Script:WaitForWF.ps1";"Delta Import";"Delta Sync");
	};
);

$ExportAsJob = 
@(
	@{
		MAName="AD";
		ProfileToRun="Export";
	};

    @{
		MAName="HR";
		ProfileToRun="Export";
	};
);


############
# DATA
############
$MAs = @(get-wmiobject -class "MIIS_ManagementAgent" -namespace "rootMicrosoftIdentityIntegrationServer" -computername ".")

############
# FUNCTIONs
############
function RunFIMAsJob
    {
    param([string]$MAName, [string]$Profile)
    Start-Job -Name $MAName -ArgumentList $MAName,$Profile -ScriptBlock {
        param($MAName,$Profile)
        $MA = (get-wmiobject -class "MIIS_ManagementAgent" -namespace "rootMicrosoftIdentityIntegrationServer" -computername "." -Filter "Name='$MAName'")
        $return = $MA.Execute($Profile)
        (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + ": " + $MAName + " : " + $Profile + " : " + $return.ReturnValue
        }
    }

############
# PROGRAM
############
(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + ": Starting Schedule"

#ImportAsJob
(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') +": Starting ImportJobs"
foreach($MAToRun in $ImportAsJob)
    {
        (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + ": Starting : " + $MAToRun.MAName + " : " + $MAToRun.ProfileToRun
        $void = RunFIMAsJob $MAToRun.MAName $MAToRun.ProfileToRun
    }
Get-Job | Wait-Job | Receive-Job -Keep
(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') +": Finished ImportJobs"

#Removing Jobs to release resources
Get-Job | Remove-Job

#Sync (not as job)
foreach($MAToRun in $SyncProfilesOrder)
    {
    foreach($profileName in $MAToRun.profilesToRun)
        {
        if($profileName.StartsWith("Sleep"))
            {Start-Sleep -Seconds $profileName.Split(":")[1]}
        elseif($profileName.StartsWith("Script"))
            {& ($scriptpath +""+ ($profileName.Split(":")[1]))}
        else
            {
            $return = ($MAs | ?{$_.Name -eq $MAToRun.MAName}).Execute($profileName)
            (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + ": " + $MAToRun.MAName + " : " + $profileName + " : " + $return.ReturnValue
            }
        }
	}

#ExportAsJob
(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') +": Starting ExportJobs"
foreach($MAToRun in $ExportAsJob)
    {
        (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + ": Starting : " + $MAToRun.MAName + " : " + $MAToRun.ProfileToRun
        $void = RunFIMAsJob $MAToRun.MAName $MAToRun.ProfileToRun
    }
Get-Job | Wait-Job | Receive-Job -Keep
(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') +": Finished ExportJobs"

#Removing Jobs to release resources
Get-Job | Remove-Job

(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') + ": Finished Schedule"

Summary>

Designing a good schedule in MIM and FIM will decrease the time it will take for changes to get applied in different systems. So please spend some time thinking about how to optimize it.

The post Scheduling MIM with advanced options appeared first on Kent Nordström | konab.com.

Next articleNominated as a top SharePoint influencer for harmon.ie’s annual Top 25 SharePoint influencer initiative
Kent Nordström jobbar som expertkonsult inom Security and Identity Management och är idag en av världens främsta experter på Microsoft Identity Manager. Han skrev sin första rad kod i slutet av 70-talet och därifrån har det bara fortsatt. Kent är Microsoft MVP och Microsoft Certified Trainer (MCT) och medlem i Microsoft Extended Expert Team. Hands-on-labbarna Kent leder på LabCenter baseras på hans långa erfarenhet från sina många kunduppdrag. Räkna med att få många tips och trix som inte står i några officiella dokument! Kent är idag en av landets mest anlitade FIM/MIM-konsulter med nära samarbete med Microsoft och har även författat handböcker inom ämnet.