Disclaimer: I am not the original author of this script. He is given credit for his work and I do not claim to have written this. What I have done is add a few functions to the script which make the everyday usage and automation of its running safer and
a little more convenient.
Further Disclaimer: This script works for me and has worked for the past year. HOWEVER, I provide no warranty that it will work. Anything that happens to your FIM environment as a result of this script is not my responsibility or my fault. I may or may not
support the script. It's a contribution to the community with no strings attached. If anyone wants to make it even better, that is awesome! Enjoy.
The first part of the script, the guts, if you will. It should be named RunSequencerProg.ps1.
#################################################################################################################################
# FIM 2010 Management Agent Runner #
# Author : Lance Hext #
# Mail : lhext@h-cp.us #
# Version : 1.2.3 #
# Information : This Powershell script execcutes an array of managements agents supplied form the calling Powershell #
# script. This powershell script utilizes the FIM wmi interface for the execution and statistics #
# gathering. #
# For each Management executed either a single email is generted per management agent #
# or a combined email is generated which will contain all the statistic from the run. #
# The email containes the following information as part on the email body #
# 1: The Managemenmt agent name #
# 2: The Mnagement Agent complition status #
# 3: All Connector space statistics #
# 4: All Inbound Metaverse statistices #
# 5: All Export data counts #
# The email contains the following attachments #
# 1: The complete run history xml #
# 2: All inbound syncronization errors #
# 3: All Exported syncronization errors #
# #
# #
# #
#################################################################################################################################
# #
# START OF POWERSHELL SCRIPT #
# #
#################################################################################################################################
# #
# * * * * * * * * * * * D O N O T M O D I F Y B E L O W * * * * * * * * * * * * * #
# __________________________________ #
# #
#################################################################################################################################
#################################################################################################################################
# START OF FUNCTIONS #
#################################################################################################################################
$line = "-----------------------------"
function Write-Output-Banner([string]$msg)
{
Write-Output $line,("- "+$msg),$line
}
#################################################################################################################################
# END OF FUNCTIONS #
#################################################################################################################################
# START OF DATA #
#################################################################################################################################
$MAs = @(get-wmiobject -class "MIIS_ManagementAgent" -namespace "root\MicrosoftIdentityIntegrationServer" -computername $params_ComputerName)
$numOfExecDone = 0
$SendEmails = $true;
#################################################################################################################################
# END OF DATA #
#################################################################################################################################
# START OF PROGRAM #
#################################################################################################################################
Write-Output-Banner($SequenceInfo)
do
{
Write-Output-Banner("Execution #:"+(++$numOfExecDone))
if (!$EmailperMA)
{
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$smtpmsg = new-object Net.Mail.MailMessage
$smtpmsg.From = $emailFrom
$smtpmsg.To.Add($emailTo)
if ($emailCC)
{
$smtpmsg.Cc.Add($emailCC)
}
if ($emailCC1)
{
$smtpmsg.Cc.Add($emailCC1)
}
$RunStart = Get-Date
$AllRunTimeStart = Get-Date -uformat "%Y%m%d%I%M%S"
$smtpmsg.Subject = "FIM Run Sequence Results Started : " +$RunStart
$smtpbody = "<!DOCTYPE html PUBLIC `"-//W3C//DTD XHTML 1.0 Strict//EN`" `"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd`">"
$smtpbody += "<html xmlns=`"http://www.w3.org/1999/xhtml`"><head>"
$smtpbody += "<title>FIM Processing Results</title></head><body>"
if ($debug)
{
$dbugmsg = "--> DB ---- In Single Email Create Mail Object"
Write-Output ($dbugmsg)
}
$AllRuns = "AllRuns-" + $AllRunTimeStart + ".xml"
$AllImportErrorRuns = "AllRuns-" + $AllRunTimeStart + "-ImportErrors.csv"
$AllExportErrorRuns = "AllRuns-" + $AllRunTimeStart + "-ExportErrors.csv"
}
foreach($MATypeNRun in $params_runProfilesOrder)
{
$found = $false;
$SendEmails = $true;
foreach($MA in $MAS)
{
if(!$found)
{
if($MA.Name.Equals($MATypeNRun.name))
{
$abortnow = $false
$found=$true;
$maname = $MA.Name
Write-Output-Banner("MA Name: "+$MA.Name,"`n- Type: "+$MA.Type)
foreach($profileName in $MATypeNRun.profilesToRun)
{
## Added 01/23/2012 :: Author: Ethan Turk
## Change Info: Added to allow sleeping for individual Sync Cycle
## Steps instead of a sleep which must run for every step.
if($MATypeNRun.sleep -gt 0) {
"Found Sleep. Sleeping for " + $MATypeNRun.sleep + " seconds" | Out-Host
Start-Sleep -Seconds $MATypeNRun.sleep
}
## End Addition
## Added 03/05/2012 :: Author: Ethan Turk
## Change Info: Added to set thresholds for maximum number of changes
## which are allowed in a single run step. You can set individual limits
## for add, updates and deletes.
$abortthreshold = "Threshold Reached on $maname $profileName. Cancelling run cycle..."
if($MATypeNRun.addthreshold) {
$ttype = "Add"
$addstatus = .\FIM_ActionThresholds.ps1 $MA.Name $ttype $MATypeNRun.addthreshold
if($addstatus) {
$abortnow = "$ttype $abortthreshold"
break
}
}
if($MATypeNRun.updthreshold) {
$ttype = "Update"
$updstatus = .\FIM_ActionThresholds.ps1 $MA.Name $ttype $MATypeNRun.updthreshold
if($updstatus) {
$abortnow = "$ttype $abortthreshold"
break
}
}
if($MATypeNRun.delthreshold) {
$ttype = "Delete"
$delstatus = .\FIM_ActionThresholds.ps1 $MA.Name $ttype $MATypeNRun.delthreshold
if($delstatus) {
$abortnow = "$ttype $abortthreshold"
break
}
}
## End Addition
Write-Output ("Run Profile "+$profileName,"`n -> starting")
$RunTimeStart = Get-Date -uformat "%Y%m%d%I%M%S"
$datetimeBefore = Get-Date;
$result = $MA.Execute($profileName);
$datetimeAfter = Get-Date;
$duration = $datetimeAfter - $datetimeBefore;
# Setup SMTP Message
if($EmailperMA)
{
if ($debug)
{
$dbugmsg = "--> DB ---- In Multiple Email Create new Mail Object"
Write-Output ($dbugmsg)
}
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
if ($UseEmailCreds)
{
$smtp.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
}
$smtpmsg = new-object Net.Mail.MailMessage
$smtpmsg.From = $emailFrom
$smtpmsg.To.Add($emailTo)
if ($emailCC)
{
$smtpmsg.Cc.Add($emailCC)
}
$smtpbody = "<!DOCTYPE html PUBLIC `"-//W3C//DTD XHTML 1.0 Strict//EN`" `"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd`">"
$smtpbody += "<html xmlns=`"http://www.w3.org/1999/xhtml`"><head>"
$smtpbody += "<title>FIM Processing Results</title></head><body>"
#$smtpbody += "<table><tr><td colspan=2 align=center><u>Forefront Identity Manager Management Agent Run Results for: <b>" + $MA.Name +"</b></u></td></tr>"
$smtpbody += "<table><tr><td colspan=2 align=center><u>Forefront Identity Manager Management Agent Run Results</b></u></td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
$smtpmsg.Subject = "FIM Management Agent - " + $MA.Name
if("success".Equals($result.ReturnValue))
{
$msg = "Done. Duration: "+$duration.Hours+":"+$duration.Minutes+":"+$duration.Seconds
$smtpmsg.Subject += " Processing Success"
$smtpbody += "<tr><td colspan=2><b>" + $MA.Name +"<font color=Green> Completed Successfully</font></b></td></tr>"
if ($EmailOnErrorOnly)
{
$SendEmails = $false;
}
}
else
{
$msg = "Done with Error. Duration: "+$duration.Hours+":"+$duration.Minutes+":"+$duration.Seconds +" - Error: "+$result
$smtpmsg.Subject += " Processing Error"
$smtpbody +="<tr><td colspan=2><b>" + $MA.Name +":<font color=Red> Completed.</font></b></td></tr>"
$smtpbody +="<tr><td colspan=2>MA Synchronization Status: <font color=Red><b>" + $result.ReturnValue + "</font></b></td></tr>"
}
}
else
{
$smtpbody += "<table><tr><td colspan=2 align=center><u>Forefront Identity Manager Management Agent Run Results</u></td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
if("success".Equals($result.ReturnValue))
{
$msg = "Done. Duration: "+$duration.Hours+":"+$duration.Minutes+":"+$duration.Seconds
$smtpbody += "<tr><td colspan=2><b>" + $MA.Name +"<font color=Green> Completed Successfully</font></b></td></tr>"
$smtpbody += "<tr><td colspan=2>MA Synchronization Status: <font color=Green><b>" + $result.ReturnValue + "</font></b></td></tr>"
if ($EmailOnErrorOnly)
{
$SendEmails = $false;
}
}
else
{
$msg = "Done with Error. Duration: "+$duration.Hours+":"+$duration.Minutes+":"+$duration.Seconds +" - Error: "+$result
$smtpbody += "<tr><td colspan=2>" + $MA.Name +":<font color=Red> Completed.</font></b></td></tr>"
$smtpbody += "<tr><td colspan=2>MA Synchronization Status: <font color=Red><b>" + $result.ReturnValue + "</font></b></td></tr>"
}
$SendEmails = $true
if ($debug)
{
$dbugmsg = "--> DB ---- In Single Email : New Table "
Write-Output ($dbugmsg)
}
}
# Problems with RunHistory WMI not working with MaGuid or MaName, so I used RunDetails from the MA.
# $RunHistory = get-wmiobject -class "MIIS_RunHistory" -namespace "root\MicrosoftIdentityIntegrationServer" -filter("MaGuid='" + $MA.guid + "'")
# # Write the RunHistory file XML out to a file to then attach to the e-mail, and also set it to a XML attribute.
# $RunHistory[1].RunDetails().ReturnValue | Out-File RunHistory.xml
# Grab the first run-history, which always is the latest result.
# [xml]$RunHistoryXML = $RunHistory[1].RunDetails().ReturnValue
#Take the MA RunDetails RunHistory XML and write to file.
$RunHistFileName = $MA.Name + "-" + $RunTimeStart +"-RunHistory.xml"
$ImportErrorUserFileName = $MA.Name + "-" + $RunTimeStart + "-ImportErrors.csv"
$ExportErrorUserFileName = $MA.Name + "-" + $RunTimeStart + "-ExportErrors.csv"
$MA.RunDetails().ReturnValue | Out-File $RunHistFileName
# Grab the MA run-history and put it into a XML var.
[xml]$RunHistoryXML = $MA.RunDetails().ReturnValue
[xml]$RunHistory1XML = $MA.RunDetails().ReturnValue
# Build User Errors for Exports
$RunHistoryXML."run-history"."run-details"."step-details"."synchronization-errors"."import-error" | select dn,"error-type" | export-csv $ImportErrorUserFileName
$RunHistoryXML."run-history"."run-details"."step-details"."synchronization-errors"."export-error" | select dn,"error-type" | export-csv $ExportErrorUserFileName
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
$smtpbody += "<tr><td colspan=2><u><b>" + $MA.Name + " Run Statistics</b></u></td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
$smtpbody += "<tr><td width=800px>MA Run Profile:</td><td width=800px align=left><b>" + $profileName+"</b></td></tr>"
$smtpbody += "<tr><td width=800px>Start Date & Time:</td><td width=800px align=left><b>" + $MA.RunStartTime().ReturnValue + "</b></td></tr>"
$smtpbody += "<tr><td width=800px>End Date & Time:</td><td width=800px align=left><b>" + $MA.RunEndTime().ReturnValue + "</b></td></tr>"
$smtpbody += "<tr><td width=800px>Total Run Time:</td><td width=800px align=left><b>"+$duration.Hours+":"+$duration.Minutes+":"+$duration.Seconds + "</b></td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
$smtpbody += "<tr><td colspan=2><u><b>Connector Space Statistics<b></u></td></tr>"
$smtpbody += "<tr><td width=800px>Total Connector Space Objects:</td><td width=800px align=left><b>" + $MA.NumCSObjects().ReturnValue +"</b></td></tr>"
$smtpbody += "<tr><td width=800px>Total Connectors:</td><td width=800px align=left><b>" + $MA.NumTotalConnectors().ReturnValue +"</b></td></tr>"
$smtpbody += "<tr><td width=800px>Connectors:</td><td width=800px align=left><b>" + $MA.NumConnectors().ReturnValue +"</b></td></tr>"
$smtpbody += "<tr><td width=800px>Explicit Connectors:</td><td width=800px align=left><b>" + $MA.NumExplicitConnectors().ReturnValue +"</b></td></tr>"
$smtpbody += "<tr><td width=800px>Total Disconnectors:</td><td width=800px align=left><b>" + $MA.NumTotalDisconnectors().ReturnValue +"</b></td></tr>"
$smtpbody += "<tr><td width=800px>Disconnectors:</td><td width=800px align=left><b>" + $MA.NumDisconnectors().ReturnValue +"</b></td></tr>"
$smtpbody += "<tr><td width=800px>Explicit Disconnectors:</b></td><td><b>" + $MA.NumExplicitDisconnectors().ReturnValue +"</b></td></tr>"
$smtpbody += "<tr><td width=800px>Total Placeholders:</b></td><td width=800px align=left><b>" + $MA.NumPlaceholders().ReturnValue +"</b></td></tr>"
$smtpbody += "<tr><td width=800px>Total Placeholders:</b></td><td width=800px align=left><b>" + $MA.NumPlaceholders().ReturnValue +"</b></td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
#################################################################################################################################
# Discovery Counters #
#################################################################################################################################
$smtpbody += "<tr><td colspan=2><u><b>Discovoery Statistics</b></u></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/ma-discovery-counters/filtered-deletions")
$smtpbody += "<tr><td width=800px>Filtered Deletions</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/ma-discovery-counters/filtered-objects")
$smtpbody += "<tr><td width=800px>Filtered Objects:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
#################################################################################################################################
# Staging Counters #
#################################################################################################################################
$smtpbody += "<tr><td colspan=2><u><b>Stage Import Statistics</b></u></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/staging-counters/stage-no-change")
$smtpbody += "<tr><td width=800px>Import Stage Unchanged:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/staging-counters/stage-add")
$smtpbody += "<tr><td width=800px>Import Stage Add:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/staging-counters/stage-update")
$smtpbody += "<tr><td width=800px>Import Stage Updates:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/staging-counters/stage-delete")
$smtpbody += "<tr><td width=800px>Import Stage Deletes:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/staging-counters/stage-delete-add")
$smtpbody += "<tr><td width=800px>Import Stage Delete-Adds:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/staging-counters/stage-failure")
$smtpbody += "<tr><td width=800px>Import Stage Failures:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
#################################################################################################################################
# MV Inbound Counters #
#################################################################################################################################
$smtpbody += "<tr><td colspan=2 align=center><u><b>Inbound Statistics</b></u></td></tr>"
$smtpbody += "<tr><td colspan=2 align=left><u><b>Disconnectors</b></u></td></tr>"
$smtpbody += "<tr><td width=800px align=right>Filtered Disconnectors:</b></td><td><b>" + $MA.NumFilteredDisconnectors().ReturnValue +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/disconnector-remains")
$smtpbody += "<tr><td width=800px align=right>Disconnectors</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$smtpbody += "<tr><td colspan=2 align=center> </td></tr>"
$smtpbody += "<tr><td colspan=2 align=left><u><b>Metaverse</b></u></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/disconnector-projected-flow")
$smtpbody += "<tr><td width=800px align=right>Projections - With Flow Updates:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/disconnector-projected-no-flow")
$smtpbody += "<tr><td width=800px align=right>Projections - Without Flow Updates:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/disconnector-joined-flow")
$smtpbody += "<tr><td width=800px align=right>Joins - With Flow Updates:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/disconnector-joined-no-flow")
$smtpbody += "<tr><td width=800px align=right>Joins - Without Flow Updates:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/connector-flow-remove-mv")
$smtpbody += "<tr><td width=800px align=right>Deleted Metaverse Objects</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/connector-delete-leave-mv")
$smtpbody += "<tr><td width=800px align=right>Disconnected Metaverse Objects</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/flow-failure")
$smtpbody += "<tr><td width=800px align=right>Metaverse Flow Failures</b></td><td width=800px align=left><b><font=Red>" + $mvValue.InnerText +"</font></b></td></tr>"
$smtpbody += "<tr><td colspan=2 align=left><u><b>Connector Objects</b></u></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/connector-flow")
$smtpbody += "<tr><td width=800px align=right>Connector With Flow Updates:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/connector-no-flow")
$smtpbody += "<tr><td width=800px align=right>Connector Without Flow Updates:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/connector-filtered-leave-mv")
$smtpbody += "<tr><td width=800px align=right>Connector Filtered</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/connector-filtered-remove-mv")
$smtpbody += "<tr><td width=800px align=right>Connector Filtered Deleted</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/connector-delete-add-processed")
$smtpbody += "<tr><td width=800px align=right>Connector Delete-Add</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
# $mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/disconnector-projected-remove-mv")
# $smtpbody += "<tr><td width=800px>Metaverse Disconnectors Projected</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
# $mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/inbound-flow-counters/disconnector-joined-remove-mv")
# $smtpbody += "<tr><td width=800px>MV Deleted - Joined Disconnectors</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$smtpbody += "<tr><td colspan=2> </td></tr>"
$smtpbody += "<tr><td colspan=2><u><b>Export Statistics</b></u></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/export-counters/export-add")
$smtpbody += "<tr><td width=800px>Export Adds</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/export-counters/export-update")
$smtpbody += "<tr><td width=800px>Export Updates</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/export-counters/export-rename")
$smtpbody += "<tr><td width=800px>Export Renames</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/export-counters/export-delete")
$smtpbody += "<tr><td width=800px>Export Deletes</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/export-counters/export-delete-add")
$smtpbody += "<tr><td width=800px>Export Delete-Adds</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $RunHistory1XML.SelectSingleNode("run-history/run-details/step-details/export-counters/export-failure")
$smtpbody += "<tr><td width=800px>Export Failures</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$smtpbody += "<tr><td colspan=2> </td></tr>"
#################################################################################################################################
# Outbound Counters #
#################################################################################################################################
$outboundCounters=$RunHistory1XML.SelectNodes("run-history/run-details/step-details/outbound-flow-counters")
foreach($outboundCounter in $outboundCounters)
{
$mvValue = $outboundCounter.ma
if ($debug)
{
Write-Output ($outboundCounter)
Write-Output ($mvValue)
}
$smtpbody += "<tr><td colspan=2><u><b>OutBound Statistics for: " + $mvValue + "</b></u></td></tr>"
$mvValue = $outboundCounter.SelectSingleNode("provisioned-add-flow")
$smtpbody += "<tr><td width=800px>Provisioning Adds:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $outboundCounter.SelectSingleNode("provisioned-disconnect")
$smtpbody += "<tr><td width=800px>Provisioning Disconnect:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$mvValue = $outboundCounter.SelectSingleNode("connector-flow")
$smtpbody += "<tr><td width=800px>Export Attribute Flow:</b></td><td width=800px align=left><b>" + $mvValue.InnerText +"</b></td></tr>"
$smtpbody += "<tr><td colspan=2> </td></tr>"
}
$smtpbody += "<tr><td colspan=2> </td></tr>"
$smtpbody += "</table></body></html>"
# Write-Output ( $smtpbody )
if($EmailperMA)
{
if ($debug)
{
$dbugmsg = "--> DB ---- In Multiple Email Send"
Write-Output ($dbugmsg)
}
$RHFile = new-object Net.Mail.Attachment([string](get-location)+'\'+ $RunHistFileName)
$smtpmsg.Attachments.Add($RHFile)
$IUFile = new-object Net.Mail.Attachment([string](get-location)+'\'+ $ImportErrorUserFileName)
$smtpmsg.Attachments.Add($IUFile)
$EUFile = new-object Net.Mail.Attachment([string](get-location)+'\'+ $ExportErrorUserFileName)
$smtpmsg.Attachments.Add($EUFile)
$smtpmsg.Body = $smtpbody
$smtpmsg.IsBodyHTML = $true
if ($SendEmails)
{
$smtp.Send($smtpmsg)
}
$RHFile.Dispose()
$IUFile.Dispose()
$EUFile.Dispose()
remove-item $RunHistFileName
remove-item $ImportErrorUserFileName
remove-item $ExportErrorUserFileName
}
else
{
if ($debug)
{
$dbugmsg = "--> DB ---- In Single Email Conat files"
Write-Output ($dbugmsg)
}
cat $RunHistFileName > $AllRuns
cat $ImportErrorUserFileName > $AllImportErrorRuns
cat $ExportErrorUserFileName > $AllExportErrorRuns
remove-item $RunHistFileName
remove-item $ImportErrorUserFileName
remove-item $ExportErrorUserFileName
}
Write-Output (" -> "+$msg)
Write-Output (" -> "+$result.ReturnValue)
}
}
}
if($abortnow) { break }
}
if(!$found -and !$abortnow)
{
Write-Output ("Not found MA Name:"+$MATypeNRun.name);
}
}
if($abortnow) { $abortnow | Out-Host }
$continue = ($params_numOfExecs -EQ 0) -OR ($numOfExecDone -lt $params_numOfExecs)
if($continue)
{
Write-Output-Banner("Sleeping "+$params_delayBetweenExecs+" seconds")
if ($debug)
{
$dbugmsg = "--> DB ---- In Single Email SLEEP Send"
Write-Output ($dbugmsg)
}
if(!$EmailperMA)
{
$smtpbody = "<font style='font-size: x-large; color: red;'>" + $abortnow +
"</font><br /><br />" + $smtpbody
$RHFile = new-object Net.Mail.Attachment([string](get-location)+'\'+ $AllRuns)
$smtpmsg.Attachments.Add($RHFile)
$IUFile = new-object Net.Mail.Attachment([string](get-location)+'\'+ $AllImportErrorRuns )
$smtpmsg.Attachments.Add($IUFile)
$EUFile = new-object Net.Mail.Attachment([string](get-location)+'\'+ $AllExportErrorRuns )
$smtpmsg.Attachments.Add($EUFile)
$smtpmsg.Body = $smtpbody
$smtpmsg.IsBodyHTML = $true
if ($SendEmails -and $abortnow)
{
$smtp.Send($smtpmsg)
}
$RHFile.Dispose()
$IUFile.Dispose()
$EUFile.Dispose()
remove-item $AllRuns
remove-item $AllImportErrorRuns
remove-item $AllExportErrorRuns
}
Start-Sleep -s $params_delayBetweenExecs
}
else
{
Write-Output ("******************************")
}
}
while($continue)
if(!$EmailperMA)
{
$smtpbody = "<font style='font-size: x-large; color: red;'>" +
$abortnow + "</font><br /><br />" + $smtpbody
if ($debug)
{
$dbugmsg = "--> DB ---- In Single Email Send"
Write-Output ($dbugmsg)
}
$RHFile = new-object Net.Mail.Attachment([string](get-location)+'\'+ $AllRuns)
$smtpmsg.Attachments.Add($RHFile)
$IUFile = new-object Net.Mail.Attachment([string](get-location)+'\'+ $AllImportErrorRuns )
$smtpmsg.Attachments.Add($IUFile)
$EUFile = new-object Net.Mail.Attachment([string](get-location)+'\'+ $AllExportErrorRuns )
$smtpmsg.Attachments.Add($EUFile)
$smtpmsg.Body = $smtpbody
$smtpmsg.IsBodyHTML = $true
if ($SendEmails -and $abortnow)
{
$smtp.Send($smtpmsg)
}
$RHFile.Dispose()
$IUFile.Dispose()
$EUFile.Dispose()
remove-item $AllRuns
remove-item $AllImportErrorRuns
remove-item $AllExportErrorRuns
}
The Guts gets its parameters from a separate file, The Parameters, which allows for multiple run sequences without modifying the standard code. It can be named anything. This is the script that you will run to kick off your Sync Cycle.
#@author: Lance Hext
#@mail: lhext@h-cp.us
#############################################################################################
# PARAMETERS #
#############################################################################################
# #
# $debug #
# debug on = $true; #
# Debug off = $false; #
# #
#############################################################################################
#
$debug = $false;
#
#############################################################################################
# #
# $SequenceInfo #
# Place some meaningfull information for display at the #
# begininiong of the squ3nce #
# #
#############################################################################################
#
$SequenceInfo = "Hourly Syncronization Sequence"
#
#############################################################################################
# #
# $params_ComputerName #
# The name of the server running FIM #
# Use "." if running on the Powershell script on the FIM server #
# #
#############################################################################################
#
$params_ComputerName = "."
#
#############################################################################################
# #
# $params_delayBetweenExecs #
# delay between each execution, in seconds #
# 1 Minute = 60 #
# 10 Minutes = 600 #
# 15 Minutes = 900 #
# 30 Minutes = 1800 #
# 1 Hour = 3600 #
# #
#############################################################################################
#
$params_delayBetweenExecs = 0
#
#############################################################################################
# #
# $params_numOfExecs #
# The number of executions the script will run before terminating #
# 0 for infinite #
# #
#############################################################################################
#
$params_numOfExecs = 1
#
#############################################################################################
# RUN Profile Sequenec Section #
# #
# The array below contains the MA run sequence order #
# #
# Format #
# @{ #
# name="<This has to match exactly the MA name in FIM>"; #
# profilesToRun=@("<This has to match the Run profile to Execute>"); #
# }; #
# #
#############################################################################################
#
## Addition Info :: Author: Ethan Turk
## Change Info 1: Added to set thresholds for maximum number of changes
## which are allowed in a single run step. You can set individual limits
## for add, updates or deletes.
##
## Ex: Add 'addthreshold=100;', 'delthreshold=100;' or 'updthreshold=1000;' to the
## cycle step below.
## See the 'AD MA' Export step below.
##
## Change Info 2: Added ability to set a mandatory sleep for individual
## sync cycle steps instead of a sleep for the whole set of steps.
##
## Ex: Add 'sleep=120;' to the cycle step below.
## See the 'FIM MA' Delta Import step below.
$params_runProfilesOrder =
@(
@{
name="HR MA";
profilesToRun=@("Full Import");
};
@{
name="HR MA";
profilesToRun=@("Full Sync");
};
@{
name="FIM MA";
profilesToRun=@("Export");
};
@{
name="FIM MA";
profilesToRun=@("Delta Import");
sleep=120;
};
@{
name="FIM MA";
profilesToRun=@("Delta Sync");
};
@{
name="AD MA";
profilesToRun=@("Export");
addthreshold=100;
delthreshold=100;
updthreshold=1000;
};
@{
name="AD MA";
profilesToRun=@("Delta Import");
};
@{
name="AD MA";
profilesToRun=@("Delta Sync");
};
@{
name="AD MA";
profilesToRun=@("Export");
addthreshold=100;
delthreshold=100;
updthreshold=1000;
};
@{
name="AD MA";
profilesToRun=@("Delta Import");
};
@{
name="AD MA";
profilesToRun=@("Delta Sync");
};
@{
name="FIM MA";
profilesToRun=@("Export");
};
@{
name="FIM MA";
profilesToRun=@("Delta Import");
};
@{
name="FIM MA";
profilesToRun=@("Delta Sync");
};
@{
name="FIM MA";
profilesToRun=@("Export");
};
@{
name="FIM MA";
profilesToRun=@("Full Import");
};
@{
name="FIM MA";
profilesToRun=@("Delta Sync");
};
);
#
#############################################################################################
# EMAIL PARAMETERS #
#############################################################################################
# #
# $UseEmailCreds #
# Directs the PowerShell script to send Using Credentials #
# $true; = Send email with Creds #
# $false; = Send email without Creds #
# #
#############################################################################################
#
$UseEmailCreds = $false;
#
#############################################################################################
# #
# $emailFrom #
# A Well formated email address for the FIM Server #
# Example "FIMSequencer@xyz.com" #
# #
#############################################################################################
#
$emailFrom = "SentFrom@yourdomain.com"
#
#############################################################################################
# #
# $emailTo #
# A Well formated email address for Receipent of the email #
# Example "someone@xyz.com" #
# #
#############################################################################################
#
$emailTo = "AdminEmail@yourdomain.com"
#
#############################################################################################
# #
# $emailCC #
# A Well formated email address for send a Copy of the email to #
# Example "carboncopy@xyz.com" #
# #
#############################################################################################
#
$emailCC = ""
#
#############################################################################################
# #
# $emailCC1 #
# A Well formated email address for send a Copy of the email to #
# Example "carboncopy@xyz.com" #
# #
#############################################################################################
#
$emailCC1 = ""
#
#############################################################################################
# #
# $smtpServer #
# A FQDN of a mail server #
# Example "mail.xyz.com" #
# #
#############################################################################################
#
$smtpServer = "your SMTP Server"
#
#############################################################################################
# #
# $EmailperMA #
# Directs the PowerShell script to either send an email at the completion #
# of each MA OR generate One email at the end of the sequence run #
# #
# $true; = Send an email for each MA #
# $false; = Send 1 (one) email at the completion on the Sequence #
# #
#############################################################################################
#
$EmailperMA = $false;
#
#############################################################################################
# #
# $EmailOnErrorOnly #
# Directs the PowerShell script to send and email on failues only #
# $true; = Send email only on an MA Sync Failure ie MA.Result <> "success" #
# $false; = Send email when MA finishes #
# #
#############################################################################################
#
$EmailOnErrorOnly = $false;
#
#############################################################################################
# #
# INCLUDE THE PROGRAM #
# #
# Location of the Actural Program. This can be a relative or physical path #
# #
# NOTE the 1st pewriod is required #
# Examples #
# Physical Path #
# .<space>C:\powershell\RunSequencerProg.ps1 #
# Relative Path #
# .<space>.\RunSequencerProg.ps1 #
# #
#############################################################################################
#
.\RunSequencerProg.ps1
So there is one more piece, The Helper, which contains the functions used to check for the number of pending adds, updates or deletes on a particular MA. It should be named FIM_ActionThresholds.ps1.
param(
[String]$maname,
[String]
[ValidateSet('Delete','Add','Update')]$checktype,
[Int]$itemthreshold = 100,
[String]$servername = "."
)
$found = $false
$lstSrv = @(get-wmiobject -class "MIIS_ManagementAgent" -namespace "root\MicrosoftIdentityIntegrationServer" -computer $servername)
$lstSrv | ForEach-Object {
if($_.Name -eq $maname) {
$found = $true
if($checktype.ToLower() -eq "delete") {
$numactions = [Int]$_.NumExportDelete().ReturnValue
} elseif($checktype.ToLower() -eq "update") {
$numactions = [Int]$_.NumExportUpdate().ReturnValue
} elseif($checktype.ToLower() -eq "add") {
$numactions = [Int]$_.NumExportAdd().ReturnValue
}
if($numactions -ge $itemthreshold) {
return $true
} else {
return $false
}
break
}
}
if($found -eq $false) {
$errmsg = "Did not find MA by the name: $maname"
return $errmsg
}
You are free to modify and redistribute this as you choose. I hope it helps someone else.
-
Edited by
Ethan Turk
Wednesday, May 02, 2012 3:33 PM
Adding script names.