Using PowerShell to start Run Profiles

Thanks to this powershell script, you can easily automatize the execution of run profiles for FIM management agents.

You just have to adapt the PARAMETERS section to your needs.

Here is a screenshot:
Using powershell to start run profile - fabien duchene

And the source code:

# @author: Fabien Duchene

# @mail: fabien.duchene1 **at** googlemail.com



############

# PARAMETERS

############

$params_ComputerName = "."  	# "." is the current computer

$params_delayBetweenExecs = 30 	#delay between each execution, in seconds

$params_numOfExecs = 0  	    #Number of executions 0 for infinite

$params_runProfilesOrder = 

@(

	@{

		type="Forefront Identity Management (FIM)";

		profilesToRun=@("Full Import";"Full Synchronization");

	};

	@{

		type="Active Directory";

		profilesToRun=@("Full Import";"Full Synchronization";"Export");

	};

	

);







############

# FUNCTIONS

############

$line = "-----------------------------"

function Write-Output-Banner([string]$msg) {

	Write-Output $line,("- "+$msg),$line

}









############

# DATAS

############



$MAs = @(get-wmiobject -class "MIIS_ManagementAgent" -namespace "root



\MicrosoftIdentityIntegrationServer" -computername $params_ComputerName)

$numOfExecDone = 0





############

# PROGRAM

############

do {

	Write-Output-Banner("Execution #:"+(++$numOfExecDone))

	foreach($MATypeNRun in $params_runProfilesOrder) {

		$found = $false;

		foreach($MA in $MAS) {	

	

		    if(!$found) {

			if($MA.Type.Equals($MATypeNRun.type)) {

				$found=$true;

				Write-Output-Banner("MA: "+$MA.Type)

				foreach($profileName in $MATypeNRun.profilesToRun) {

					Write-Output (" "+$profileName),"  -> starting"

					$datetimeBefore = Get-Date;

					$result = $MA.Execute($profileName);

					$datetimeAfter = Get-Date;

					$duration = $datetimeAfter - $datetimeBefore;

					if("success".Equals($result.ReturnValue)){

						$msg = "done. Duration: "+$duration.Hours



+":"+$duration.Minutes+":"+$duration.Seconds

					} else { $msg = "Error: "+$result }

	

					Write-Output ("  -> "+$msg)

				}

			}

		    }

		}

		if(!$found) { Write-Output ("Not found MA type :"+$MATypeNRun.type); }

	}

	

	$continue = ($params_numOfExecs -EQ 0) -OR ($numOfExecDone -lt $params_numOfExecs)

	if($continue) { 

		Write-Output-Banner("Sleeping "+$params_delayBetweenExecs+" seconds")

		Start-Sleep -s $params_delayBetweenExecs

	}

} while($continue)



You can also find more informations on my blog: http://fabienduchene.blogspot.com/2009/11/fim-execute-management-agents-run.html
November 18th, 2009 3:15pm

Very cool, Fabien, thanks for sharing the script with the community!
I have added your script to the catalog page.

Cheers,
Markus
Free Windows Admin Tool Kit Click here and download it now
November 18th, 2009 4:15pm

Hello, I was testing with this script today and had a question. It seems in the configuration that I specify the "type" of MA that the run profiles should be selected from but I don't see how to specify the "name" of the MA that should be chosen. In my environment I will have several "Active Directory" MAs so I need to specify the MA name when I launch. is this possible in the power shell script? (sorry if this is a simple question but I'mm new to PS). Thanks.
December 13th, 2009 8:16pm

You're totally right, I selected the management agent according to its type (active directory, FIM, SAP...) but not from its name.
I will check tomorrow how to select a MA by its name and will keep you posted.
Cheers.
Free Windows Admin Tool Kit Click here and download it now
December 13th, 2009 8:26pm

In order to select the management agent by its name instead of by its type:

$params_runProfilesOrder = 
@(
 @{
  name="FIM MA";
  profilesToRun=@("Export";"Delta Import";"Delta Synchronization");
 };
 @{
  name="adds";
  profilesToRun=@("Export";"Delta Import";"Delta Synchronization");
 };
);

and replace the line
if($MA.Type.Equals($MATypeNRun.type)) {

by
if($MA.Name.Equals($MATypeNRun.name)) {

Cheers.
December 14th, 2009 2:57pm

Outstanding. I will test this right away. Thank you very much!
Free Windows Admin Tool Kit Click here and download it now
December 14th, 2009 3:28pm

Something I do in my run scripts is put in a function to retrieve a MA by name, which can be assigned to a variable and then the Execute method can be called on that. If you have a lot of management agents, it can be a bit quicker and more efficient. Here's the one I use:

function GetMA
{
param([string]$maName)
$filter = "Name='" + $maName + "'"
Get-WmiObject -Class MIIS_ManagementAgent -Namespace root/MicrosoftIdentityIntegrationServer -Filter $filter
}



I like your idea of using an array of profile names and iterating over that. I guess the next step would be to use a hashtable with the MA name as the key and the array of profiles to run. Hmmm....., serialize as XML, then you'd have a completely data-driven script that you'd never have to change.... I feel a PowerShell session coming on...

James
December 14th, 2009 3:43pm

I've made a few changes to it so that it e-mails "someone" when things go wrong.
# @author: Fabien Duchene
# @mail: fabien.duchene1 **at** googlemail.com
# @Modified by Peter Lambrechtsen to include sending errors via e-mail 
# including run-history if things go wrong- plambrechtsen at gmail dot com


############
# PARAMETERS
############
$params_ComputerName = "."  # "." is the current computer
$params_delayBetweenExecs = 30 #delay between each execution, in seconds
$params_numOfExecs = 1    #Number of executions 0 for infinite
$params_runProfilesOrder = 
@(
 @{
 name="OracleMA";
 profilesToRun=@("Load");
 };
 @{
 name="Active Directory";
 profilesToRun=@("Export";"Full Synchronization";"Export");
 };
);

##################
# EMAIL PARAMETERS
##################
$emailFrom = "FIM@org.com"
$emailTo = "FIMAlertMailbox@org.com"
$smtpServer = "smtp.org.com"

############
# FUNCTIONS
############
$line = "-----------------------------"
function Write-Output-Banner([string]$msg) {
 Write-Output $line,$msg,$line
}

############
# DATAS
############

$MAs = @(get-wmiobject -class "MIIS_ManagementAgent" -namespace "root\MicrosoftIdentityIntegrationServer" -computername $params_ComputerName)
$numOfExecDone = 0

############
# PROGRAM
############
do {
 Write-Output-Banner("Execution #:"+(++$numOfExecDone))
 foreach($MATypeNRun in $params_runProfilesOrder) {
 $found = $false;
 foreach($MA in $MAS) { 
 
   if(!$found) {
#  if($MA.Type.Equals($MATypeNRun.type)) {
  if($MA.Name.Equals($MATypeNRun.name)) {
  $found=$true;
  Write-Output-Banner("- MA Name: "+$MA.Name,"`n- Type: "+$MA.Type)
#  Write-Output-Banner("MA Type: "+$MA.Type)
  foreach($profileName in $MATypeNRun.profilesToRun) {
   Write-Output (" "+$profileName)," -> starting"
   $datetimeBefore = Get-Date;
   $result = $MA.Execute($profileName);
   $datetimeAfter = Get-Date;
   $duration = $datetimeAfter - $datetimeBefore;
   if("success".Equals($result.ReturnValue)){
   $msg = "done. Duration: "+$duration.Hours+":"+$duration.Minutes+":"+$duration.Seconds
   } else { 
   $msg = "Error: "+$result 
# 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.
   $MA.RunDetails().ReturnValue | Out-File RunHistory.xml
   # Grab the MA run-history and put it into a XML var.
   [xml]$RunHistoryXML = $MA.RunDetails().ReturnValue
   # Build User Errors for Exports
   $RunHistoryXML."run-history"."run-details"."step-details"."synchronization-errors"."export-error" | select dn,"error-type" | export-csv ErrorUsers.csv
   # Build SMTP Message
   $smtp = new-object Net.Mail.SmtpClient($smtpServer)
   $smtpmsg = new-object Net.Mail.MailMessage
   $smtpmsg.From = $emailFrom
   $smtpmsg.To.Add($emailTo)
   $smtpmsg.Subject = "FIM Processing Error: " + $result.ReturnValue
   $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 Error</title></head><body>"
   $smtpbody += "<b>A Forefront Identity Manager</b> error has occured: " + $result.ReturnValue
   $smtpbody += "<br><b>MA Name</b>: " + $MA.Name
   $smtpbody += "<br><b>MA Run Profile</b>: " + $profileName
   $smtpbody += "<br><b>Start date & time</b>: " + $MA.RunStartTime().ReturnValue
   $smtpbody += "<br><b>End date & time</b>: " + $MA.RunEndTime().ReturnValue
   $smtpbody += "<br><b>Total connector space objects</b>: " + $MA.NumCSObjects().ReturnValue
   $smtpbody += "<br><b>Total Connectors</b>: " + $MA.NumTotalConnectors().ReturnValue
   $smtpbody += "<br><b>Connectors</b>: " + $MA.NumConnectors().ReturnValue
   $smtpbody += "<br><b>Explicit Connectors</b>: " + $MA.NumExplicitConnectors().ReturnValue
   $smtpbody += "<br><b>Total Disconnectors</b>: " + $MA.NumTotalDisconnectors().ReturnValue
   $smtpbody += "<br><b>Disconnectors</b>: " + $MA.NumDisconnectors().ReturnValue
   $smtpbody += "<br><b>Explicit Disconnectors</b>: " + $MA.NumExplicitDisconnectors().ReturnValue
   $smtpbody += "<br><b>Filtered Disconnectors</b>: " + $MA.NumFilteredDisconnectors().ReturnValue
   $smtpbody += "<br><b>Total Placeholders</b>: " + $MA.NumPlaceholders().ReturnValue
   $smtpbody += "<br><b>Import Add</b>: " + $MA.NumImportAdd().ReturnValue
   $smtpbody += "<br><b>Import Updates</b>: " + $MA.NumImportUpdate().ReturnValue
   $smtpbody += "<br><b>Import Deletes</b>: " + $MA.NumImportDelete().ReturnValue
   $smtpbody += "<br><b>Import No Change</b>: " + $MA.NumImportNoChange().ReturnValue
   $smtpbody += "<br><b>Export Add</b>: " + $MA.NumExportAdd().ReturnValue
   $smtpbody += "<br><b>Export Updates</b>: " + $MA.NumExportUpdate().ReturnValue
   $smtpbody += "<br><b>Export Deletes</b>: " + $MA.NumExportDelete().ReturnValue
   $smtpbody += "<br><br></body></html>"
#   Write-Output ( $smtpbody )
   $smtpmsg.Body = $smtpbody
   $smtpmsg.IsBodyHTML = $true
   $RHFile = new-object Net.Mail.Attachment([string](get-location)+'\RunHistory.xml')
   $smtpmsg.Attachments.Add($RHFile)
   $EUFile = new-object Net.Mail.Attachment([string](get-location)+'\ErrorUsers.csv')
   $smtpmsg.Attachments.Add($EUFile)
   $smtp.Send($smtpmsg)
   $RHFile.Dispose()
   $EUFile.Dispose()
   }
   Write-Output (" -> "+$msg)
   Write-Output (" -> "+$result.ReturnValue)
  }
  }
   }
 }
 if(!$found) { Write-Output ("Not found MA type :"+$MATypeNRun.type); }
 }
 $continue = ($params_numOfExecs -EQ 0) -OR ($numOfExecDone -lt $params_numOfExecs)
 if($continue) { 
 Write-Output-Banner("Sleeping "+$params_delayBetweenExecs+" seconds")
 Start-Sleep -s $params_delayBetweenExecs
 }
} while($continue)
Free Windows Admin Tool Kit Click here and download it now
May 31st, 2010 7:59am

Hi,

How do i get past this?

PS C:\users\appfimda\desktop> get-wmiobject -class "MIIS_ManagementAgent"
Get-WmiObject : Invalid class
At line:1 char:14
+ get-wmiobject <<<<  -class "MIIS_ManagementAgent"

I'm guessing i need to define some cmdlet or somethin?

September 21st, 2010 6:42am

Hi, first note the correct command is

$MAs = @(get
-wmiobject -class
 "MIIS_ManagementAgent"
 -namespace
 "root\MicrosoftIdentityIntegrationServer" -computername $params_ComputerName)



Then you obviously would need to the wmi class MIIS_ManagementAgent registred. Thus I am assuming installing MIIS synchronization server, formerly named FIM 2010 Sync server would be enough for this class to be registred.

Cheers
Free Windows Admin Tool Kit Click here and download it now
September 21st, 2010 6:47am

I do something similar, and I'm attaching methods to the returned PSObject so that it's simpler to run profiles:

# run a profile and print execution time and result
function RunProfile ($agent,[string] $profileName) {
 $runStart = [System.DateTime]::UtcNow
 Write-Host -noNewLine "$($agent.Name) ${profileName} "
 $res = $agent.Execute($profileName)
 $runTime = [System.DateTime]::UtcNow - $runStart
 if ($res.ReturnValue -eq "success") {
  Write-Host "[$runTime] : $($res.ReturnValue)"
 } else {
  Write-Host -ForegroundColor Yellow "[$runTime] : $($res.ReturnValue)"
 }
}

# get an MA by name and attach functions to run profiles
function ManagementAgent([string] $name) {
 $ma = get-wmiobject -class MIIS_ManagementAgent `
  -namespace root\MicrosoftIdentityIntegrationServer `
  -filter "name='$name'" -ErrorAction SilentlyContinue
 Add-Member -InputObject $ma ScriptMethod FullImport  { RunProfile $this "Full Import" }
 Add-Member -InputObject $ma ScriptMethod FullSynch  { RunProfile $this "Full Synch" }
 Add-Member -InputObject $ma ScriptMethod DeltaImport { RunProfile $this "Delta Import" }
 Add-Member -InputObject $ma ScriptMethod DeltaSynch  { RunProfile $this "Delta Synch" }
 Add-Member -InputObject $ma ScriptMethod Export   { RunProfile $this "Export" }
 Add-Member -InputObject $ma ScriptMethod Run   { 
  if ($args.Length -eq 0) {
   throw "Specify the name of the profile to run."
  }
  RunProfile $this $args[0]
 }
 $ma
}

# get the MA named "AD"
$ad = ManagementAgent "AD"

At this point, to run a profile from the PS shell you just need to type e.g.

$ad.FullImport()

and the best part is that if you hit tab you get auto-completion for the method n

September 21st, 2010 12:12pm

Hi, first note the correct command is

$MAs = @(get

-wmiobject -class

 "MIIS_ManagementAgent"

 -namespace

 "root\MicrosoftIdentityIntegrationServer" -computername $params_ComputerName)



Then you obviously would need to the wmi class MIIS_ManagementAgent registred. Thus I am assuming installing MIIS synchronization server, formerly named FIM 2010 Sync server would be enough for this class to be registred.

Cheers

Registrering the wmi class MIIS_ManagementAgent would be what i'm missing. Apparently it's not enough to install the FIM Sync server. I'll find out how to do that, and post i here, then maybe you could add it to the post?
Free Windows Admin Tool Kit Click here and download it now
September 23rd, 2010 7:22am

very useful info

 

has anyboy managed to find a way to get past the

 

Get-WmiObject : Invalid namespace
At C:\Run Profiles\1-TEST-RUN-PROFILE.ps1:44 char:23

 

error. I'm quiet new in the scripting world and don't really know how to register the wmi class.

Thanks

October 28th, 2010 2:04pm

Hi....Can anyone help me to configure connector filter for MA using powershell script....

Thanks in advance..

 

Vijai Anand.R

Free Windows Admin Tool Kit Click here and download it now
January 5th, 2011 7:42am

Hi Vijai,

that powershell script is only to ordonance management agents.

I am not sure about what you are trying to perform, but I am assuming you would like to run a management agent tasks, and passing it a connector filter, right?

January 5th, 2011 12:04pm

Hello,

i also made some modifications, one is to seperate the configuration into a XML file. also some other modifications.

MyScript goes like this:

 

<#
	.Synopsis
	Starts the FIM 2010 Management Agents in a sequence

	.Description
	Starting FIM 2010 Management Agents in a sequence based on a XML config file
		
	.Example
	FIMRunCycle -configfile config.xml
	Starts the RunCycle based on the specified config file.

	.Parameter configfile
	Specify the name of the XML config file

	.Notes
	NAME: FIMRunCycle
	AUTHOR: Author
	LASTEDIT: 01/06/2011
	KEYWORDS: FIM 2010, Run Cycle, Management Agent

	#Requires -Version 2.0
#>
param([string]$configfile=$(Read-Host -prompt "Configfile"))

### Load Configuration Data ###
[xml]$maconfig=(Get-Content $configfile)
"" > $maconfig.runcycle.logfile

### Functions ###
$line = "---------------------------------------------------------------------------------"
function Write-Output-Banner([string]$msg) {
	Write-Output $line,(" "+$msg),$line
	Write-Output $line,(" "+$msg),$line >> $maconfig.runcycle.logfile
}

function Write-Output-Text([string]$msg) {
	Write-Output $msg
	Write-Output $msg >> $maconfig.runcycle.logfile
}


### 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)
	if($continue) { 
		Write-Output-Banner("Sleeping "+$maconfig.runcycle.cycleWaitSeconds+" seconds")
		Start-Sleep -s $maconfig.runcycle.cycleWaitSeconds
	}
} while($continue)

and the XML config file is like this:

<?xml version="1.0" encoding="utf-8" ?>
<runcycle computerName="." cycleWaitSeconds="15" numOfExecs="1" logFile=".\runcycle.log">
	<MA>	
		<name>HR MA</name>
		<preScript>.\pre.cmd</preScript>
		<profilesToRun>FISO</profilesToRun>
		<profilesToRun>DS</profilesToRun>
		<postScript>.\post.cmd</postScript>
		<waitSeconds>5</waitSeconds>
	</MA>
	<MA>
		<name>FIM MA</name>
		<preScript>.\pre.bat</preScript>
		<profilesToRun>FISO</profilesToRun>
		<profilesToRun>DS</profilesToRun>
		<profilesToRun>E</profilesToRun>
		<profilesToRun>DISO</profilesToRun>
		<postScript>.\post.bat</postScript>
		<waitSeconds>5</waitSeconds>
	</MA>
	<MA>
		<name>AD MA</name>
		<preScript>cscript .\pre.vbs</preScript>
		<profilesToRun>E</profilesToRun>
		<profilesToRun>DISO</profilesToRun>
		<profilesToRun>DS</profilesToRun>
		<postScript>cscript .\post.vbs</postScript>
		<waitSeconds>5</waitSeconds>
	</MA>
</runcycle>

Greets

Peter

 

Free Windows Admin Tool Kit Click here and download it now
January 6th, 2011 10:39am

very useful info

 

has anyboy managed to find a way to get past the

 

Get-WmiObject : Invalid namespace
At C:\Run Profiles\1-TEST-RUN-PROFILE.ps1:44 char:23

 

error. I'm quiet new in the scripting world and don't really know how to register the wmi class.

June 28th, 2011 6:45pm

If you do not need  a lot just run

 

get-wmiobject -namespace "root\MicrosoftIdentityIntegrationServer" -query  "SELECT * FROM MIIS_ManagementAgent WHERE Name LIKE 'AD %'"  -computername "." | ForEach-Object {$_.Execute("FI FS")}
get-wmiobject -class MIIS_ManagementAgent -namespace "root\MicrosoftIdentityIntegrationServer" -filter  "Name='AD 0"  -computername "." | ForEach-Object {$_.Execute("ex di")}
get-wmiobject -class MIIS_ManagementAgent -namespace "root\MicrosoftIdentityIntegrationServer" -filter  "Name='AD 1"  -computername "." | ForEach-Object {$_.Execute("ex di")}
get-wmiobject -class MIIS_ManagementAgent -namespace "root\MicrosoftIdentityIntegrationServer" -filter  "Name='AD 2"  -computername "." | ForEach-Object {$_.Execute("ex di")}
get-wmiobject -class MIIS_ManagementAgent -namespace "root\MicrosoftIdentityIntegrationServer" -filter  "Name='AD 3"  -computername "." | ForEach-Object {$_.Execute("ex di")}
get-wmiobject -class MIIS_ManagementAgent -namespace "root\MicrosoftIdentityIntegrationServer" -filter  "Name='AD 4"  -computername "." | ForEach-Object {$_.Execute("ex di")}
get-wmiobject -class MIIS_ManagementAgent -namespace "root\MicrosoftIdentityIntegrationServer" -filter  "Name='5"  -computername "." | ForEach-Object {$_.Execute("ex di")}

 

Free Windows Admin Tool Kit Click here and download it now
September 17th, 2011 10:31pm

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:&nbsp<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>&nbsp;</td></tr>"
	   							$smtpbody += "<tr><td colspan=2 align=center>&nbsp;</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:&nbsp;<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>&nbsp;</td></tr>"
	   							$smtpbody += "<tr><td colspan=2 align=center>&nbsp;</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:&nbsp;<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:&nbsp;<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>&nbsp;</td></tr>"
							$smtpbody += "<tr><td colspan=2 align=center>&nbsp;</td></tr>"
   							$smtpbody += "<tr><td colspan=2><u><b>" + $MA.Name + " Run Statistics</b></u></td></tr>"
							$smtpbody += "<tr><td colspan=2 align=center>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</td></tr>"
							}
							
							$smtpbody += "<tr><td colspan=2>&nbsp;</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.
May 2nd, 2012 3:21pm

Hi, first note the correct command is

$MAs = @(get

-wmiobject -class

 "MIIS_ManagementAgent"

 -namespace

 "root\MicrosoftIdentityIntegrationServer" -computername $params_ComputerName)



Then you obviously would need to the wmi class MIIS_ManagementAgent registred. Thus I am assuming installing MIIS synchronization server, formerly named FIM 2010 Sync server would be enough for this class to be registred.

Cheers


Registrering the wmi class MIIS_ManagementAgent would be what i'm missing. Apparently it's not enough to install the FIM Sync server. I'll find out how to do that, and post i here, then maybe you could add it to the post?

I found out how to re-register it at:

http://www.apollojack.com/2009/04/cannot-connect-to-mms-wmi-service.html

Free Windows Admin Tool Kit Click here and download it now
May 23rd, 2012 4:21pm

About the Access Denied (0x80070005) issue when running PS script for FIM:

I don't know why exactly, but on a particular FIM Synchronization Server I had similar issues running Powershell script from Task Scheduler.

They ran from under the security context of the FIM (domain) service account.

The .ps1 files were called from a .bat file in Task Scheduler.

Kept running into these 3 events in the Eventlog:

  • Source: MsiInstaller
  • User: NETWORK SERVICE
  • Event ID's: 1004, 1001, 1015

Some product GUID could not find feature 'ILM_Server' with a component GUID for a resource which had a path to the FIM installation folder.
It said it 'did not exist'... I stared at the folders for over an hour to convince myself they were really, really there...

To solve this I had to grant the local NETWORK SERVICE account read access to the FIM installation folder and subfolders.

That solved it. I see similar issues with Sharepoint Profile Sync (which has FIM under the hood), see here.

May 24th, 2012 10:39pm

How to Switch Gal Sync and Lync Sync .dll(s) automatically

Hello, 

Scenario - 2 forests with 2 way trust enabled, Task is to enable GAL Sync and Provision Lync from Central forest to User Forest. 

Solution: - I have installed and configured FIM 2010 R2 in Central Forest, configured two Management agents for GAL Sync and 2 Management Agents for Lync Sync. This is working fine. 

Problem:- In Synchronization Service GUI, I need to switch manually between .dlls (GALsync.dll Lcssync.dll) for GAL Sync and Lync Sync respectively when i need to run a sync. I have automated Management Agents and their run profiles in PowerShell, but am not able to switch the .dll automatically. Is there a way to switch .dll automatically using Powershell\WMI ??

Thanks

Shahid

Shahid.a.shah@gmail.com(Primary Email)

v-2shahs@hotmail.com(secondary Email)


  • Edited by v-2shahs Thursday, September 27, 2012 2:17 PM InCorrect email
Free Windows Admin Tool Kit Click here and download it now
September 27th, 2012 2:17pm

Need Help

Scenario - 2 forests with 2 way trust enabled, Task is to enable GAL Sync and Provision Lync from Central forest to User Forest. 

Solution: - I have installed and configured FIM 2010 R2 in Central Forest, configured two Management agents for GAL Sync and 2 Management Agents for Lync Sync. This is working fine. 

Problem:- In Synchronization Service GUI, I need to switch between .dll (GALsync.dll Lcssync.dll) for GAL Sync and Lync Sync respectively when i need to run a sync. I have automated Management Agents and their run profiles in PowerShell, but am not able to switch the .dll automatically. Is there a way to switch this .dll automatically using Powershell\WMI ??

Thanks

Shahid

Shahid.a.shah@gmail.com(Primary Email)

v-2shahs@hotmail.com(secondary Email)

September 27th, 2012 2:33pm

Need Help

Scenario - 2 forests with 2 way trust enabled, Task is to enable GAL Sync and Provision Lync from Central forest to User Forest. 

Solution: - I have installed and configured FIM 2010 R2 in Central Forest, configured two Management agents for GAL Sync and 2 Management Agents for Lync Sync. This is working fine. 

Problem:- In Synchronization Service GUI, I need to switch between .dll (GALsync.dll Lcssync.dll) for GAL Sync and Lync Sync respectively when i need to run a sync. I have automated Management Agents and their run profiles in PowerShell, but am not able to switch the .dll automatically. Is there a way to switch this .dll automatically using Powershell\WMI ??

Thanks

Shahid

Shahid.a.shah@gmail.com(Primary Email)

v-2shahs@hotmail.com(secondary Email)

Free Windows Admin Tool Kit Click here and download it now
September 27th, 2012 2:34pm

Hi V-2shahs,

I don't think you can automate the change of Dlls. But yes you can do something like writing the code of Gal sync and Lync sync in your own provisioning code and with that single provisioning code you can achieve both.

October 8th, 2012 11:47am

About Get-WmiObject : Access denied

Check the System Event Log. If you are getting Errors from DistributedCOM, then the Problem is that the account under which the scheduled Task is running is not member of the FIMSyncAdmins Group.

Free Windows Admin Tool Kit Click here and download it now
February 7th, 2013 12:58pm

Hellos. I am not so familiar with Powershell. I am wondering about error handling.

If we wish to build a PS script which calls other scripts (including the PSrunMAs script you have produced) and the calling script has the line $ErrorActionPreference = "stop" at the top.

From what I see, the only test for an "error" is the return from $MA.Execute() e.g.

$result = $MA.Execute($profileName);

If $result is not "success" we have a problem. If we have a problem we look at $result rather than $error.

Would it not be better to put that Execute that in a try catch block?

October 21st, 2013 10:25am

Thanks! I was banging my head on the wall for this. Funny thing, the script will run from the command line but not if scheduled.
Free Windows Admin Tool Kit Click here and download it now
August 3rd, 2014 1:57am

Hi

I have been using this script for a while and it works great :) Thanks

But the email Notification har never worked, is there something i have missed?

I can successfully use mail using the ps cmd: send-mailmessage and this will get through. so the smtp server and sender/recipient relay Access should be ok.

I have changed these values: $smtpserver, $emailTo, $emailFrom, $emailPerMA, $emailOnErrorOnly

March 6th, 2015 5:30am

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics