Archive

Posts Tagged ‘GetManagementPack’

ssPortal: Revisiting the Custom Monitoring Report Web Service

May 16, 2011 2 comments

Now that the custom CPU, Disk, and Memory thresholds have been implemented, we need to revisit the Custom Monitoring Report, specifically the Web Service methods that interrogate SCOM.

Remember that all custom settings are held in a customer-specific management pack. However, the RSPerf groups that are used to implement the threshold overrides reside in a separate management pack. I suppose, we could have created all of the RSPerf groups in each customer MP, but that would have been a maintenance nightmare. Suppose we want to add or remove a threshold value? We would have to make the change in hundreds, perhaps thousands of management packs. No, thank you.

So, we put the RSPerf groups into their own MP. But that means the GetCustomMonitoring web service method needs to be updated. In addition to getting all the overrides in the customer’s MP, the method now needs to also check the RSPerf MP to see if any of the customer’s servers are members of any of the RSPerf groups.

First, modify the public method to call a private function(GetSSPortalThresholds) that will return the RSPerf data to be included in the report.

GetCustomMonitoring Web Service public method

public XmlDocument GetCustomMonitoring(string DC, int Account)
{
    WebServiceXML ReturnXML = new WebServiceXML();
    try
    {
        ConnectManagementGroup(DC);

        ManagementPackCriteria mpCriteria = new ManagementPackCriteria(“DisplayName like ‘%” + Account + “%'”);
        ReadOnlyCollection<ManagementPack> mpList = mg.GetManagementPacks(mpCriteria);
        if (mpList.Count > 0)
        {
            ManagementPack mp = mpList[0];
            GetOverrides(mg, mp);

            GetSSPortalThresholds(DC, Account);

            ovList.Sort();
        }
                
        BuildTable();
        ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
        ReturnXML.AddData(tblRules.FirstChild.InnerXml);
        CreateCacheDependency(PortalSystem.SCOM, FunctionalArea.CustomReporting,HttpContext.Current.Request.Url.Query);
             
    }
    catch (Exception ex)
    {
        EventLogWriter.LogEvent(ex);
        ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, GenericErrorMsg);
        InvalidateCachePage(PortalSystem.SCOM, FunctionalArea.CustomReporting, HttpContext.Current.Request.Url.Query);
    }
    return ReturnXML.Root;
}//GetCustomMonitoring

This new function(and it’s sub function) use the SCOM extension methods developed earlier to determine group membership – specifically, the MemberOf() method, which returns a dictionary of all the groups(and their guid) that a particular object(server or disk drive) is a member of.

GetSSPortalThresholds private function

        private void GetSSPortalThresholds(string dc, int acct)
        {
            XmlDocument xd = sa.GetAgents(dc, acct, string.Empty); //Get the list of servers for the account
            XmlNode status = xd.SelectSingleNode(“/Response/Status”);
            XmlNodeList serverList = xd.SelectNodes(“/Response/ReturnData/Server”);

            foreach (XmlNode svr in serverList)
            {
                //get ssPortal thresholds for the server object
                PartialMonitoringObject pmoServer = mg.GetPartialMonitoringObject(new Guid(svr.Attributes["guid"].Value));
                GetObjectThresholds(pmoServer);

                //Get the ssPortal thresholds for the logical disk drives on this server
                string critString = “Path like ‘%” + svr.InnerText + “%’ AND FullName Like ‘%LogicalDisk%'”;
                MonitoringObjectGenericCriteria crit = new MonitoringObjectGenericCriteria(critString);
                ReadOnlyCollection<PartialMonitoringObject> driveList = mg.GetPartialMonitoringObjects(crit);

                foreach (PartialMonitoringObject pmoDrive in driveList)
                    GetObjectThresholds(pmoDrive);

            }//foreach
          }//GetssPortalThresholds
        
        private void GetObjectThresholds(PartialMonitoringObject pmo)
        {
            Dictionary<string, string> dctGroups = pmo.MemberOf(); //get the list of groups this object is a member of

            //use LINQ to get just the RSPerf groups
            var ssPortalThresholdList = from grp in dctGroups
                                        where grp.Value.Contains(“RSPerf”)
                                        select grp.Value;

            foreach (var th in ssPortalThresholdList)
            {
                string s = (string)th.Substring(7); //chopp off the “RSPerf.” since has no real meaning to an end user
                SCOMCustomOverride sco = new SCOMCustomOverride();
                sco.Name = “ssPortal Custom Threshold”;
                sco.Type = “RSPerf”;

                // split the RSPerf….. group name into pieces that can be plugged into the SCOMCustomOverride object
                string[] grpSplit = s.Split(‘.’); //split at the ‘.’
                string counter = grpSplit[0]; //counter is before the .
                string thresh = grpSplit[1]; // threshold is after the .

                string[] cntrSplit = counter.Split(‘_’); //further split the counter name at the underscores
                sco.Config = “<Config type=\”RSPerf\”>” + cntrSplit[0] + “</Config>”; //Counter Group is before the first _
                
                // actual counter name is everything after the first _
                // some counter names include _ to further qualify them, such as “PctUtilization_30m” meaning
                // % utilization averaged over a 30 min period. The counter.split() above would put the “30m”
                // into a 3rd string
                // code below puts this 3rd string, if present, into ( ) before sticking it into the SCO object
                sco.Override = cntrSplit.Length == 2 ? cntrSplit[1] : cntrSplit[1] + “(” + cntrSplit[2] + “)”;
                sco.Override += “=” + thresh;
                sco.Override = “<Override>” + sco.Override + “</Override>”;

                sco.Target = pmo.Path == null ? pmo.DisplayName : pmo.Path + “\\” + pmo.DisplayName;
                sco.Target = “” + sco.Target + “”;

                ovList.Add(sco);
            }
        }

ssPortal: Create/Update Custom SCOM Rules with the SDK (Part 1)

March 3, 2011 Leave a comment

The CreateEventRule web service method is very similar to the CreateServiceStateMonitor:

  • connect to the management group based on the DC parameter
  • gets the MP for the Account parameter
  • Creates a disabled Rule
  • Creates the Rule datasource from the passed in parameters
  • Creates the Alert settings, the alert text is set to the same text as the Rule name
  • write the Audit Trail record
  • return the GUID of the newly created Rule

The major difference from the CreateServiceStateMonitor is the way alerts are generated. The SCOM UnitMonitor class has built-in AlertSettings property, which makes it easy to create the alert. For some reason, though, the ManagementPackRule class does not have a similar property. So the alerting for a rule has to be built manually with XML strings.

As with the CreateServiceStateMonitor method there are related public methods to Update, Enable, Disable, and Get Custom Event Rules.

Create/Update Event Rule methods and associated helper functions

   #region Custom Event Rules

        [WebMethod]
        public XmlDocument CreateEventRule( string DC, int Account,
                                            string AlertText, string EventLogName,
                                            string EventIDExpression, string EventSourceExpression,
                                            string EventLevelExpression, string EventDescriptionExpression,
                                            string Ticket,
                                            string UserID)
        {
         
            WebServiceXML ReturnXML = new WebServiceXML();
            try
            {
                string AcctRuleName = string.Empty;
                string AcctAlertName = string.Empty;

                if (AlertText.StartsWith(Account.ToString())) //does the alert text begin with the acct# ??
                {
                    AcctAlertName = AlertText; //yes – do nothing
                }
                else
                {
                    AcctAlertName = Account.ToString() + ” – ” + AlertText; //else add acct# to rule name
                }

                string RuleID = Guid.NewGuid().ToString().Replace(“-“, string.Empty); //generate a guid and strip out the dashes
                string mpRuleName = “WebServiceRule” + RuleID; //generate an internal name

                //connect to the Management Group
                ConnectManagementGroup(DC);

                ManagementPack mp = mg.GetManagementPacks(“rs” + Account.ToString())[0];
                if (mp != null) //if mp is not found, return empty data
                {
                    ManagementPackRule rule = new ManagementPackRule(mp, mpRuleName);
                    rule = new ManagementPackRule(mp, mpRuleName);
                    rule.Target = WinComputerClass;
                    rule.Category = ManagementPackCategoryType.Custom;
                    rule.DisplayName = AcctAlertName; //display name and alert text are the same
                    rule.Description = DateTime.Now.ToShortDateString() + ” – #” + Ticket + ” Rule created by ” + UserID + ” via ssPortal”;
                    
                    rule.Enabled = ManagementPackMonitoringLevel.@false;

                    string xmlCfg = CreateConfigXML(EventLogName, EventIDExpression, EventSourceExpression, EventLevelExpression, EventDescriptionExpression);

                    //Add DataSource module
                    ManagementPackModuleType dsModType;
                    ManagementPackDataSourceModule dsModule;

                    dsModType = mg.GetMonitoringModuleTypes(“Microsoft.Windows.EventProvider”)[0];
                    dsModule = new ManagementPackDataSourceModule(rule, “DS”);
                    dsModule.TypeID = (ManagementPackDataSourceModuleType)dsModType;
                    dsModule.Configuration = xmlCfg;
                    rule.DataSourceCollection.Add(dsModule);

                    //Add Alert Write Action module
                    ManagementPackModuleType alertModuleType = mg.GetMonitoringModuleTypes(“System.Health.GenerateAlert”)[0];
                    ManagementPackWriteActionModule alertModule = new ManagementPackWriteActionModule(rule, “Alert”);
                    alertModule.DisplayName = “Alert”;
                    alertModule.TypeID = (ManagementPackWriteActionModuleType)alertModuleType;
                    StringBuilder sb = new StringBuilder();
                    sb.Append(“<Priority>1</Priority>”);
                    sb.Append(“<Severity>2</Severity>”);
                    sb.Append(“<AlertName>” + AcctAlertName + “</AlertName>”);
                    sb.Append(“<AlertDescription />”);
                    sb.Append(“<AlertOwner />”);

                    string AlertMsgID = CreateStringResource(mp, rule, “Event Description: {0}”);
                    sb.Append(“<AlertMessageId>$MPElement[Name=\"" + AlertMsgID + "\"]$</AlertMessageId>”);
                    
                    sb.Append(“<AlertParameters>”);
                        sb.Append(“<AlertParameter1>$Data/EventDescription$</AlertParameter1>”);
                    sb.Append(“</AlertParameters>”);
                    sb.Append(“<Suppression />”);
                    sb.Append(“<Custom1 />”);
                    sb.Append(“<Custom2 />”);
                    sb.Append(“<Custom3 />”);
                    sb.Append(“<Custom4 />”);
                    sb.Append(“<Custom5 />”);
                    sb.Append(“<Custom6 />”);
                    sb.Append(“<Custom7 />”);
                    sb.Append(“<Custom8 />”);
                    sb.Append(“<Custom9 />”);
                    sb.Append(“<Custom10 />”);
                    alertModule.Configuration = sb.ToString();
                    rule.WriteActionCollection.Add(alertModule);

                    //commit changes to MP
                    mp.Verify();
                    mp.AcceptChanges();
                    
                    ReturnXML.AddData(“<Rule>” + rule.Id + “</Rule>”);
                    // Set variables to pass to Auditing
                    String MethodName = new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name;
                    string oldVal = string.Empty;
                    string NewVal = string.Empty;
                    string NamePath = rule.DisplayName;

                    this.WriteAuditTrail(MethodName, NamePath, oldVal, NewVal, Ticket, UserID, “SCOM”);
                }//if mp not null
    
                //set status
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
            }
            catch (Exception ex)
            {
                EventLogWriter.LogEvent(ex);
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, GenericErrorMsg);
            }

            return ReturnXML.Root;
        }//CreateEventRule

        [WebMethod]
        public XmlDocument UpdateEventRule(string DC, int Account, string RuleGUID,
                                            string AlertText, string EventLogName,
                                            string EventIDExpression, string EventSourceExpression,
                                            string EventLevelExpression, string EventDescriptionExpression,
                                            string Ticket,
                                            string UserID)
        {
            WebServiceXML ReturnXML = new WebServiceXML();
            try
            {
                string AcctRuleName = string.Empty;
                string AcctAlertName = string.Empty;

                if (AlertText.StartsWith(Account.ToString())) //does the alert text begin with the acct# ??
                {
                    AcctAlertName = AlertText; //yes – do nothing
                }
                else
                {
                    AcctAlertName = Account.ToString() + ” – ” + AlertText; //else add acct# to rule name
                }

                string mpRuleName = “WebServiceRule” + RuleGUID;

                //connect to the Management Group
                ConnectManagementGroup(DC);

                ManagementPack mp = mg.GetManagementPacks(“rs” + Account.ToString())[0];
                ManagementPackRule rule = mg.GetMonitoringRule(new Guid(RuleGUID));
                rule.Description += “\r\n” + DateTime.Now.ToShortDateString() + ” – #” + Ticket + ” Rule updated by ” + UserID + ” via ssPortal”;
                rule.DisplayName = AcctAlertName;

                string xmlCfg = CreateConfigXML(EventLogName, EventIDExpression, EventSourceExpression, EventLevelExpression, EventDescriptionExpression);

                rule.DataSourceCollection[0].Configuration = xmlCfg;

                //update Alert Write Action module
                ManagementPackModuleType alertModuleType = mg.GetMonitoringModuleTypes(“System.Health.GenerateAlert”)[0];
                ManagementPackWriteActionModule alertModule = new ManagementPackWriteActionModule(rule, “Alert”);
                alertModule.DisplayName = “Alert”;
                alertModule.TypeID = (ManagementPackWriteActionModuleType)alertModuleType;
                StringBuilder sb = new StringBuilder();
                sb.Append(“<Priority>1</Priority>”);
                sb.Append(“<Severity>2</Severity>”);
                sb.Append(“<AlertName>” + AcctAlertName + “</AlertName>”);

                string AlertMsgID = CreateStringResource(mp, rule, “Event Description: {0}”);
                sb.Append(“<AlertMessageId>$MPElement[Name=" + AlertMsgID + "]$</AlertMessageId>”);

                sb.Append(“<AlertOwner />”);
                sb.Append(“<AlertMessageId />”);
                sb.Append(“<AlertParameters>”);
                sb.Append(“<AlertParameter1>$Data/EventDescription$</AlertParameter1>”);
                sb.Append(“</AlertParameters>”);
                sb.Append(“<Suppression />”);
                sb.Append(“<Custom1 />”);
                sb.Append(“<Custom2 />”);
                sb.Append(“<Custom3 />”);
                sb.Append(“<Custom4 />”);
                sb.Append(“<Custom5 />”);
                sb.Append(“<Custom6 />”);
                sb.Append(“<Custom7 />”);
                sb.Append(“<Custom8 />”);
                sb.Append(“<Custom9 />”);
                sb.Append(“<Custom10 />”);

                alertModule.Configuration = sb.ToString();

                rule.WriteActionCollection.Clear(); //erase old module
                rule.WriteActionCollection.Add(alertModule); //rewrite the new one

                rule.Status = ManagementPackElementStatus.PendingUpdate;

                //commit changes to MP
                mp.Verify();
                mp.AcceptChanges();

                ReturnXML.AddData(“<Rule>” + rule.Id + “</Rule>”);

                // Set variables to pass to Auditing
                String MethodName = new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name;
                string oldVal = string.Empty;
                string NewVal = string.Empty;
                string NamePath = rule.DisplayName;

                this.WriteAuditTrail(MethodName, NamePath, oldVal, NewVal, Ticket, UserID, “SCOM”);

                //set status
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
            }
            catch (Exception ex)
            {
                EventLogWriter.LogEvent(ex);
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, GenericErrorMsg);
            }

            return ReturnXML.Root;
        }//UpdateEventRule

        private string CreateStringResource(ManagementPack mp, ManagementPackRule r, string AlertText)
        {
            ManagementPackStringResource msr = new ManagementPackStringResource(mp, r.Name + “.AlertMessage”);
            msr.DisplayName = r.DisplayName;
            msr.Description = AlertText;
            return msr.Name;
        }
        private string CreateConfigXML(string EvtLog, string EventIDExpr, string EventSourceExpr,
                                       string EventLevelExpr, string EventDescriptionExpr)
        {
            StringBuilder xmlString = new StringBuilder();

            xmlString.Append(@”<ComputerName>$Target/Property[Type=""Windows!Microsoft.Windows.Computer""]/NetworkName$</ComputerName>”);
            xmlString.Append(“<LogName>” + EvtLog + “</LogName>”);
            int expStart = xmlString.Length;
            int expCount = 0;
            if (EventIDExpr != string.Empty)
            {
                xmlString.Append(CreateExpressionTree(“UnsignedInteger”, “EventDisplayNumber”, EventIDExpr));
                expCount++;
            }
            if (EventSourceExpr != string.Empty)
            {
                xmlString.Append(CreateExpressionTree(“String”, “PublisherName”, EventSourceExpr));
                expCount++;
            }
            if (EventLevelExpr != string.Empty)
            {
                xmlString.Append(CreateExpressionTree(“Integer”, “EventLevel”, EventLevelExpr));
                expCount++;
            }
            if (EventDescriptionExpr != string.Empty)
            {
                xmlString.Append(CreateExpressionTree(“String”, “EventDescription”, EventDescriptionExpr));
                expCount++;
            }

            if (expCount == 0)
            {
                xmlString.Append(“<Expression />”);
            }
            else
            {
                if (expCount > 1) //if more than 1 expression, wrap the expressions inside an <AND> expression
                {
                    xmlString.Insert(expStart, “<Expression><And>”);
                    xmlString.Append(“</And></Expression>”);
                }
            }

            
            return xmlString.ToString();
        }

        private string CreateExpressionTree(string vType, string vName, string expr)
        {
            string LeftOp = @”<XPathQuery Type=””” + vType + @”””>” + vName + “</XPathQuery>”;
            string Op = expr.Substring(0, expr.IndexOf(” “));
            string RightOp = expr.Substring(expr.IndexOf(” “)+1);
            StringBuilder sb = new StringBuilder();

            switch (Op)
            {
                case “Equal”:
                case “NotEqual”:
                case “Greater”:
                case “GreaterEqual”:
                case “Less”:
                case “LessEqual”:
                                sb.Append(“<Expression><SimpleExpression>”);
                                sb.Append(“<ValueExpression>” + LeftOp + “</ValueExpression>”);
                                    sb.Append(“<Operator>” + Op + “</Operator>”);
                                sb.Append(“<ValueExpression>”);
                                    sb.Append(@”<Value Type=””” + vType + @”””>” + RightOp + “</Value>”);
                                sb.Append(“</ValueExpression></SimpleExpression></Expression>”);
                                break;

                case “ContainsSubstring”:
                case “DoesNotContainSubstring”:
                case “MatchesWildcard”:
                case “DoesNotMatchWildcard”:
                                sb.Append(“<Expression><RegExExpression>”);
                                sb.Append(“<ValueExpression>” + LeftOp + “</ValueExpression>”);
                                sb.Append(“<Operator>” + Op + “</Operator>”);
                                sb.Append(@”<Pattern>” + RightOp + “</Pattern>”);
                                sb.Append(“</RegExExpression></Expression>”);
                                break;

                default:
                                sb.Append(“Invalid operator: <” + Op + “>”);
                                break;
            }//switch

            return sb.ToString();
        }//CreateExpressionTree

        [WebMethod]
        public XmlDocument EnableRule(string DC, string RuleGUID, string ServerGUID, string Ticket, string UserID)
        {
            WebServiceXML ReturnXML = new WebServiceXML();
            List<string> pNodes = new List<string>();

            try
            {
                ConnectManagementGroup(DC);
                MonitoringObject objServer = mg.GetMonitoringObject(new Guid(ServerGUID));
                ManagementPackRule rule = mg.GetMonitoringRule(new Guid(RuleGUID));
                ManagementPack mp = rule.GetManagementPack();

                MonitoringObjectGenericCriteria moCriteria;

                moCriteria = new MonitoringObjectGenericCriteria(“DisplayName like ‘%” + objServer.DisplayName + “%'”);
                MonitoringObject WinComputerObject = mg.GetMonitoringObjects(moCriteria, WinComputerClass)[0];
                EnableOverride(mg, rule, WinComputerObject.Id, Ticket, UserID);

                mp.Verify();
                mp.AcceptChanges();

                // Set variables to pass to Auditing
                String MethodName = new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name;
                string oldVal = string.Empty;
                string NewVal = objServer.DisplayName;
                string NamePath = rule.DisplayName;

                this.WriteAuditTrail(MethodName, NamePath, oldVal, NewVal, Ticket, UserID, “SCOM”);

                //set status
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
            }
            catch (Exception ex)
            {
                EventLogWriter.LogEvent(ex);
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, ex.Message);
            }
            return ReturnXML.Root;

        }//EnableRule

        private void EnableOverride(ManagementGroup mg, ManagementPackRule rule, Guid svrGUID, string ticket, string user)
        {
            ManagementPack mp = rule.GetManagementPack();
            string OverrideName = “OverrideForRule” + rule.Name + svrGUID.ToString().Replace(“-“,string.Empty);

            ManagementPackRulePropertyOverride ov = new ManagementPackRulePropertyOverride(mp, OverrideName);
            ov.DisplayName = “Override for Rule: ” + rule.DisplayName;
            ov.Rule = rule;
            ov.Description += “\r\n” + DateTime.Now.ToShortDateString() + ” – #” + ticket + ” Enabled by ” + user + ” via ssPortal”;
            ov.Property = ManagementPackWorkflowProperty.Enabled;
            ov.Value = “true”;
            ov.Context =WinComputerClass;
            ov.ContextInstance = svrGUID;
        }//EnableRule

        [WebMethod]
        public XmlDocument DisableRule(string DC, string RuleGuid, string ServerGUID,string Ticket, string UserID)
        {
            WebServiceXML ReturnXML = new WebServiceXML();

            try
            {
                ConnectManagementGroup(DC);

                ManagementPackRulePropertyOverride ov;
                ManagementPackRule rule = mg.GetMonitoringRule(new Guid(RuleGuid));
                ManagementPack mp = rule.GetManagementPack();
                MonitoringObject objServer = mg.GetMonitoringObject(new Guid(ServerGUID));
                MonitoringObjectGenericCriteria monCriteria;

                string crit = “DisplayName like ‘%” + objServer.DisplayName + “%’ “;
                monCriteria = new MonitoringObjectGenericCriteria(crit);
                ReadOnlyCollection<MonitoringObject> WinComputerObjects = mg.GetMonitoringObjects(monCriteria, WinComputerClass);

                crit = “TargetId = ‘” + RuleGuid + “‘ AND ContextObjectId = ‘” + WinComputerObjects[0].Id.ToString() + “‘ “;
                MonitoringOverrideCriteria moCriteria = new MonitoringOverrideCriteria(crit);
                ReadOnlyCollection<ManagementPackOverride> RuleOverrides = mg.GetMonitoringOverrides(moCriteria);
                
                foreach (ManagementPackRuleOverride ruleOverride in RuleOverrides)
                {
                    if (ruleOverride is ManagementPackRulePropertyOverride)
                    {
                        ov = (ManagementPackRulePropertyOverride)ruleOverride;
                        ov.Value = “false”;
                        ov.Description += “\r\n” + DateTime.Now.ToShortDateString() + ” – #” + Ticket + ” Disabled by ” + UserID + ” via ssPortal”;
                        ov.Status = ManagementPackElementStatus.PendingUpdate;
                    }
                }

                mp.Verify();
                mp.AcceptChanges();

                // Set variables to pass to Auditing
                String MethodName = new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name;
                string oldVal = objServer.DisplayName;
                string NewVal = string.Empty;
                string NamePath = rule.DisplayName;

                this.WriteAuditTrail(MethodName, NamePath, oldVal, NewVal, Ticket, UserID, “SCOM”);

                //set status
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
            }
            catch (Exception ex)
            {
                EventLogWriter.LogEvent(ex);
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, ex.Message);
            }
            return ReturnXML.Root;

        }//DisableRule

        [WebMethod(cacheDuration=600]
        public XmlDocument GetEventRules(string DC, int Account)
        {
            WebServiceXML ReturnXML = new WebServiceXML();
            try
            {
                ConnectManagementGroup(DC);
                ManagementPack mp = mg.GetManagementPacks(“rs” + Account.ToString())[0];
                GetRuleOverrides(mg, mp); //load rule overrides into list for faster lookups
                if (mp != null)
                {
                    ManagementPackElementCollection<ManagementPackRule> Rules = mp.GetRules();
                    StringBuilder sbXML = new StringBuilder();
                    foreach (ManagementPackRule rule in Rules)
                    {
                        if (rule.Name.Contains(“WebServiceRule”)) //only interested in custom rules created by the WebService
                        {
                            sbXML.Append(@”<Rule guid=””” + rule.Id + @”””>”);
                            sbXML.Append(“<AlertText>” + rule.DisplayName + “</AlertText>”);
                            sbXML.Append(“<Criteria>”);
                            sbXML.Append(rule.DataSourceCollection[0].Configuration);
                            sbXML.Append(“</Criteria>”);
                            sbXML.Append(“<Overrides>”);
                            sbXML.Append(GetOverridesForRule(rule.Id));
                            sbXML.Append(“</Overrides>”);
                            sbXML.Append(“</Rule>”);
                        }
                    }
                    //set status
                    ReturnXML.AddData(sbXML.ToString());
                }//if mp is not null
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
             }
            catch (Microsoft.EnterpriseManagement.Common.ObjectNotFoundException onf)
            {
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, “Custom Management Pack for account ” + Account.ToString() + ” was not found. Create a custom MP, then try this page again”);
            }
            catch (Exception ex)
            {
                EventLogWriter.LogEvent(ex);
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, ex.Message);
            }
            return ReturnXML.Root;

        }//EnableRule

        private void GetRuleOverrides(ManagementGroup mg, ManagementPack mp)
        {
            ManagementPackElementCollection<ManagementPackOverride> overrides = mp.GetOverrides();
            foreach (ManagementPackOverride mpOverride in overrides)
            {
                if (mpOverride is ManagementPackRulePropertyOverride)
                {
                    ManagementPackRulePropertyOverride ruleOV = (ManagementPackRulePropertyOverride)mpOverride;
                    if (ruleOV.Property == ManagementPackWorkflowProperty.Enabled)
                        lstRuleOverrides.Add(ruleOV);
                }
            }
        }
  
        private string GetOverridesForRule(Guid ruleID)
        {
            MonitoringObject svrObj;
            StringBuilder sbOV = new StringBuilder();
            List<string> serverList = new List<string>();

            var res = from o in lstRuleOverrides
                      where o.Rule.Id == ruleID
                      select o;

            foreach(var ov in res)
            {
                ManagementPackRulePropertyOverride ruleOV = (ManagementPackRulePropertyOverride)ov;
                svrObj = mg.GetMonitoringObject((Guid)ruleOV.ContextInstance);

                if (!serverList.Contains(svrObj.DisplayName))
                {
                    MonitoringObjectGenericCriteria moCriteria = new MonitoringObjectGenericCriteria(“DisplayName like ‘%” + svrObj.DisplayName + “%'”);
                    ReadOnlyCollection<MonitoringObject> objList = mg.GetMonitoringObjects(moCriteria,WinComputerClass);

                    if (objList.Count > 0)
                    {
                        sbOV.Append(“<Override id=\”” + ruleOV.Id.ToString() + “\”>”);
                        sbOV.Append(“<Server enabled=\”” + ruleOV.Value + “\” id=\”” + objList[0].Id.ToString() + “\”>” + svrObj.DisplayName + “</Server>”);
                        sbOV.Append(“</Override>”);
                        serverList.Add(svrObj.DisplayName);
                    }
                }
            }//foreach

            return sbOV.ToString();
        }
#endregion

ssPortal: Create/Update a Service State Monitor(Part 2)

March 1, 2011 Leave a comment

After entering the usual DC and Account number parameters, the Service State Monitors page displays a list of Monitored Services. This is a list of service Display Names that have custom service state monitors defined for them. Clicking on a service displays the details of the monitor: the actual service name, the display name and a list of computers that have enable overrides defined.

Clicking the New Monitor button displays an empty form to create a new monitor. The Service Name is the shortname of the service(as found in the registry under HKLM\SYSTEM\CurrentControlSet\Services). The Display Name, for simplicity, should match the service Display Name, although it doesn’t have to. The text in the Display Name is used to build the alert text, which is “<Display Name> service is not running”. In the sample screen shot below, I could have entered “SCOM Agent” in the Display Name and the monitor would alert with the text “SCOM Agent service is not running”.

The Monitor is created in a disabled state. Adding a server to a monitor is just creating an enable override. Removing a server from a monitor sets the override’s enabled property to false, since the SDK does not have any methods to delete anything.

Service State Monitors

ServiceMonitor.aspx

<%@ Page Title=”” Language=”C#” MasterPageFile=”~/Site.Master” AutoEventWireup=”true”
    CodeBehind=”ServiceMonitor.aspx.cs” Inherits=”SSPortal.SCOM.ServiceMonitor” %>

<%@ Register Assembly=”AjaxControlToolkit” Namespace=”AjaxControlToolkit” TagPrefix=”asp” %>
<asp:Content ID=”Content1″ ContentPlaceHolderID=”PageContents” runat=”server”>
    <asp:XmlDataSource runat=”server” ID=”xmlSCOM” DataFile=”~/App_Data/SCOMRMS.xml” />
    <asp:ToolkitScriptManager ID=”ToolkitScriptManager1″ runat=”server” />
    <h3>
        Service State Monitors</h3>
    <asp:UpdatePanel ID=”UpdatePanel” runat=”server” UpdateMode=”Conditional” RenderMode=”Inline”>
        <ContentTemplate>
            <div id=”inDiv”>
                DC:
                <asp:DropDownList ID=”ddlDC” runat=”server” DataSourceID=”xmlSCOM” DataTextField=”dc”
                    DataValueField=”dc” ToolTip=”The Data Center where the Account is housed. The DC is used to determine which SCOM server to connect to.” />
                Account:
                <asp:TextBox ID=”txtAccount” runat=”server” Width=”50px” ToolTip=”The account number you want to create/modify service monitors for” />
                <asp:Button ID=”Button1″ runat=”server” Text=”Submit” OnClick=”Button1_Click” />
                <asp:UpdateProgress ID=”UpdateProgressPanel” AssociatedUpdatePanelID=”UpdatePanel”
                    runat=”server” DynamicLayout=”false”>
                    <ProgressTemplate>
                        <asp:Image ID=”LoadingSpinner” runat=”server” ImageUrl=”~/images/loading.gif” Height=”24px”
                            Width=”24px” ImageAlign=”Top” />
                    </ProgressTemplate>
                </asp:UpdateProgress>
            </div>
            <asp:Label ID=”lblErrMsg” runat=”server” ForeColor=”Red”> </asp:Label>
            <asp:CompareValidator ID=”CompareValidator1″ runat=”server” ErrorMessage=”Select a DC from the list<br/>”
                ControlToValidate=”ddlDC” ValueToCompare=’Select a DC…’ Display=”Dynamic” Operator=”NotEqual”></asp:CompareValidator>
            <asp:RequiredFieldValidator ID=”RequiredFieldValidator1″ runat=”server” ErrorMessage=”Account Number is required<br/>”
                ControlToValidate=”txtAccount” Display=”Dynamic”></asp:RequiredFieldValidator>
            <asp:RangeValidator ID=”RangeValidator1″ runat=”server” ErrorMessage=”Invalid data in Account number<br/>”
                ControlToValidate=”txtAccount” Type=”Integer” MinimumValue=”000000″ MaximumValue=”999999″
                Display=”Dynamic”></asp:RangeValidator>
            <hr />
            <asp:Label runat=”server” ID=”lblNote” Visible=”false”>
                <em>
                    The default SCOM monitoring will alert if the Windows Service Control Manager reports that a service terminates "unexpectedly".<br />
                    If someone stops the service in the Services console(or with the NET STOP command), the alert will not be generated.<br />
                    <br />
                    If you want an alert any time the service is not in a RUNNING state for any reason, incuding manual stops, then create a custom Service State Monitor for the service.<br />
                    NOTE: Only services that have a Start type of <b>Automatic</b> are monitored by the Service State Monitor
                </em>
            </asp:Label>
            <asp:Table runat=”server” ID=”tblMonitors” Width=”1020px” Visible=”false” CellPadding=”0″
                CellSpacing=”0″>
                <asp:TableRow>
                    <asp:TableCell VerticalAlign=”Top” HorizontalAlign=”left” Width=”310px”>
                        <div style=”vertical-align: top; height: 350px; overflow: auto; width: 300px;”>
                            <b>Monitored Services</b><br />
                            <asp:ListBox ID=”lstMonitors” runat=”server” Width=”280px” AutoPostBack=”true” OnSelectedIndexChanged=”lstMonitors_SelectedIndexChanged” Rows=”19″ ToolTip=”This is the list of the Services that have monitors defined for them. Click on the service name to see the monitor details.”></asp:ListBox>
                        </div>
                        <asp:Button runat=”server” ID=”Button2″ OnClick=”btnNewMonitor_Click” Text=”New Monitor” />
                    </asp:TableCell>
                    <asp:TableCell VerticalAlign=”Top” HorizontalAlign=”Center” Width=”710px”>
                        <br />
                        <asp:Table runat=”server” ID=”tblDetails” BorderWidth=”1″ BorderStyle=”Solid” Visible=”false”
                            CssClass=”TblRowOdd”>
                            <asp:TableRow>
                                <asp:TableCell Width=”500px”>
                                    <asp:Label runat=”server” ID=”lblMonitorID” Width=”435px”></asp:Label></asp:TableCell>
                                <asp:TableCell Width=”210px”> </asp:TableCell>
                            </asp:TableRow>
                            <asp:TableRow>
                                <asp:TableCell>
                                    <asp:Table runat=”server” ID=”tblMonitorCriteria” Width=”500px” BorderStyle=”Solid”
                                        BorderWidth=”1″>
                                        <asp:TableRow>
                                            <asp:TableCell Width=”130px”>Service Name</asp:TableCell>
                                            <asp:TableCell Width=”180px”>
                                                <asp:TextBox runat=”server” ID=”txtServiceName” OnTextChanged=”Form_DataChanged”
                                                    Width=”180px” ToolTip=”This is the ‘internal’ name of the service; not the display name that you see in the Services console. Only services that have a start type of AUTOMATIC will be monitored.”></asp:TextBox></asp:TableCell>
                                            <asp:TableCell Width=”200px”> </asp:TableCell>
                                        </asp:TableRow>
                                        <asp:TableRow>
                                            <asp:TableCell Width=”130px”>Display Name</asp:TableCell>
                                            <asp:TableCell Width=”180px”>
                                                <asp:TextBox runat=”server” ID=”txtDisplayName” OnTextChanged=”Form_DataChanged”
                                                    Width=”180px” ToolTip=”This is a user-friendly name for the service. When this monitor triggers an alert, the alert text will be ‘<Display Name> service is not running’. It does not neccessarily have to match what is displayed in the Services console, but to keep things consistent it probably should match.”></asp:TextBox></asp:TableCell>
                                            <asp:TableCell Width=”200px”> </asp:TableCell>
                                        </asp:TableRow>
                                        <asp:TableRow>
                                            <asp:TableCell> </asp:TableCell>
                                            <asp:TableCell> </asp:TableCell>
                                            <asp:TableCell> </asp:TableCell>
                                        </asp:TableRow>
                                        <asp:TableRow>
                                            <asp:TableCell ColumnSpan=”3″>Apply to these servers:</asp:TableCell>
                                        </asp:TableRow>
                                        <asp:TableRow>
                                            <asp:TableCell> </asp:TableCell>
                                            <asp:TableCell ColumnSpan=”2″>
                                                <asp:ListBox runat=”server” ID=”lstMonitorServers” Width=”380px” Rows=”10″ SelectionMode=”Multiple”
                                                    ToolTip=”This is the list of servers that the service monitor will be applied to.”>
                                                </asp:ListBox>
                                                <br />
                                                <br />
                                                <asp:Button ID=”btnRemoveServer” runat=”server” OnClick=”btnRemoveServer_Click” Text=”Remove server from rule” />
                                            </asp:TableCell>
                                        </asp:TableRow>
                                    </asp:Table>
                                </asp:TableCell>
                                <asp:TableCell VerticalAlign=”Top”>
                                    Available Servers
                                    <asp:ListBox runat=”server” ID=”lstAllServers” Rows=”10″ Width=”210px” SelectionMode=”Multiple”
                                        ToolTip=”This is the list of all servers in the account that are running the SCOM agent. If a server does not appear in this list and it is running the SCOM agent, check that the HKLM\Software\Rackspace Registry key exists and that the CustomerNumber value is populated with the correct account number. Select one or more servers and click the <–Add Server(s) button below to add the server(s) to the list of servers the rule is applied to.”>
                                    </asp:ListBox>
                                    <asp:Button ID=”btnAddServer” runat=”server” Text=”<– Add server(s)” OnClick=”btnAddServer_Click” />
                                </asp:TableCell>
                            </asp:TableRow>
                            <asp:TableRow>
                                <asp:TableCell>
                                    Ticket# <asp:TextBox ID=”txtTicket” runat=”server” Width=”12em”></asp:TextBox>(required for committing changes)</asp:TableCell>
                            </asp:TableRow>
                        </asp:Table>
                        <asp:TableCell>
                            <asp:Button ID=”btnCommit” runat=”server” Text=”Commit Changes” OnClientClick=”validate()”
                                OnClick=”btnCommit_Click” />
                            <asp:Button ID=”btnReset” runat=”server” Text=”Reset” OnClick=”lstMonitors_SelectedIndexChanged” />
                        </asp:TableCell>
                    </asp:TableCell>
                </asp:TableRow>
            </asp:Table>
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

ServiceMonitor.aspx.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using LogWriter;
using ListBoxSorter;
using ssPortalWebClient;

namespace SSPortal.SCOM
{
    public partial class ServiceMonitor : System.Web.UI.Page
    {
        protected DataTable dtMonitors = new DataTable();
        protected DataTable dtMonitorservers = new DataTable();
        protected DataTable dtMonitorServersCurrent = new DataTable();
        protected DataTable dtMonitorserversOriginal = new DataTable();
        protected DataTable dtAllServers = new DataTable();
        protected string UserName;
        protected bool DataChanged = false;
        protected bool ServerListChanged = false;

        //Event Handlers
        #region Event Handlers
        protected void Page_Load(object sender, EventArgs e)
        {
#if __PRODUCTION__
            NetworkCredential creds = (NetworkCredential)Session["Credentials"];
            UserName = creds.UserName;
#else
            UserName = “Test.User”;
#endif
            if (!IsPostBack)
            {
                ddlDC.Focus();
                lblErrMsg.Text = string.Empty;
                lblNote.Visible = true;
            }
            Page.Form.DefaultButton = Button1.UniqueID;
            if (Session["DataChanged"] != null) DataChanged = (bool)Session["DataChanged"];
            if (Session["ServerListChanged"] != null) ServerListChanged = (bool)Session["ServerListChanged"];
        }
        protected void Button1_Click(object sender, EventArgs e)
        {
            lblErrMsg.Text = string.Empty;
            lblNote.Visible = false;
            tblMonitors.Visible = false;
            tblDetails.Visible = false;
            btnCommit.Visible = false;
            btnReset.Visible = false;
            dtMonitors.Clear();
            dtMonitorservers.Clear();
            lstMonitors.Items.Clear();
           try
            {
                LoadData(); //load web service data into datatables
                if (lstMonitors.Items.Count == 0)
                    lstMonitors.Visible = false;
                else
                    lstMonitors.Visible = true;
              
            }//try
            catch (Exception ex)
            {
                lblErrMsg.Text = EventLogWriter.GenericErrorMsg;
                EventLogWriter.LogEvent(ex);
            }
        }//Button1_click
        protected void lstMonitors_SelectedIndexChanged(object sender, EventArgs e)
        {
            lblErrMsg.Text = string.Empty;
            dtMonitors = (DataTable)Session["dtMonitors"];
            DataRow dr = dtMonitors.Select(“MonitorGuid='” + lstMonitors.SelectedValue + “‘”)[0];

            lblMonitorID.Text = “ID: ” + dr["MonitorGuid"].ToString();
            txtServiceName.Text = dr["ServiceName"].ToString();
            txtDisplayName.Text = dr["DisplayName"].ToString();
            txtTicket.Text = string.Empty;

            dtMonitorservers = (DataTable)Session["MonitorServersTable"];

            DataView dv = new DataView(dtMonitorservers, “MonitorGuid='” + lstMonitors.SelectedValue + “‘”, “ServerName”, DataViewRowState.CurrentRows);

            dtMonitorServersCurrent = dv.ToTable();
            dtMonitorserversOriginal = dv.ToTable();

            SavetoSession(“CurrentMonitorServers”, dtMonitorServersCurrent);
            SavetoSession(“OriginalMonitorServers”, dtMonitorserversOriginal);

            lstMonitorServers.DataSource = dtMonitorServersCurrent.DefaultView;
            lstMonitorServers.DataTextField = “ServerName”;
            lstMonitorServers.DataValueField = “ServerGuid”;
            lstMonitorServers.DataBind();
            if (lstMonitorServers.Items.Count == 0)
            {
                btnRemoveServer.Enabled = false; //so user doesn’t try to remove something that is not there
            }
            else
            {
                btnRemoveServer.Enabled = true;
            }

            btnCommit.Text = “Commit Monitor Changes”;
            btnCommit.Visible = true;
            btnReset.Visible = true;
            tblDetails.Visible = true;
        }
        protected void btnNewMonitor_Click(object sender, EventArgs e)
        {
            lblErrMsg.Text = string.Empty;
            InitDetailForm(); //clear all the fields
            
            dtMonitorServersCurrent = (DataTable)Session["CurrentMonitorServers"];
            if (dtMonitorServersCurrent != null)
                dtMonitorServersCurrent.Clear();

            dtMonitorserversOriginal = (DataTable)Session["OriginalMonitorServers"];
            if (dtMonitorserversOriginal != null)
                dtMonitorserversOriginal.Clear();
        }
        protected void btnCommit_Click(object sender, EventArgs e)
        {
            try
            {
                lblErrMsg.Text = string.Empty;
                string monitorID = string.Empty;

                if (ValidData())
                {
                    dtMonitors = (DataTable)Session["dtMonitors"];
                    if (btnCommit.Text == “Commit New Monitor”) //are we adding a new monitor?
                    {
                        if (DataChanged)
                        {
                            monitorID = AddUpdateMonitor(“Create”);
                            btnCommit.Text = “Commit Monitor Changes”;
                            dtMonitors.Rows.Add(monitorID, txtServiceName.Text, txtDisplayName.Text);
                            dtMonitors.AcceptChanges();
                            if ((monitorID != string.Empty) && (ServerListChanged))
                                ApplyServersToMonitor(monitorID);

                            AddToARIC();
                        }
                    }
                    else //updating an existing monitor
                    {
                        if (DataChanged)
                        {
                            monitorID = AddUpdateMonitor(“Update”);
                            DataRow[] rows = dtMonitors.Select(“MonitorGuid='” + monitorID +”‘”);
                            rows[0]["ServiceName"] = txtServiceName.Text;
                            rows[0]["DisplayName"] = txtDisplayName.Text;
                            dtMonitors.AcceptChanges();
                        
                            if (lstMonitors.SelectedItem.Text != txtDisplayName.Text)
                                UpdateARIC();
                        }
                        if (ServerListChanged)
                            ApplyServersToMonitor(lblMonitorID.Text.Substring(4));
                    }

                    if ((DataChanged) || (ServerListChanged)) //if anything was changed
                    {

                        //rebind the listbox
                        DataView dv = new DataView(dtMonitors);
                        dv.Sort = “DisplayName”;
                        lstMonitors.DataSource = dv;
                        lstMonitors.DataTextField = “DisplayName”;
                        lstMonitors.DataValueField = “MonitorGuid”;
                        lstMonitors.DataBind();
                        lstMonitors.SelectedIndex =dv.Find(txtDisplayName.Text);

                        //reset the flags
                        DataChanged = false;
                        ServerListChanged = false;

                        //save eveything
                        SavetoSession(“dtMonitors”, dtMonitors);
                        SavetoSession(“DataChanged”, DataChanged);
                        SavetoSession(“ServerListChanged”, ServerListChanged);
                    }
                    txtTicket.Text = string.Empty;
                }
            }
            catch (Exception ex)
            {
                lblErrMsg.Text = EventLogWriter.GenericErrorMsg;
                EventLogWriter.LogEvent(ex);
            }
        }
        protected void btnAddServer_Click(object sender, EventArgs e)
        {
            DataRow dr, dr2;
            ServerListChanged = true;
            SavetoSession(“ServerListChanged”, ServerListChanged);

            if (Session["CurrentMonitorServers"] != null)
                dtMonitorServersCurrent = (DataTable)Session["CurrentMonitorServers"];

            if (Session["MonitorServersTable"] != null)
                dtMonitorservers = (DataTable)Session["MonitorServersTable"];

            for (int i=0;i<lstAllServers.Items.Count; i++) //loop through the listbox
            {
                if (lstAllServers.Items[i].Selected) //if the row is selected
                {
                    dr = dtMonitorServersCurrent.NewRow();
                    if (lblMonitorID.Text == string.Empty)
                    {
                        dr["MonitorGuid"] = string.Empty;
                    }
                    else
                    {
                        dr["MonitorGuid"] = lblMonitorID.Text.Substring(4);
                    }
                    dr["OverrideGuid"] = string.Empty;
                    dr["ServerName"] = lstAllServers.Items[i].Text;
                    dr["ServerGuid"] = lstAllServers.Items[i].Value;

                    DataRow[] existingRows = dtMonitorServersCurrent.Select(“ServerGuid = ‘” + lstAllServers.Items[i].Value + “‘”);

                    if (existingRows.Length == 0) //not already found in current list
                    {
                        dtMonitorServersCurrent.Rows.Add(dr);
                        dr2 = dtMonitorservers.NewRow();
                        dr2.ItemArray = dr.ItemArray;
                        dtMonitorservers.Rows.Add(dr2);
                        btnRemoveServer.Enabled = true; //enable so it can be removed
                    }
                }//if li.selected
            }//for
            SavetoSession(“CurrentMonitorServers”, dtMonitorServersCurrent);
            SavetoSession(“MonitorServersTable”, dtMonitorservers);
            lstMonitorServers.DataSource = dtMonitorServersCurrent.DefaultView;
            lstMonitorServers.DataTextField = “ServerName”;
            lstMonitorServers.DataValueField = “ServerGuid”;
            lstMonitorServers.DataBind();
        }
        protected void btnRemoveServer_Click(object sender, EventArgs e)
        {
            ServerListChanged = true;
            SavetoSession(“ServerListChanged”, ServerListChanged);
            
            if (Session["CurrentMonitorServers"] != null)
                dtMonitorServersCurrent = (DataTable)Session["CurrentMonitorServers"];

            if (Session["MonitorServersTable"] != null)
                dtMonitorservers = (DataTable)Session["MonitorServersTable"];

            for (int i = 0; i < lstMonitorServers.Items.Count; i++) //loop through the listbox
            {
                if (lstMonitorServers.Items[i].Selected) //if the row is selected
                {
                    DataRow[] existingRows = dtMonitorServersCurrent.Select(“ServerGuid = ‘” + lstMonitorServers.Items[i].Value + “‘”);

                    if (existingRows.Length == 1) //found – row was in original server list
                    {
                        dtMonitorServersCurrent.Rows.Remove(existingRows[0]);
                    }

                    existingRows = dtMonitorservers.Select(“MonitorGuid = ‘” + lblMonitorID.Text.Substring(4) + “‘ and ServerGuid = ‘” + lstMonitorServers.Items[i].Value + “‘”);

                    if (existingRows.Length == 1) //found – row was in original server list
                    {
                        dtMonitorservers.Rows.Remove(existingRows[0]);
                    }
                }//if li.selected
            }//for
            SavetoSession(“CurrentMonitorServers”, dtMonitorServersCurrent);
            SavetoSession(“MonitorServersTable”, dtMonitorservers);
            lstMonitorServers.DataSource = dtMonitorServersCurrent.DefaultView;
            lstMonitorServers.DataTextField = “ServerName”;
            lstMonitorServers.DataValueField = “ServerGuid”;
            lstMonitorServers.DataBind();
            if (lstMonitorServers.Items.Count == 0) //is the list empty?
            {
                btnRemoveServer.Enabled = false;
            }
        }
        protected void Form_DataChanged(object sender, EventArgs e)
        {
            DataChanged = true;
            SavetoSession(“DataChanged”, DataChanged);
        }

#endregion
        private void LoadData()
        {
                string qsParms = string.Empty;
                XmlDocument xmlRules = new XmlDocument();

                qsParms = “?DC=” + ddlDC.SelectedValue + “&Account=” + txtAccount.Text;
                WebServiceCaller wc = new WebServiceCaller();
                wc.Exec(“http://&#8221; + Session["WebServicesServer"] + “/scom/SCOMAdmin.asmx/GetServiceStateMonitors” + qsParms);

                if (wc.Status == WebServiceCaller.WebServiceCallStatus.Succeeded)
                {
                    //build tables
                    BuildMonitorsTable();
                    XmlNode treeRoot = wc.Data;

                    if (treeRoot.HasChildNodes)
                    {
                        LoadMonitors(treeRoot); //load the data into a data table
                        tblMonitors.Visible = true;
                    }
                    else
                    {
                        lblErrMsg.Text = “No custom service state monitors found for account ” + txtAccount.Text;
                        tblMonitors.Visible = true;
                    }
                    LoadAllServers(); //load the list of servers in the account

                    SavetoSession(“dtMonitors”, dtMonitors);
                    SavetoSession(“MonitorServersTable”, dtMonitorservers);
                    SavetoSession(“CurrentMonitorServers”, dtMonitorServersCurrent);
                    SavetoSession(“OriginalMonitorServers”, dtMonitorserversOriginal);

                }//status=succeeded
                else //webservice failed
                {
                    lblErrMsg.Text = wc.StatusMessage;
                    tblMonitors.Visible = false;
                }
            
        }
        private void LoadMonitors(XmlNode root)
        {
            DataRow dr;
            XmlNode CurrNode;
            XmlNodeList nodeList;

            foreach (XmlNode n in root.ChildNodes)
            {
                dr = dtMonitors.NewRow();
                dr["MonitorGuid"] = n.Attributes["guid"].Value;

                CurrNode = n.SelectSingleNode(“./DisplayName”);
                dr["DisplayName"] = CurrNode.InnerText;

                CurrNode = n.SelectSingleNode(“./Criteria/ServiceName”);
                dr["ServiceName"] = CurrNode.InnerText;

                dtMonitors.Rows.Add(dr);

                nodeList = n.SelectNodes(“./Overrides/Override/Server[@enabled='true']“);
                foreach (XmlNode x in nodeList)
                {
                    dr = dtMonitorservers.NewRow();
                    dr["MonitorGuid"] = n.Attributes["guid"].Value;
                    dr["OverrideGuid"] = x.ParentNode.Attributes["id"].Value;
                    dr["ServerName"] = x.InnerText;
                    dr["ServerGuid"] = x.Attributes["id"].Value;
                    dtMonitorservers.Rows.Add(dr);
                }
            }//foreach monitor

            DataView dv = new DataView(dtMonitors);
            dv.Sort = “DisplayName”;
            lstMonitors.DataSource = dv;
            lstMonitors.DataTextField = “DisplayName”;
            lstMonitors.DataValueField = “MonitorGuid”;
            lstMonitors.DataBind();
        }
        private void LoadAllServers()
        {
            try
            {
            //get list of all servers in account that can be added to a monitor
                string qsParms = string.Empty;
                XmlDocument xmlServerList = new XmlDocument();
                qsParms = “?DC=” + ddlDC.SelectedValue + “&Account=” + txtAccount.Text + “&ServerFilter=”;

                WebServiceCaller wc = new WebServiceCaller();
                wc.Exec(“http://&#8221; + Session["WebServicesServer"] + “/scom/SCOMAgent.asmx/GetAgents” + qsParms);
                
                if (wc.Status == WebServiceCaller.WebServiceCallStatus.Succeeded)
                {
                    XmlNode treeRoot = wc.Data;
                    if (treeRoot.HasChildNodes)
                    {
                        //add servers/guids to arraylist so we can sort it
                        ArrayList al = new ArrayList();
                        foreach (XmlNode x in treeRoot.ChildNodes)
                        {
                            al.Add(new ListItem(x.InnerText,x.Attributes["guid"].Value));
                        }
                        al.Sort(new ListItemSorter());

                        //then bind it to the listbox
                        lstAllServers.Items.Clear();
                        lstAllServers.DataSource = al;
                        lstAllServers.DataTextField = “Text”;
                        lstAllServers.DataValueField = “Value”;
                        lstAllServers.DataBind();
                        lstAllServers.Enabled = true;
                        btnAddServer.Enabled = true;
                    }
                    else
                    {
                        lstAllServers.Items.Clear();
                        lstAllServers.Items.Add(“–None Found–“);
                        lstAllServers.Items.Add(“Check the Rackspace RegKey”);
                        lstAllServers.Items.Add(“HKLM\\Software\\Rackspace “);
                        lstAllServers.Items.Add(“and make sure that the “);
                        lstAllServers.Items.Add(“CustomerNumber is correct”);
                        lstAllServers.Items.Add(“on all devices running “);
                        lstAllServers.Items.Add(“the SCOM agent”);
                        lstAllServers.Enabled = false;
                        btnAddServer.Enabled = false;
                    }
                }//status=succeeded
                else //webservice failed
                {
                    lblErrMsg.Text = wc.StatusMessage;
                }
            }
            catch (Exception ex)
            {
                lblErrMsg.Text = EventLogWriter.GenericErrorMsg;
                EventLogWriter.LogEvent(ex);
            }
        }
       
        private void BuildMonitorsTable()
        {
            dtMonitors.Columns.Add(“MonitorGuid”);
            dtMonitors.Columns.Add(“ServiceName”);
            dtMonitors.Columns.Add(“DisplayName”);

            dtMonitorservers.Columns.Add(“MonitorGuid”);
            dtMonitorservers.Columns.Add(“OverrideGuid”);
            dtMonitorservers.Columns.Add(“ServerName”);
            dtMonitorservers.Columns.Add(“ServerGuid”);

            //dtMonitorserversCurrent holds servers that are applied/or to be applied to be to the current monitor
            dtMonitorServersCurrent = dtMonitorservers.Clone(); //duplicate the dtMonitorservers Table

            //dtMonitorserversOriginal hold the original list of servers applied to the current monitor, before any user changed
            //When committing, the Current and Original tables are compared to determine which servers need to be added/removed from the monitor via the WebService
            dtMonitorserversOriginal = dtMonitorservers.Clone(); //duplicate the dtMonitorservers table
            dtMonitorserversOriginal.Rows.Clear(); //and clear the data
        }//BuildMonitorsTable

        protected void InitDetailForm()
        {
            lblMonitorID.Text = string.Empty;
            txtDisplayName.Text = string.Empty;
            txtServiceName.Text = string.Empty;
            txtTicket.Text = string.Empty;

            lstMonitorServers.Items.Clear();
            lstAllServers.SelectedIndex = -1;

            //change the button text so we know that we are adding instead of updating
            btnCommit.Text = “Commit New Monitor”;

            //show the Commit and Reset buttons
            btnCommit.Visible = true;
            btnReset.Visible = true;

            // disable the remove servers button
            btnRemoveServer.Enabled = false;

            //display the table
            tblDetails.Visible = true;
        }

        private string AddUpdateMonitor(string CreateUpdate)
        {
            string qsParms = string.Empty;
            XmlDocument xmlRules = new XmlDocument();
            lblErrMsg.Text = string.Empty;

            qsParms = “?DC=” + ddlDC.SelectedValue;
            qsParms += “&Account=” + txtAccount.Text;
            if (CreateUpdate == “Update”)
                qsParms += “&MonitorGuid=” + lblMonitorID.Text.Substring(4); //chop off the ID: from the displayed monitorID
            
            qsParms += “&ServiceName=” + txtServiceName.Text;
            qsParms += “&ServiceDisplayName=” + txtDisplayName.Text;
            qsParms += “&Ticket=” + txtTicket.Text;
            qsParms += “&UserID=” + UserName;

            WebServiceCaller wc = new WebServiceCaller();
            string webMethod = CreateUpdate + “ServiceStateMonitor”; //webmethod name is either CreateServiceStateMonitor or UpdateServiceStateMonitor
            wc.Exec(“http://&#8221; + Session["WebServicesServer"] + “/scom/SCOMAdmin.asmx/” + webMethod + qsParms);

            if (wc.Status == WebServiceCaller.WebServiceCallStatus.Succeeded)
            {
                //add to datatable dtMonitors
                lblErrMsg.Text = “Custom Service monitor has been ” + CreateUpdate.ToLower() + “d for the \”” + txtDisplayName.Text +”\” service “; //Created or Updated msg
                XmlNode treeRoot = xmlRules.SelectSingleNode(“/Response/ReturnData”);
                lblMonitorID.Text = “ID: ” + treeRoot.FirstChild.InnerText; //show the new monitorid, if adding
                btnCommit.Text = “Commit Monitor Changes”;
                return treeRoot.FirstChild.InnerText;
            }//status=succeeded
            else //webservice failed
            {
                lblErrMsg.Text = wc.StatusMessage;
                return string.Empty;
            }
        }
        
        private void ApplyServersToMonitor(string MonitorGuid)
        {
            //compare lstOriginalMonitorServes to lstMonitorServers to see what was added/removed
            if (Session["CurrentMonitorServers"] != null)
                dtMonitorServersCurrent = (DataTable)Session["CurrentMonitorServers"];

            if (Session["OriginalMonitorServers"] != null)
                dtMonitorserversOriginal = (DataTable)Session["OriginalMonitorServers"];

            //newly added servers will have an empty Override Guid in the Current table
            DataRow[] newServers = dtMonitorServersCurrent.Select(“OverrideGuid = ””);
            foreach (DataRow r in newServers)
            {
                AddServerToMonitor(MonitorGuid, r["ServerGuid"].ToString());
            }
            
            //servers in Original but not current list need to be removed from monitor
            foreach (DataRow r in dtMonitorserversOriginal.Rows)
            {
                DataRow[] existingRow = dtMonitorServersCurrent.Select(“ServerGuid = ‘” + r["ServerGuid"].ToString() + “‘”);
                if (existingRow.Length == 0)
                {
                    RemoveServerFromMonitor(MonitorGuid, r["ServerGuid"].ToString());
                }
            }

        }
        private void AddServerToMonitor(string monitorGUID, string serverGUID)
        {
                string qsParms = string.Empty;
                XmlDocument xmlRules = new XmlDocument();
                //lblErrMsg.Text = string.Empty;

                qsParms = “?DC=” + ddlDC.SelectedValue;
                qsParms += “&MonitorGuid=” + monitorGUID;
                qsParms += “&ServerGuid=” + serverGUID;
                qsParms += “&Ticket=” + txtTicket.Text;
                qsParms += “&UserID=” + UserName;

                WebServiceCaller wc = new WebServiceCaller();
                wc.Exec(“http://&#8221; + Session["WebServicesServer"] + “/scom/SCOMAdmin.asmx/EnableMonitor” + qsParms);

                if (wc.Status == WebServiceCaller.WebServiceCallStatus.Succeeded)
                {
                    if (!DataChanged)
                        lblErrMsg.Text = “Server list has been updated”;

                }//status=succeeded
                else //webservice failed
                {
                    lblErrMsg.Text = wc.StatusMessage;
                }
        }
        private void RemoveServerFromMonitor(string monitorGUID, string serverGUID)
        {
            string qsParms = string.Empty;
            XmlDocument xmlRules = new XmlDocument();
            lblErrMsg.Text = string.Empty;

            qsParms = “?DC=” + ddlDC.SelectedValue;
            qsParms += “&MonitorGuid=” + monitorGUID;
            qsParms += “&ServerGuid=” + serverGUID;
            qsParms += “&Ticket=” + txtTicket.Text;
            qsParms += “&UserID=” + UserName;

            WebServiceCaller wc = new WebServiceCaller();
            wc.Exec(“http://&#8221; + Session["WebServicesServer"] + “/scom/SCOMAdmin.asmx/DisableMonitor” + qsParms);

            if (wc.Status == WebServiceCaller.WebServiceCallStatus.Succeeded)
            {
                if (!DataChanged)
                    lblErrMsg.Text = “Server list has been updated”;
            }//status=succeeded
            else //webservice failed
            {
                lblErrMsg.Text = wc.StatusMessage;
                //tblMonitors.Visible = false;
            }
        }
        
        private bool ValidData()
        {
            bool status = true;
            
            if (txtServiceName.Text == string.Empty)
            {
                lblErrMsg.Text += “Service Name is required<br />”;
                txtServiceName.Focus();
                status = false;
            }
            else
            {
                if (HasSpecialChars(txtServiceName.Text))
                {
                    lblErrMsg.Text += “Service Name contains invalid characters. Valid characters are a-z, 0-9, space, hyphen and underscore<br />”;
                    txtServiceName.Focus();
                    status = false;
                }
            }

            if (txtDisplayName.Text == string.Empty)
            {
                lblErrMsg.Text += “Display Name is required<br />”;
                txtDisplayName.Focus();
                status = false;
            }
            else
            {
                if (HasSpecialChars(txtDisplayName.Text))
                {
                    lblErrMsg.Text += “Display Name contains invalid characters. Valid characters are a-z, 0-9, space, hyphen and underscore<br />”;
                    txtDisplayName.Focus();
                    status = false;
                }
            }

            if (txtTicket.Text == string.Empty)
            {
                lblErrMsg.Text += “Ticket ID is required<br />”;
                txtTicket.Focus();
                status = false;
            }
            else
            {
                if (HasSpecialChars(txtTicket.Text))
                {
                    lblErrMsg.Text += “Display Name contains invalid characters. Valid characters are a-z, 0-9, space, hyphen and underscore<br />”;
                    txtTicket.Focus();
                    status = false;
                }
            }
            return status;
        }

        private bool HasSpecialChars(string s)
        {
            Regex pattern = new Regex(@”^[A-Za-z0-9_ \-]+$”, RegexOptions.IgnoreCase);
            return !pattern.IsMatch(s);
        }
        
        private void SavetoSession(string sVar, object obj)
        {
            if (Session[sVar] == null)
            { Session.Add(sVar, obj); }
            else { Session[sVar] = obj; }
        }

private void AddToARIC()
        {
            string qsParms = string.Empty;
            XmlDocument xmlRules = new XmlDocument();
            lblErrMsg.Text = string.Empty;

            qsParms = “?ARICSourceID=1″;
            qsParms += “&Account=” + txtAccount.Text;

            qsParms += “&AlertText=” + txtAccount.Text + ” – ” + txtDisplayName.Text + ” service is not running”;

            WebServiceCaller wc = new WebServiceCaller();
            wc.Exec(“http://&#8221; + Session["WebServicesServer"] + “/scom/SCOMAdmin.asmx/AddToARIC” + qsParms);

            if (wc.Status != WebServiceCaller.WebServiceCallStatus.Succeeded) //webservice call failed
            {
                lblErrMsg.Text = wc.StatusMessage;
            }

        }

        private void UpdateARIC()
        {
            string qsParms = string.Empty;
            XmlDocument xmlRules = new XmlDocument();
            lblErrMsg.Text = string.Empty;

            qsParms = “?ARICSourceID=1″;
            qsParms += “&Account=” + txtAccount.Text;
            qsParms += “&OldAlertText=” + txtAccount.Text + ” – ” + lstMonitors.SelectedItem.Text + ” service is not running”;
            qsParms += “&NewAlertText=” + txtAccount.Text + ” – ” + txtDisplayName.Text + ” service is not running”;

            WebServiceCaller wc = new WebServiceCaller();
            wc.Exec(“http://&#8221; + Session["WebServicesServer"] + “/scom/SCOMAdmin.asmx/UpdateARIC” + qsParms);

            if (wc.Status != WebServiceCaller.WebServiceCallStatus.Succeeded ) //webservice call failed
            {
                lblErrMsg.Text = wc.StatusMessage;
            }
        }
    }//class
}//namespace

ssPortal: Create/Update a Service State Monitor(Part 1)

February 18, 2011 Leave a comment

I created a Custom Event Rule page first, but for the sake of explanation, I’ll present the Service State Monitor first. The logic for the Service State Monitor is somewhat simpler and will make for a better introduction to creating your own monitors and rules.

The SCOM SDK has a documented example of How to Create a Unit Monitor. Adapting this example to my environment was not very difficult. The major difference was that, like all good SCOM admins, we create rules and monitors in a disabled state. Then we create an override to enable them. The example doesn’t do this.

The CreateServiceStateMonitor web service method does the following:

  • connect to the management group based on the DC parameter
  • gets the MP for the Account parameter
  • Creates a disabled Unit Monitor of type “Microsoft.Windows.CheckNTServiceStateMonitorType”
  • Creates the Alert settings, the alert text is set to “ServiceDisplayName service is not running”
  • Creates the Healthstates: “Running”=Healthy; “NotRunning”=Critical
  • Sets the config XML to the monitor the ServiceName service
  • adds the unit monitor to the monitoring hierarchy, by setting the parent aggregate monitor
  • write the Audit Trail record
  • return the GUID of the newly created monitor

The UpdateServiceStateMonitor method is almost identical with just a few minor changes.

Now for my one real complaint with the SCOM SDK — the classes have no methods to delete anything. You can create and update, enable and disable almost anything all day long, but you can’t delete anything. Hacking the XML is about your only option and that was something I was not willing to do. So, the ssPortal would be able to create and update rules and monitors, but not delete anything. If something needs to be deleted, users have to contact my team and we do it through the SCOM console. I really hope the Microsoft decide(d) to put some delete capabilities in future SDK’s.

OK, off the soapbox and on to the code…

Create/Update Service State Monitor methods and associated helper functions

        [WebMethod]
        public XmlDocument CreateServiceStateMonitor(string DC, int Account,string ServiceName, string ServiceDisplayName, string Ticket, string UserID)
        {
            WebServiceXML ReturnXML = new WebServiceXML();
            ManagementPack mp;
            MonitoringClass monitoringClass;
            ManagementPackUnitMonitor serviceMonitor;
            ManagementPackUnitMonitorType serviceMonitorType;
            try
            {
                ConnectManagementGroup(DC); //connect to the Management Group
                mp = mg.GetManagementPacks(“rs” + Account.ToString())[0]; //Get the MP
                if (mp != null) //if mp is not found, return empty data
                {
                    string MonitorID = Guid.NewGuid().ToString().Replace(“-“, string.Empty); //generate a guid and strip out the dashes
                    string mpMonitorName = “WebServiceMonitor” + MonitorID; //generate an internal name

                    serviceMonitorType = mg.GetUnitMonitorTypes(“Microsoft.Windows.CheckNTServiceStateMonitorType”)[0];
                    serviceMonitor = new ManagementPackUnitMonitor(mp, mpMonitorName, ManagementPackAccessibility.Internal);

                    serviceMonitor.DisplayName = Account.ToString() + ” – ” + ServiceDisplayName + ” service is not running”;
                    serviceMonitor.TypeID = serviceMonitorType;
                    serviceMonitor.Target = WinComputerClass;
                    serviceMonitor.Enabled = ManagementPackMonitoringLevel.@false;
                    serviceMonitor.Description = “\r\n” + DateTime.Now.ToShortDateString() + ” – #” + Ticket + ” Monitor created by ” + UserID + ” via ssPortal”;

                    CreateAlertSettings(serviceMonitor, serviceMonitorType, mp);
                    CreateHealthStates(serviceMonitor, serviceMonitorType);
                    CreateUpdateMonitorConfiguration(serviceMonitor, ServiceName);
                    CreateParentMonitor(serviceMonitor, mg);
                    
                    mp.Verify();
                    mp.AcceptChanges(); //Save the changes into the management pack.

                    ReturnXML.AddData(“<Monitor>” + serviceMonitor.Id.ToString() + “</Monitor>”);
                    
                    // Set variables to pass to Auditing
                    String MethodName = new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name;
                    string oldVal = string.Empty;
                    string NewVal = string.Empty;
                    string NamePath = serviceMonitor.DisplayName;

                    this.WriteAuditTrail(MethodName, NamePath, oldVal, NewVal, Ticket, UserID, “SCOM”);
                    ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
                }
            }
            catch (Exception ex)
            {
                EventLogWriter.LogEvent(ex);
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, GenericErrorMsg);
            }
            return ReturnXML.Root;
        }//CreateServiceStateMonitor

        [WebMethod]
        public XmlDocument UpdateServiceStateMonitor(string DC, int Account, string MonitorGuid, string ServiceName, string ServiceDisplayName, string Ticket, string UserID)
        {
            WebServiceXML ReturnXML = new WebServiceXML();
            ManagementPack mp;
            ManagementPackUnitMonitor serviceMonitor;
            try
            {
                ConnectManagementGroup(DC); //connect to the Management Group
                mp = mg.GetManagementPacks(“rs” + Account.ToString())[0]; //Get the MP
                if (mp != null) //if mp is not found, return empty data
                {
                    string mpMonitorName = “WebServiceMonitor” + MonitorGuid; //generate an internal name
                    serviceMonitor = (ManagementPackUnitMonitor)mg.GetMonitor(new Guid(MonitorGuid));
                    serviceMonitor.Description += “\r\n” + DateTime.Now.ToShortDateString() + ” – #” + Ticket + ” Monitor updated by ” + UserID + ” via ssPortal”;
                    serviceMonitor.DisplayName = Account.ToString() + ” – ” + ServiceDisplayName + ” service is not running”;

                    UpdateAlertSettings(serviceMonitor, mp);
                    CreateUpdateMonitorConfiguration(serviceMonitor, ServiceName);
                    
                    serviceMonitor.Status = ManagementPackElementStatus.PendingUpdate;

                    mp.Verify();
                    mp.AcceptChanges(); //Save the changes into the management pack.

                    ReturnXML.AddData(“<Monitor>” + serviceMonitor.Id.ToString() + “</Monitor>”);

                    // Set variables to pass to Auditing
                    String MethodName = new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name;
                    string oldVal = string.Empty;
                    string NewVal = string.Empty;
                    string NamePath = ServiceDisplayName;

                    this.WriteAuditTrail(MethodName, NamePath, oldVal, NewVal, Ticket, UserID,”SCOM”);
                    ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
                }
            }
            catch (Exception ex)
            {
                EventLogWriter.LogEvent(ex);
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, GenericErrorMsg);
            }
            return ReturnXML.Root;
        }//UpdateServiceStateMonitor

        private void CreateAlertSettings(ManagementPackUnitMonitor serviceMonitor, ManagementPackUnitMonitorType unitMonitorType,ManagementPack mp)
        {
            serviceMonitor.AlertSettings = new ManagementPackMonitorAlertSettings();
            serviceMonitor.AlertSettings.AlertOnState = HealthState.Error;
            serviceMonitor.AlertSettings.AutoResolve = true;
            serviceMonitor.AlertSettings.AlertPriority = ManagementPackWorkflowPriority.Normal;
            serviceMonitor.AlertSettings.AlertSeverity = ManagementPackAlertSeverity.Error;
            serviceMonitor.AlertSettings.AlertParameter1 = @”$Target/Property[Type=""Windows!Microsoft.Windows.Computer""]/NetworkName$”; //this points to the computer name

            ManagementPackStringResource alertMessage;

            alertMessage = new ManagementPackStringResource(mp, serviceMonitor.Name + “AlertMessage”);

            alertMessage.DisplayName = serviceMonitor.DisplayName;
            alertMessage.Description = “The service on computer {0} is not in a RUNNING state.”;

            serviceMonitor.AlertSettings.AlertMessage = alertMessage;
        }
        private void UpdateAlertSettings(ManagementPackUnitMonitor serviceMonitor, ManagementPack mp)
        {
            ManagementPackStringResource alertMessage = mp.GetStringResource(serviceMonitor.Name + “AlertMessage”);
            alertMessage.DisplayName = serviceMonitor.DisplayName;

            serviceMonitor.AlertSettings.AlertMessage = alertMessage;
        }
        private void CreateHealthStates(ManagementPackUnitMonitor serviceMonitor, ManagementPackUnitMonitorType serviceMonitorType)
        {
            ManagementPackUnitMonitorOperationalState healthyState;
            ManagementPackUnitMonitorOperationalState errorState;

            healthyState = new ManagementPackUnitMonitorOperationalState(serviceMonitor, “Success”);
            errorState = new ManagementPackUnitMonitorOperationalState(serviceMonitor, “Error”);

            healthyState.HealthState = HealthState.Success;
            healthyState.MonitorTypeStateID = “Running”;

            errorState.HealthState = HealthState.Error;
            errorState.MonitorTypeStateID = “NotRunning”;

            serviceMonitor.OperationalStateCollection.Add(healthyState);
            serviceMonitor.OperationalStateCollection.Add(errorState);
        }
        private void CreateUpdateMonitorConfiguration(ManagementPackUnitMonitor serviceMonitor, string svcName)
        {
            string monitorConfig;

            monitorConfig = @”<ComputerName>$Target/Property[Type=""Windows!Microsoft.Windows.Computer""]/NetworkName$</ComputerName>
                                        <ServiceName>” + svcName + “</ServiceName>”;

            serviceMonitor.Configuration = monitorConfig;
        }
        private void CreateParentMonitor(ManagementPackUnitMonitor serviceMonitor,ManagementGroup mg)
        {
            ManagementPackAggregateMonitor parentMonitor;
            MonitorCriteria monitorCriteria;

            monitorCriteria = new MonitorCriteria(“Name=’System.Health.AvailabilityState'”);
            parentMonitor = (ManagementPackAggregateMonitor)mg.GetMonitors(monitorCriteria)[0];
            serviceMonitor.ParentMonitorID = parentMonitor;
        }

Setting the Override to enable/disable the monitor for a particular computer is handled by another pair methods, aptly named EnableMonitor and DisableMonitor. Please disregard the logic involving clusters(IsACluster, GetClusterNodes,…). I was attempting to abstract the cluster nodes, by not presenting the physical nodes in the list of account servers. If a cluster was selected, then the code would use the physical nodes where appropriate. However, I have just recently discovered that there are a couple of gaping holes in my logic and It needs to be re-worked -but that is another article for a later time…. much, much later.

Enable/DisableMonitor methods

 [WebMethod]
        public XmlDocument EnableMonitor(string DC, string MonitorGUID, string ServerGUID, string Ticket, string UserID)
        {
            WebServiceXML ReturnXML = new WebServiceXML();
            List<string> pNodes = new List<string>();
            try
            {
                ConnectManagementGroup(DC);
                MonitoringClass monitoringClass = mg.GetMonitoringClass(SystemMonitoringClass.WindowsComputer);
                MonitoringObject objServer = mg.GetMonitoringObject(new Guid(ServerGUID));
                ManagementPackMonitor monitor = mg.GetMonitor(new Guid(MonitorGUID));
                ManagementPack mp = monitor.GetManagementPack();
                
                //if ((IsACluster(objServer.DisplayName)) && (!IsSQLServer(objServer.DisplayName)))
                if (IsACluster(objServer.DisplayName))
                {
                    pNodes = GetClusterNodes(objServer.DisplayName);
                }
                else pNodes.Add(objServer.DisplayName);

                foreach (string n in pNodes)
                {
                    MonitoringObjectGenericCriteria moCriteria = new MonitoringObjectGenericCriteria(“DisplayName like ‘%” + n + “%'”);
                    MonitoringObject WinComputerObject = mg.GetMonitoringObjects(moCriteria, monitoringClass)[0];

                    string overrideName = “OverrideForMonitor” + monitor.Name + WinComputerObject.Id.ToString().Replace(“-“, string.Empty);
                    ManagementPackMonitorPropertyOverride monitorOverride = new ManagementPackMonitorPropertyOverride(mp, overrideName);
                    monitorOverride.Monitor = monitor;
                    monitorOverride.Property = ManagementPackMonitorProperty.Enabled;
                    monitorOverride.Value = “true”;
                    monitorOverride.Context = monitoringClass;
                    monitorOverride.ContextInstance = WinComputerObject.Id;
                    monitorOverride.DisplayName = “Override for Monitor ” + monitor.Name;
                    monitorOverride.Description += “\r\n” + DateTime.Now.ToShortDateString() + ” – #” + Ticket + ” Monitor enabled by ” + UserID + ” via ssPortal”;
                }
                mp.Verify();
                mp.AcceptChanges();

                // Set variables to pass to Auditing
                String MethodName = new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name;
                string oldVal = string.Empty;
                string NewVal = objServer.DisplayName;
                string NamePath = monitor.DisplayName;
                this.WriteAuditTrail(MethodName, NamePath, oldVal, NewVal, Ticket, UserID, “SCOM”);

                //set status
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
            }
            catch (Exception ex)
            {
                EventLogWriter.LogEvent(ex);
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, ex.Message);
            }
            return ReturnXML.Root;
        }

        [WebMethod]
        public XmlDocument DisableMonitor(string DC, string MonitorGUID, string ServerGUID, string Ticket, string UserID)
        {
            WebServiceXML ReturnXML = new WebServiceXML();

            try
            {
                ConnectManagementGroup(DC);

                ManagementPackMonitorPropertyOverride ov;
                ManagementPackMonitor monitor = mg.GetMonitor(new Guid(MonitorGUID));
                ManagementPack mp = monitor.GetManagementPack();
                MonitoringObject objServer = mg.GetMonitoringObject(new Guid(ServerGUID));
                List<string> pNodes = new List<string>();
                MonitoringObjectGenericCriteria monCriteria;

                if (IsACluster(objServer.DisplayName))
                {
                    pNodes = GetClusterNodes(objServer.DisplayName);
                }
                else pNodes.Add(objServer.DisplayName);

                MonitoringClass WinComputerClass = mg.GetMonitoringClass(SystemMonitoringClass.WindowsComputer);

                string crit = “DisplayName like ‘%” + pNodes[0] + “%’ “;
                for (int i = 1; i < pNodes.Count; i++)
                {
                    crit += “OR DisplayName like ‘%” + pNodes[i] + “%’ “;
                }
                monCriteria = new MonitoringObjectGenericCriteria(crit);
                ReadOnlyCollection<MonitoringObject> WinComputerObjects = mg.GetMonitoringObjects(monCriteria, WinComputerClass);

                crit = “TargetId = ‘” + MonitorGUID + “‘ AND (ContextObjectId = ‘” + WinComputerObjects[0].Id.ToString() + “‘ “;
                for (int i = 1; i < pNodes.Count; i++)
                {
                    crit += “OR ContextObjectId = ‘” + WinComputerObjects[i].Id.ToString() + “‘”;
                }

                crit += “)”;
                MonitoringOverrideCriteria moCriteria = new MonitoringOverrideCriteria(crit);
                ReadOnlyCollection<ManagementPackOverride> MonitorOverrides = mg.GetMonitoringOverrides(moCriteria);

                foreach (ManagementPackMonitorOverride monitorOverride in MonitorOverrides)
                {
                    if (monitorOverride is ManagementPackMonitorPropertyOverride)
                    {
                        ov = (ManagementPackMonitorPropertyOverride)monitorOverride;
                        ov.Value = “false”;
                        ov.Description += “\r\n” + DateTime.Now.ToShortDateString() + ” – #” + Ticket + ” Monitor disabled by ” + UserID + ” via ssPortal”;
                        ov.Status = ManagementPackElementStatus.PendingUpdate;
                    }
                }

                //Save the changes into the management pack.
                mp.Verify();
                mp.AcceptChanges();

                // Set variables to pass to Auditing
                String MethodName = new System.Diagnostics.StackTrace().GetFrame(0).GetMethod().Name;
                string oldVal = objServer.DisplayName;
                string NewVal = string.Empty;
                string NamePath = monitor.DisplayName;

                this.WriteAuditTrail(MethodName, NamePath, oldVal, NewVal, Ticket, UserID, “SCOM”);

                //set status
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
            }
            catch (Exception ex)
            {
                EventLogWriter.LogEvent(ex);
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, ex.Message);
            }
            return ReturnXML.Root;
        }

And finally, now that I could create, update, enable and disable the service state monitors, I needed another method to retrieve them for a given account number. This method

  • Connects to the Management Group
  • Gets the account MP
  • Gets all the Monitors in the MP
  • Gets all the Monitor-Related overrides and saves them in a generic List for quick lookup later
  • Then for each Monitor in the MP
    • Get the Configuration xml data
    • use LINQ on the generic List to get the Override(s) for this particular monitor
    • build the XML to be returned

GetServiceStateMonitors method and associated helper functions

 [WebMethod(CacheDuration = cacheTime)]
        public XmlDocument GetServiceStateMonitors(string DC, int Account)
        {
            WebServiceXML ReturnXML = new WebServiceXML();
            try
            {
                ConnectManagementGroup(DC);
                ManagementPack mp = mg.GetManagementPacks(“rs” + Account.ToString())[0];
                if (mp != null)
                {
                    ManagementPackElementCollection<ManagementPackMonitor> Monitors = mp.GetMonitors();
                    StringBuilder sbXML = new StringBuilder();
                    GetMonitorOverrides(mg, mp); //load overrides into a list for faster lookups
                    foreach (ManagementPackUnitMonitor monitor in Monitors)
                    {
                        if (monitor.Name.Contains(“WebServiceMonitor”)) //only interested in monitors created by the WebService
                        {
                            sbXML.Append(@”<Monitor guid=””” + monitor.Id + @”””>”);
                            string dname = monitor.DisplayName;
                            int len = dname.IndexOf(” service is not running”) – dname.IndexOf(“-“) – 2;
                            dname = dname.Substring(dname.IndexOf(“-“) + 2, len);
                            sbXML.Append(“<DisplayName>” + dname + “</DisplayName>”);
                            sbXML.Append(“<Criteria>”);
                            sbXML.Append(monitor.Configuration);
                            sbXML.Append(“</Criteria>”);
                            sbXML.Append(“<Overrides>”);
                            sbXML.Append(GetOverrideForMonitor(monitor.Id));
                            sbXML.Append(“</Overrides>”);
                            sbXML.Append(“</Monitor>”);
                        }
                    }
                    //set status
                    ReturnXML.AddData(sbXML.ToString());
                }//if mp is not null
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Succeeded);
            }
            catch (Microsoft.EnterpriseManagement.Common.ObjectNotFoundException onf)
            {
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, “Custom Management Pack for account ” + Account.ToString() + ” was not found. Create a custom MP, then try this page again”);
            }
            catch (Exception ex)
            {
                EventLogWriter.LogEvent(ex);
                ReturnXML.SetStatus(WebServiceXML.ServiceStatus.Failed, ex.Message);
             }
            return ReturnXML.Root;

        }//EnableRule

        private void GetMonitorOverrides(ManagementGroup mg, ManagementPack mp)
        {
            ManagementPackElementCollection<ManagementPackOverride> overrides = mp.GetOverrides();
            foreach (ManagementPackOverride mpOverride in overrides)
            {
                if (mpOverride is ManagementPackMonitorPropertyOverride)
                {
                    ManagementPackMonitorPropertyOverride monitorOV = (ManagementPackMonitorPropertyOverride)mpOverride;
                    if (monitorOV.Property == ManagementPackMonitorProperty.Enabled)
                        lstMonitorOverrides.Add(monitorOV);
                }
            }
        }
         
         private string GetOverrideForMonitor(Guid monID)
        {
            PartialMonitoringObject svrObj;
            StringBuilder sbOV = new StringBuilder();
            List<string> ServerList = new List<string>();
            string logicalName = string.Empty;

            var res = from o in lstMonitorOverrides
                      where o.Monitor.Id == monID
                      select o;
            foreach (var ov in res)
            {
                ManagementPackMonitorPropertyOverride monitorOV = (ManagementPackMonitorPropertyOverride)ov;
                svrObj = mg.GetMonitoringObject((Guid)monitorOV.ContextInstance);
                if (IsClusterNode(svrObj.DisplayName)) //is this a cluster node
                    logicalName = GetClusterName(svrObj.DisplayName);
                else
                    logicalName = svrObj.DisplayName;

                if (!ServerList.Contains(logicalName))
                {
                    MonitoringObjectGenericCriteria moCriteria = new MonitoringObjectGenericCriteria(“DisplayName like ‘%” + logicalName + “%'”);
                    ReadOnlyCollection<PartialMonitoringObject> objList = mg.GetPartialMonitoringObjects(moCriteria, WinComputerClass);
                    if (objList.Count > 0)
                    {
                        svrObj = mg.GetPartialMonitoringObject((Guid)monitorOV.ContextInstance);
                        sbOV.Append(“<Override id=\”” + monitorOV.Id.ToString() + “\”>”);
                        sbOV.Append(“<Server enabled=\”” + monitorOV.Value + “\” id=\”” + objList[0].Id.ToString() + “\”>” + logicalName + “</Server>”);
                        sbOV.Append(“</Override>”);
                        ServerList.Add(logicalName);
                    }
                }//if!server.contains
            }//foreach
            return sbOV.ToString(); ;
        }

Follow

Get every new post delivered to your Inbox.