Scheduling MIM with advanced options

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 "root\MicrosoftIdentityIntegrationServer" -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 "root\MicrosoftIdentityIntegrationServer" -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.

2 Replies to “Scheduling MIM with advanced options”

  1. Pingback: Scheduling MIM with LithnetMiisAutomation - Kent Nordström | konab.com

Leave a Reply

Your email address will not be published. Required fields are marked *