We have noticed over the last few weeks, a problem where subscriptions in System Center Operations Manager 2007 suddenly and for no reason we can identify, become disabled. This is a bad thing because these subscriptions are used to send email and pages to folks like Winfra when there is a critical problem with a domain controller or the SCCM folks.
I'm working with Microsoft to resolve the problem but until we get a resolution that does not involve deleting all of the subscriptions and re-creating them, I wrote a Windows service to monitor and re-enable any subscription that becomes disabled without permission.
So here is how it works. Written in C#, I have a timer that counts down 60 minutes and then it connects to the production root management server and queries the subscriptions and their status. If it finds a subscription that is in a disabled state, it will set the enabled property to true and then executes the update() method. It will then write an event to the event log on the server running the service.
In SCOM, I created a rule to read the event log and alert when it sees this condition.
So how does it do all of this? Well, let's get to the nitty gritty. Time to code!
First let's look at a few basics. We need to be able to connect to SCOM, we need to be able to query the subscriptions, we need to be able to enable a specific subscription and we need to be able to write to the event log.
Connecting to the management server can be done two ways. First we can connect using our own credentials. This will require that we have authority to connect and to read the subscriptions. This means our user account must be in the SCOM Admins role. We can easily do this by setting the logon credentials for our new service instead of using the local system account.
Option number two is to pass the logon credentials to the management server via code. I'll cover both methods here but the most practical way would be to set the credentials in the service logon tab of the service properties page. This will allow us to change the user account password and user ID without recompiling the code.
In the first method, hard coding the credentials, we need to consider a couple of things. First, the password has to be secure. This is a requirement of the SCOM SDK and not just best practice. You do this with a method called SecureString. In your declarations section, you need to have a reference to System.Security.
Next, you need to obtain the password from somewhere. You can do it via a database or code or whatever. I will use a simple array here for demonstration purposes but you can do it any way you want.
char[] sPassword = new char[8] { 'P', '@', 's', 's', 'w', '0', 'r', 'd' };
Now you can loop through the array and add each character to the secure string.
SecureString sPasswd = new SecureString();
foreach (char pw in sPassword)
{
sPasswd.AppendChar(pw);
}
Now that you have that, you need to tell the SDK where to find the management server.
ManagementGroupConnectionSettings mgSettings = new ManagementGroupConnectionSettings(sMgmtSvr);
Using the mgSettings variable, you can now define the connection settings needed and connect to the management server.
mgSettings.UserName = "SvcMyAccount";
mgSettings.Domain = "NW";
mgSettings.Password = sPasswd;
ManagementGroup mg = new ManagementGroup(mgSettings);
if (mg.IsConnected)
{
//Do stuff here
}
Connecting to the SCOM SDK is just that simple. Without the need to specify a user and password, it is even more simple. You can forgo the ManagementGroupConnectionSettings code and simply connect with this:
ManagementGroup mg = new ManagementGroup("myRMS.company.com");
This will use the credentials of the logged in user or the credentials of the user defined in the service.
Now that we are connected, we need to read the list of subscriptions and get their current status. If not enabled, enable it and update. Then write to the servers application log.
foreach (NotificationSubscription subscr in mg.GetNotificationSubscriptions())
{
if (!subscr.Enabled)
{
subscr.Enabled = true;
subscr.Update();
EventLog.WriteEntry(sService, "Enabled the " + subscr.DisplayName + " subscription", EventLogEntryType.Warning, 234);
}
}