CategoriesIdentity

Simple MIM Sync Run Profiles Scheduler using PowerShell and Task Scheduler – GG EZ

Today I’m going to share one weird trick to schedule MIM Run Profiles using PowerShell. Consultants hate me. Let’s get started.

Script

We are going to create two folders. The first folder is where we are going to store the PowerShell script and configuration. The second folder is where we are going to store our logfiles. I will use C:\MIMRunScheduler and C:\MIMRunScheduler\Log.

param([string]$configfile=$(Read-Host -prompt "Configfile"))

### Load Configuration Data ###
[xml]$maconfig=(Get-Content $configfile)
"" > $maconfig.runcycle.logfile
$sourceFolder="C:\MIMRunScheduler\"
### Functions ###
$line = "---------------------------------------------------------------------------------"
function Write-Output-Banner([string]$msg) {
       Write-Output $line,(" "+$msg),$line
    Write-Output $line,(" "+$msg),$line | Add-Content $sourceFolder"Log\$(Get-Date -f yyyy-MM-dd).log"
}

function Write-Output-Text([string]$msg) {
       Write-Output $msg
    Write-Output $msg | Add-Content $sourceFolder"Log\$(Get-Date -f yyyy-MM-dd).log"
}


### Get Management Agent Data ###
$allMA = @(get-wmiobject -class "MIIS_ManagementAgent" -namespace "root\MicrosoftIdentityIntegrationServer" -computername $maconfig.runcycle.computername)
$numOfExecDone = 0


### Main Script ###
do {
       Write-Output-Banner("Execution #:"+(++$numOfExecDone)+" - Date: "+(date))
       foreach($MANextRun in $maconfig.runcycle.ma) {
             $found = $false;
             
             foreach($MA in $allMA) {   
               if(!$found) {
                    if($MA.Name.Equals($MANextRun.name)) {
                           $found=$true;
                           Write-Output-Banner("MA: "+$MA.Name+" [Type: "+$MA.Type+"]")
                           Write-Output-Text(" - Starting Pre-Script: "+$MANextRun.preScript)
                           invoke-expression $MANextRun.preScript | Out-Null
                           Write-Output-Text(" - Done`n")
                           
                           foreach($profileName in $MANextRun.profilesToRun) {
                                  Write-Output-Text(" - Starting Profile: "+$profileName)
                                  $datetimeBefore = Get-Date;
                                  $result = $MA.Execute($profileName);
                                  $datetimeAfter = Get-Date;
                                  $duration = $datetimeAfter - $datetimeBefore;
                                  Write-Output-Text(" - Done with status: "+$result.ReturnValue+" - Duration: "+$duration.Hours+":"+$duration.Minutes+":"+$duration.Seconds+"`n")
                           }
                           
                           Write-Output-Text(" - Starting Post-Script: "+$MANextRun.postScript)
                           invoke-expression $MANextRun.postScript | Out-Null
                           Write-Output-Text(" - Done`n")
                           Start-Sleep -s $MANextRun.waitSeconds
                    }
               }
             }
             if(!$found) { Write-Output-Text("Not found MA name :"+$MANextRun.name); }
       }

       $continue = ($maconfig.runcycle.cycleWaitSeconds -EQ 0) -OR ($numOfExecDone -lt $maconfig.runcycle.numOfExecs) -OR ($maconfig.runcycle.numOfExecs -EQ -1)
       if($continue) { 
             Write-Output-Banner("Sleeping "+$maconfig.runcycle.cycleWaitSeconds+" seconds")
             Start-Sleep -s $maconfig.runcycle.cycleWaitSeconds
       }
} while($continue)

Save the PowerShell script as C:\MIMRunScheduler\MIMRunCycle.ps1.

The PowerShell script accepts an XML configuration file as a parameter and causes the MIM Synchronization Engine runs to be performed. How the runs are performed is described in the configuration file.

Within the PowerShell script, there is a $sourceFolder variable. This is responsible for the location where the log files will reside.

Script Syntax

.\MIMRunCycle.ps1 [-configFile] <location>

-configFile <location>

The <location> refers to the location of the configuration file. The following example shows how this can be done:

-configfile C:\MIMRunScheduler\FULLConfig.XML

NameValue
Required?True
Accept wildcard characters?False
Accept pipeline input?False
PositionNamed

Configuration

We are going to create two additional scripts called C:\MIMRunScheduler\pre.ps1 and C:\MIMRunScheduler\post.ps1. If you want to perform an action right before or after a run, you can use these two scripts. We are going to leave them empty.

<?xml version="1.0" encoding="UTF-8"?>
<runcycle numOfExecs="0" cycleWaitSeconds="15" computerName=".">
   <MA>
      <name>ADMA</name>
      <preScript>C:\MIMRunScheduler\pre.ps1</preScript>
      <profilesToRun>FIFS</profilesToRun>
      <postScript>C:\MIMRunScheduler\post.ps1</postScript>
      <waitSeconds>5</waitSeconds>
   </MA>
   <MA>
      <name>MIMMA</name>
      <preScript>C:\MIMRunScheduler\pre.ps1</preScript>
      <profilesToRun>FIFS</profilesToRun>
      <postScript>C:\MIMRunScheduler\post.ps1</postScript>
      <waitSeconds>5</waitSeconds>
   </MA>
</runcycle>

Save the configuration file as C:\MIMRunScheduler\FULLConfig.xml.

Configuration Syntax

Each configuration file starts with the XML declaration.

<?xml version="1.0" encoding="UTF-8"?>

After that, run cycles (runcycle in XML) can be defined. A runcycle contains three parameters.

<runcycle numOfExecs="0" cycleWaitSeconds="15" computerName=".">
NameDatatypeDescription
numOfExecsInteger0 = perform the run once
-1 = perform the runs in perpetuity
>0 = define how often the runs should be performed
cycleWaitSecondsIntegerTime between performing run cycles in seconds.
computerNameStringSpecify the computer name in FQDN or in NetBIOS on which MIM is installed. Use the value “.” if the PowerShell script is running on the same server on which MIM is installed.

In a runcycle, multiple MA elements (<MA>) can be defined. In each MA element contains the following elements.

   <MA>
      <name>ADMA</name>
      <preScript>C:\MIMRunScheduler\pre.ps1</preScript>
      <profilesToRun>FIFS</profilesToRun>
      <postScript>C:\MIMRunScheduler\post.ps1</postScript>
      <waitSeconds>5</waitSeconds>
   </MA>
NameDatatypeDescription
nameStringSpecify the name of the Management Agent.
preScriptStringSpecify the location of the PowerShell script to be performed before the run.
profilesToRunStringSpecify the run profile of the selected Management Agent from the name element.
postScriptStringSpecify the location of the PowerShell script to be performed after the run.
waitSecondsIntegerSpecify how many seconds to wait between running the Management Agents.

Task Scheduler

Create a new task in Windows Task Scheduler.

In the General tab, ensure that the task is run by a service account with sufficient rights in MIMSync. Furthermore, pay attention to the Local Security PolicyLocal PoliciesUser Rights Management > Log on as a batch job permission.

Go to the Actions tab.

Press New… to create a new action.

Action:Start a program
Program/script:Powershell.exe “C:\MIMRunScheduler\MIMRunCycle.ps1”
Add arguments (optional):-configfile “C:\MIMRunScheduler\FULLConfig.XML”

Click on OK to save.

Side note: In some environments, the PowerShell execution policy is set to restricted so make sure that’s dealt with first with the system administrator and security officer.

Action:Start a program
Program/script:Powershell.exe -ExecutionPolicy Bypass “C:\MIMRunScheduler\MIMRunCycle.ps1”
Add arguments (optional):-configfile “C:\MIMRunScheduler\FULLConfig.XML”
Disclaimer: Use -ExecutionPolicy Bypass at your own discretion. CISO’s hate this one trick.

Save and run the task.

Conclusion

That’s all folks! I really prefer this method of scheduling MIMSync runs because the script is very lightweight and easy to understand. Hope that you can make use of this. Have a good one.

Leave a Reply

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