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
Name | Value |
Required? | True |
Accept wildcard characters? | False |
Accept pipeline input? | False |
Position | Named |
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=".">
Name | Datatype | Description |
numOfExecs | Integer | 0 = perform the run once -1 = perform the runs in perpetuity >0 = define how often the runs should be performed |
cycleWaitSeconds | Integer | Time between performing run cycles in seconds. |
computerName | String | Specify 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>
Name | Datatype | Description |
name | String | Specify the name of the Management Agent. |
preScript | String | Specify the location of the PowerShell script to be performed before the run. |
profilesToRun | String | Specify the run profile of the selected Management Agent from the name element. |
postScript | String | Specify the location of the PowerShell script to be performed after the run. |
waitSeconds | Integer | Specify 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 Policy – Local Policies – User 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” |
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.