public void Serialize(string file, MARunScheduler c) { System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(c.GetType()); StreamWriter writer = File.CreateText(file); xs.Serialize(writer, c); writer.Flush(); writer.Close(); }
public static MARunScheduler Deserialize(string file) { System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(MARunScheduler)); StreamReader reader = File.OpenText(file); MARunScheduler c = (MARunScheduler)xs.Deserialize(reader); reader.Close(); return(c); }
public static void Main(string[] args) { try { string serverName = System.Environment.MachineName; string configurationFilename = null; foreach (string arg in args.ToList <string>()) { if (arg.StartsWith("/s:", StringComparison.InvariantCultureIgnoreCase)) { serverName = Regex.Replace(arg, @"^/s\:", "", RegexOptions.IgnoreCase).ToUpper(); } if (arg.StartsWith("/f:", StringComparison.InvariantCultureIgnoreCase)) { configurationFilename = Regex.Replace(arg, @"^/f\:", "", RegexOptions.IgnoreCase); } } #region Syntax information if (string.IsNullOrEmpty(configurationFilename)) { Console.WriteLine("Management Agent Run Profile Scheduler"); Console.WriteLine("Copyright (c) 2011-2016 Soren Granfeldt. All rights reserved."); Console.WriteLine(); Console.WriteLine("Description: Uses an XML input file to run management agents in a"); Console.WriteLine("specified sequence. Functionality is based on Microsoft Identity"); Console.WriteLine("Integration Server MASequencer Utility."); Console.WriteLine(); Console.WriteLine("Syntax: MARunScheduler /f:filename"); Console.WriteLine(); Console.WriteLine("Parameters:"); Console.WriteLine(); Console.WriteLine("Value Description"); Console.WriteLine(); Console.WriteLine("/f: filename Specifies the XML input file that contain"); Console.WriteLine(" the configuration details for running the"); Console.WriteLine(" management agents."); Console.WriteLine(); Console.WriteLine("Example:"); Console.WriteLine(); Console.WriteLine("To run MASequencer on the server {0} using the input file", serverName); Console.WriteLine("MARunScheduler.xml, use the following command:"); Console.WriteLine(); Console.WriteLine("MARunScheduler.exe /f:MARunScheduler.xml"); Console.WriteLine(); Console.WriteLine("For more information on parameters, see MARunScheduler.xml."); return; } #endregion configuration = MARunScheduler.Deserialize(Path.GetFullPath(configurationFilename)); Log("Started"); Log(string.Format("Running against server '{0}'", serverName)); ManagementScope WMInamespace; ConnectionOptions connOpt = new ConnectionOptions(); connOpt.Authentication = AuthenticationLevel.PacketPrivacy; WMInamespace = new ManagementScope(String.Format(@"\\{0}\{1}", serverName, FIMWMINamespace), connOpt); Action <object> action = (object runThread) => { RunThread thread = (RunThread)runThread; int repeatCount = thread.RepeatCount - 1; DateTime defaultThreadRunAfter = DateTime.MinValue; DateTime defaultThreadRunBefore = DateTime.MaxValue.AddSeconds(-1); DateTime threadRunBefore; DateTime threadRunAfter; if (!DateTime.TryParse(thread.RunBefore, out threadRunBefore)) { threadRunBefore = defaultThreadRunBefore; } if (!DateTime.TryParse(thread.RunAfter, out threadRunAfter)) { threadRunAfter = defaultThreadRunAfter; } while (thread.LoopIndefinitely || thread.RepeatCount > 0) { LogThread(thread.Name, string.Format("It's now {0}", DateTime.Now.TimeOfDay)); LogThread(thread.Name, string.Format("Thread should run before {0}", threadRunBefore.TimeOfDay)); LogThread(thread.Name, string.Format("Thread should after {0}", threadRunAfter.TimeOfDay)); LogThread(thread.Name, string.Format("Thread should on {0}", string.IsNullOrEmpty(thread.RunOnDays) ? "all days" : thread.RunOnDays)); if (DateTime.Now.TimeOfDay > threadRunAfter.TimeOfDay && DateTime.Now.TimeOfDay < threadRunBefore.TimeOfDay && RunToday(thread.RunOnDays)) { LogThread(thread.Name, string.Format("Starting cycle #{0}", (repeatCount - thread.RepeatCount) + 1)); DateTime defaultItemRunAfter = DateTime.MinValue; DateTime defaultItemRunBefore = DateTime.MaxValue.AddSeconds(-1); foreach (RunItem ri in thread.Item) { DateTime runItemRunBefore; DateTime runItemRunAfter; if (!DateTime.TryParse(ri.RunBefore, out runItemRunBefore)) { runItemRunBefore = defaultItemRunBefore; } if (!DateTime.TryParse(ri.RunAfter, out runItemRunAfter)) { runItemRunAfter = defaultItemRunAfter; } LogThreadMA(thread.Name, ri.MA, string.Format("Run Profile item should run before {0}", runItemRunBefore.TimeOfDay)); LogThreadMA(thread.Name, ri.MA, string.Format("Run Profile item should after {0}", runItemRunAfter.TimeOfDay)); LogThreadMA(thread.Name, ri.MA, string.Format("Run Profile item should on {0}", string.IsNullOrEmpty(ri.RunOnDays) ? "all days" : ri.RunOnDays)); if ((DateTime.Now.TimeOfDay > runItemRunAfter.TimeOfDay && DateTime.Now.TimeOfDay < runItemRunBefore.TimeOfDay && RunToday(ri.RunOnDays))) { #region Pre processing if (!(string.IsNullOrEmpty(ri.Preprocessing))) { ExecuteCommand(thread.Name, ri.Preprocessing, ri.PreprocessingArguments, ""); } #endregion #region Run profile string managementAgentQueryString = String.Format("SELECT * FROM MIIS_ManagementAgent WHERE Name='{0}'", ri.MA); ObjectQuery managementAgentQuery = new ObjectQuery(managementAgentQueryString); ManagementObjectSearcher MASearcher = new ManagementObjectSearcher(WMInamespace, managementAgentQuery); ManagementObjectCollection MAObjects = MASearcher.Get(); string result = "management-agent-not-found"; if (MAObjects.Count == 1) { ManagementObjectCollection.ManagementObjectEnumerator Enum = MAObjects.GetEnumerator(); Enum.MoveNext(); ManagementObject MAObject = (ManagementObject)Enum.Current; LogThreadMA(thread.Name, ri.MA, string.Format("Connected to MA '{0}' (Type: {1}, GUID: {2})", MAObject["name"].ToString(), MAObject["type"].ToString(), MAObject["Guid"].ToString())); List <string> param = new List <string>(); if (!string.IsNullOrEmpty(ri.RunProfile)) { param.Add(ri.RunProfile); } long NumCSObjects = long.Parse((string)MAObject.InvokeMethod("NumCSObjects", null)); LogThreadMA(thread.Name, ri.MA, string.Format("Number of CS object(s): {0:n0}", NumCSObjects)); long NumTotalConnectors = long.Parse((string)MAObject.InvokeMethod("NumTotalConnectors", null)); LogThreadMA(thread.Name, ri.MA, string.Format("Number of connectors: {0:n0}", NumTotalConnectors)); long NumTotalDisconnectors = long.Parse((string)MAObject.InvokeMethod("NumTotalDisconnectors", null)); LogThreadMA(thread.Name, ri.MA, string.Format("Number of disconnectors: {0:n0}", NumTotalDisconnectors)); // pending imports long PendingImportAdds = long.Parse((string)MAObject.InvokeMethod("NumImportAdd", null)); LogThreadMA(thread.Name, ri.MA, string.Format("Pending Import Add(s): {0:n0}", PendingImportAdds)); long PendingImportUpdates = long.Parse((string)MAObject.InvokeMethod("NumImportUpdate", null)); LogThreadMA(thread.Name, ri.MA, string.Format("Pending Import Update(s): {0:n0}", PendingImportUpdates)); long PendingImportDeletes = long.Parse((string)MAObject.InvokeMethod("NumImportDelete", null)); LogThreadMA(thread.Name, ri.MA, string.Format("Pending Import Delete(s): {0:n0}", PendingImportDeletes)); // pending exports long PendingExportAdds = long.Parse((string)MAObject.InvokeMethod("NumExportAdd", null)); LogThreadMA(thread.Name, ri.MA, string.Format("Pending Export Add(s): {0:n0}", PendingExportAdds)); long PendingExportUpdates = long.Parse((string)MAObject.InvokeMethod("NumExportUpdate", null)); LogThreadMA(thread.Name, ri.MA, string.Format("Pending Export Update(s): {0:n0}", PendingExportUpdates)); long PendingExportDeletes = long.Parse((string)MAObject.InvokeMethod("NumExportDelete", null)); LogThreadMA(thread.Name, ri.MA, string.Format("Pending Export Delete(s): {0:n0}", PendingExportDeletes)); bool thresholdsMet = false; if (ri.ThresholdLimits != null) { thresholdsMet = IsThresholdMet("Import Adds", thread.Name, NumTotalConnectors, ri.ThresholdLimits.MaximumPendingImportAdds, PendingImportAdds) || IsThresholdMet("Import Updates", thread.Name, NumTotalConnectors, ri.ThresholdLimits.MaximumPendingImportUpdates, PendingImportUpdates) || IsThresholdMet("Import Deletes", thread.Name, NumTotalConnectors, ri.ThresholdLimits.MaximumPendingImportDeletes, PendingImportDeletes) || IsThresholdMet("Export Adds", thread.Name, NumTotalConnectors, ri.ThresholdLimits.MaximumPendingExportAdds, PendingExportAdds) || IsThresholdMet("Export Updates", thread.Name, NumTotalConnectors, ri.ThresholdLimits.MaximumPendingExportUpdates, PendingExportUpdates) || IsThresholdMet("Export Deletes", thread.Name, NumTotalConnectors, ri.ThresholdLimits.MaximumPendingExportDeletes, PendingExportDeletes); } if (thresholdsMet) { LogThreadMA(thread.Name, ri.MA, "One or more thresholds met. Skipping run profile"); } else { LogThreadMA(thread.Name, ri.MA, string.Format("Only run on pending imports: {0:n0}", ri.OnlyRunIfPendingImports)); LogThreadMA(thread.Name, ri.MA, string.Format("Only run on pending exports: {0:n0}", ri.OnlyRunIfPendingExports)); if (((ri.OnlyRunIfPendingExports && (PendingExportAdds + PendingExportUpdates + PendingExportDeletes) > 0) || !ri.OnlyRunIfPendingExports) && ((ri.OnlyRunIfPendingImports && (PendingImportAdds + PendingImportUpdates + PendingImportDeletes) > 0) || !ri.OnlyRunIfPendingImports)) { LogThreadMA(thread.Name, ri.MA, string.Format("Running: '{0}'", ri.RunProfile)); result = (string)MAObject.InvokeMethod("Execute", param.ToArray()); LogThreadMA(thread.Name, ri.MA, string.Format("Run result: {0}", result)); } else { LogThreadMA(thread.Name, ri.MA, string.Format("There are no pending imports/exports; skipping run")); } } Enum.Dispose(); } else { Log(new Exception("Error connecting to MA"), ERROR_COULDNOTCONNECTOMANAGEMENTAGENT); LogThreadMA(thread.Name, ri.MA, string.Format("Error: Unable to connect to Management Agent '{0}'", ri.MA)); } #endregion #region RunDetails /* * // Check Run For Errors * switch (maResult.ToLower()) { * case "success": * case "completed-no-objects": * case "completed-warnings": * break; * case "completed-export-errors": * throw( new ApplicationException( "The Management Agent '" + maName + * "' reported import errors on execution. " + * "You will need to use the Identity Manager to determine the problem(s)." ) ); * default: * throw( new ApplicationException( "The Management Agent '" + maName + * "' failed on execution. The error returned is '" + maResult + "'" ) ); * } * // Fetch the run details for the ma * object xmlContent = ma.InvokeMethod( "RunDetails", null ); * XmlDocument xmlDoc = new XmlDocument(); * xmlDoc.LoadXml( xmlContent.ToString() ); * // Check Run Stage Count * int runStateCount = 0; * runStateCount += GetNodeCount( xmlDoc, "stage-add" ); * runStateCount += GetNodeCount( xmlDoc, "stage-update" ); * runStateCount += GetNodeCount( xmlDoc, "stage-rename" ); * runStateCount += GetNodeCount( xmlDoc, "stage-delete" ); * runStateCount += GetNodeCount( xmlDoc, "stage-delete-add" ); * // Check Export Count * int exportCount = 0; * exportCount += GetNodeCount( xmlDoc, "export-add" ); * exportCount += GetNodeCount( xmlDoc, "export-update" ); * exportCount += GetNodeCount( xmlDoc, "export-rename" ); * exportCount += GetNodeCount( xmlDoc, "export-delete" ); * exportCount += GetNodeCount( xmlDoc, "export-delete-add" ); * public static int GetNodeCount(XmlDocument xmlDoc, string nodeName) { * int returnCount = 0; * XmlNodeList nodes = xmlDoc.DocumentElement.GetElementsByTagName( nodeName ); * if ((nodes != null) && (nodes.Count > 0)) { * foreach (XmlNode node in nodes) { * if (node.InnerText.Length > 0) { * returnCount += int.Parse( node.InnerText ); * } * } * } * return returnCount; * } * */ #endregion #region Post processing if (!(string.IsNullOrEmpty(ri.Postprocessing))) { if ((result.Equals("success", StringComparison.InvariantCultureIgnoreCase)) || (ri.ContinueOnFailure)) { ExecuteCommand(thread.Name, ri.Postprocessing, ri.PostprocessingArguments, result); } else { Log("Post-processing not run because of run error"); } } #endregion #region Wait minutes if (ri.WaitMinutes > 0) { LogThreadMA(thread.Name, ri.MA, ri.WaitMinutes.ToString("Start: Waiting 0 minute(s)")); Thread.Sleep(ri.WaitMinutes * 60000); LogThreadMA(thread.Name, ri.MA, ri.WaitMinutes.ToString("End: Waiting 0 minute(s)")); } #endregion } else { LogThreadMA(thread.Name, ri.MA, string.Format("Item '{0}' won't run due to day or time restrictions", ri.MA)); } } LogThread(thread.Name, string.Format("Ending cycle #{0}", repeatCount - thread.RepeatCount)); } else { LogThread(thread.Name, string.Format("Thread '{0}' won't run due to day or time restrictions", thread.Name)); } if (thread.WaitMinutes > 0) { LogThread(thread.Name, thread.WaitMinutes.ToString("Start: Thread waiting 0 minute(s)")); Thread.Sleep(thread.WaitMinutes * 60000); LogThread(thread.Name, thread.WaitMinutes.ToString("End: Thread waiting 0 minute(s)")); } thread.RepeatCount--; } }; List <Task> tasks = new List <Task>(); foreach (RunThread thread in configuration.Thread) { tasks.Add(new Task(action, thread)); } foreach (Task t in tasks) { t.Start(); } foreach (Task t in tasks) { t.Wait(); } tasks = null; #region Clearing run histories if (configuration.ClearRunHistory.ClearRuns) { ObjectQuery cleartAgentQuery = new ObjectQuery(string.Format("SELECT * FROM MIIS_Server", serverName)); ManagementObjectSearcher clearRunsMASearcher = new ManagementObjectSearcher(WMInamespace, cleartAgentQuery); ManagementObjectCollection clearRunsMAObjects = clearRunsMASearcher.Get(); if (clearRunsMAObjects.Count == 0) { throw new Exception("Unable to find server: " + serverName); } else { foreach (ManagementObject oReturn in clearRunsMAObjects) { DateTime clearDate = DateTime.Now.AddMinutes(-configuration.ClearRunHistory.AgeInMinutes); Log(string.Format("Clearing runs older than {0}", clearDate.ToLocalTime().ToLocalTime())); object[] methodArgs = { clearDate.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:00") }; string clearRunsResult = (string)oReturn.InvokeMethod("ClearRuns", methodArgs); Log(string.Format("Clear Runs Result: {0}", string.Format("Run result: {0}", clearRunsResult))); if (clearRunsResult.ToString().ToLower() != "success") { throw new Exception("Failed to delete old operation logs: " + clearRunsResult.ToString()); } } } } #endregion Log("Ended"); } catch (FileNotFoundException fileNotFoundException) { string error = string.Format("File Not Found: {0}", fileNotFoundException.FileName); Console.WriteLine(error); Log(new Exception(error), ERROR_CONFIGURATIONFILENOTFOUND); } catch (Exception ex) { string error = string.Format("{0}-{1}", ex.GetType().ToString(), ex.Message); Log(new Exception(error), ERROR_UNSPECIFIEDERROR); } }