RSS .92| RSS 2.0| ATOM 0.3
  • Home
  • About
  •  

    Operations Manager 2007 Database Query Utility

    May 28th, 2009

    Knowing how to pull informational data directly from the Operations Manager database and data warehouse can be a bit tricky, but a critical part of identifying and troubleshooting performance pain points as well as obtaining key informational data in the SCOM environment. To that extent, I have always leveraged the massively cool collection of SQL scripts on Kevin Holman’s website.

    Now when I needed to run these queries, I would open up Kevin’s website, fire up SQL Management Studio, connect to the database, open a query window and then start pasting and executing. In order to put all that functionality into a single resource, I quickly threw together a executable that contains most of the queries on Kevin’s website as well as the ability to connect to the SCOM backends and dump the information into a DataGridView on a windows form. I also included basic functionality for the queries that were parameterized to take input from the form rather than modifying the queries in the SQL editor window.

    First and foremost, I would like to thank Kevin (and give him full credit)  for posting his queries that have proven helpful time and time again. I have included the compiled standalone executable in the links below as well as the source code. Feel free to modify the code in any way to suit your needs as you see fit. The SQL statements are simply embedded into a basic XML resource which can be easily modified to add new queries.

    OpsMgrQueries.zip            OpsMgrQueries_Source.zip


    Operations Manager Data Warehouse High CPU Utilization

    October 29th, 2008

    I recently ran into an issue where the sqlserver.exe process on my data warehouse server was continously running at close to 100%. Stopping and starting the service did not help as it would continously climb back up to near 100% within a few minutes. I gave PSS a call and they helped me to identify the issue which I thought might be good to share.

    To put a little perspective on the environment; my data warehouse server is a dedicated cluster with quad processors and 8 GB on each node. The DW database is approx. 80GB and there are no other sql instances or databases running on the platform which is why I could not figure out why the CPU continuously stayed pegged as there was more than enough hardware to handle that role. Since there were multiple hyperthreaded processors, the first thing we attempted was to disable hyperthreading in the BIOS. No luck. The next item on the agenda was to make sure that the MAXDOP (Max Degree of Parallelism) was set properly for the server. This was done by running the following command and making the appropriate changes from the returned results to the maxdop properties of the server in Management Studio:

    select case when cpu_count / hyperthread_ratio > 8 then 8 else cpu_count / hyperthread_ratio end as optimal_maxdop_setting from sys.dm_os_sys_info.

    After changing the setting to the output from the select statement, my CPU utilization dropped down to around a steady 40% to 50% utilization. Better, but not the 3% to 5% normal utilization the server used to run with.

    After analyzing a few perfmon and SQL Profiler traces, PSS identified a stored procedure that was taking too long to run on the State dataset from “StandardDatasetMaintenance”. After some additional analysis, it turned out that there were several missing indexes which needed to be rebuilt. I ran the following two commands against the database:

    EXEC sp_MSForEachTable  “UPDATE STATISTICS ? with fullscan”

    EXEC sp_MSforeachtable @command1=”print ‘?’ DBCC DBREINDEX (‘?’, ‘ ‘, 100)”

    After these commands completed (took about 90 minutes), the CPU utilization was returned back to 5% or below. I have scheduled these as maintenance tasks to run every 30 days. It took nearly three weeks of headache to finally resolve the high CPU utilization so I hope this saves some time for others who admin SCOM, but are not DBA’s.


    Maintenance Mode in C# please, Maestro

    August 27th, 2008

    There are several outstanding PowerShell scripts available for placing computers into Maintenance Mode. A couple of examples would be here and here and even here for a Managment Pack to schedule Maintenance Mode. While these (and many others) are all great, they still required that Operations Manager console be installed on the machines where they were run. I needed a solution in my environment that allowed several admins to be able to put servers they were responsible for into MM without publishing the console to several workstations. Why not use the default web console for Operations Manager 2007 you ask? Because the Health Service Watcher class is not placed into MM when a server is selected from the Computers action pane and placed into MM. This meant that if the server needed to be restarted, an alert was triggered.

    Hmm… to get around this and to get a better understanding of what went on under the hood during Maintenance Mode, I thought I why not build a web page? Centralized solution, leverages the .NET namespaces in the code behind, brilliant! When I finally came up with a working solution I thought, “Woo-hoo! Publish that baby and see if it helps out some others”.

    For me, the largest hurdle was figuring out how to explicitly not only enumerate the MonitoringClass object I was targeting, but to also zero in on the target MonitoringObject as well without repeatedly enumerating all the members of the HealthServiceWatcher class until I found the one I needed. The key for me was putting the core classes to be placed into MM into an array and then properly specifying not only the MonitoringClassCriteria, but also the MonitoringObjectCriteria to effectively target the server to be placed into MM. A snippet of the code is as follows (thanks to the MSDN site for some helpful pointers). Note: On one or two occassions, I’ve seen the code for this post not get processed correctly by the syntax highlighter resulting in a server side error in the display box. If this happens to occur, simply refresh the page.

    ?View Code CSHARP
    ManagementGroup mg = new ManagementGroup(sRMS);
    ReadOnlyCollection<MonitoringObject> monitoringObjects;
    MonitoringClass computerMonitoringClass;
    MonitoringObjectCriteria criteria;
    MonitoringClassCriteria classCriteria;
    classCriteria = new MonitoringClassCriteria(arrClasses[i]);
    computerMonitoringClass = mg.GetMonitoringClasses(classCriteria)[0];
    criteria = new MonitoringObjectCriteria(string.Format("DisplayName like '" +
        sComputer + "%'"), computerMonitoringClass);
    monitoringObjects = mg.GetMonitoringObjects(criteria);
     
    foreach (MonitoringObject monObject in monitoringObjects)
    {
        if ((!monObject.InMaintenanceMode) && (monObject.DisplayName.ToLower() == sComputer))
        {
            DateTime startTime = DateTime.UtcNow;
            DateTime schedEndTime = DateTime.UtcNow.AddMinutes(intMin);
            MaintenanceModeReason reason = MaintenanceModeReason.PlannedOther;
            String comment = "Server Placed into MM via website";
            monObject.ScheduleMaintenanceMode(startTime, schedEndTime, reason, comment);
            results += monObject.DisplayName + " - " + strMonClass + " successfully set in maintenance mode." + "<br />";
        }
        if ((monObject.InMaintenanceMode) && (monObject.DisplayName.ToLower() == sComputer))
        {
            MaintenanceWindow window = monObject.GetMaintenanceWindow();
            DateTime schedEndTime = window.ScheduledEndTime;
            results += monObject.DisplayName + " - " + strMonClass +
    " already in maintenance mode until " + schedEndTime.AddHours(-7).ToShortTimeString() + " PST." + "<br />";
        }
    }

    I’ve included the source code as well as the compiled web site below. Feel free to copy and mangle to suit your needs. Some things to keep in mind:

    1. You will need to create an Application Pool for the website to run in the context of an account that has permissions to place objects in Maintenance Mode since it will default to the IUSR account.

    2. If you don’t want everyone to be able to connect to the website, you will need to implement some security such as a log on page for authorization or group membership checking via the Security.Principal namespace.

    3. I’m what is popularly known as “aesthetically challenged”. I’ve removed most of the formatting on the asp to just present the functionality. If you want to view the functionality before editing anything, you can create a website on your webserver and then simply extract the compiled site into your site’s root directory.

    SourceCode           CompiledWebsite


    Collecting Performance Data in Operations Manager 2007 and Publishing to SharePoint Part 2

    August 7th, 2008

    After figuring out how to get the logical drive performance data into the Data Warehouse (demonstrated in part 1), I needed to present the data in a simple report format that was quickly readable and searchable. Since we leverage SharePoint fairly heavily, I also needed to post the published report to the portal.

    The first step is to figure out the SQL query to get the data from the DW. This took the longest for me to figure out because I didn’t know exactly which tables were keeping the data being collected. As I mentioned in part 1, I would have saved myself a lot of time if I had knuckled down and slowly read over the examples for custom reporting as they detailed many different SQL scripts that greatly help explain the relationships between the tables as well as where to look to pull the performance data (or event and state data for that matter). The Report Authoring Guide can be found here. The following is the SQL script I used for the Data Source to return the information for all servers from the DW:

    SELECT	vPerf.DateTime,  vPerf.AverageValue, vPerformanceRuleInstance.InstanceName,
    	vManagedEntity.Name,  vPerformanceRule.CounterName
    FROM	Perf.vPerfHourly AS vPerf INNER JOIN
    	vPerformanceRuleInstance ON vPerformanceRuleInstance.PerformanceRuleInstanceRowId = vPerf.PerformanceRuleInstanceRowId INNER JOIN
    	vManagedEntity ON vPerf.ManagedEntityRowId = vManagedEntity.ManagedEntityRowId INNER JOIN
    	vPerformanceRule ON vPerformanceRuleInstance.RuleRowId = vPerformanceRule.RuleRowId
    WHERE	(vPerformanceRule.CounterName IN ('TotalCapacity')) AND (vPerformanceRuleInstance.InstanceName LIKE '%:') AND (vPerf.DateTime > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0))
    	OR
    	(vPerformanceRule.CounterName IN ('FreeSpace')) AND (vPerformanceRuleInstance.InstanceName LIKE '%:') AND (vPerf.DateTime > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0))
    	OR
    	(vPerformanceRule.CounterName IN ('UsedSpace')) AND (vPerformanceRuleInstance.InstanceName LIKE '%:') AND (vPerf.DateTime > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0))
    ORDER BY vManagedEntity.Name, vPerformanceRuleInstance.InstanceName,  vPerformanceRule.CounterName DESC

    Note: I leveraged views rather than the actual tables to prevent issues with the query should Microsoft change the schema a little in future updates. This is a recommended best practice per the documentation

    Next item is to create the report using the Business Intelligence Development Studio. Basic steps are as follows:
    1. Create a new Report Server Project Wizard.
    Create report wizard

    2. At the Select Data Source page, enter a name for the data source and click the Edit button to set up the connection to the SQL Data Warehouse server.

    3. Click OK to enter the server connection settings and verify them in the Select Data Source page. Click Next

    4. At the Design the Query window, copy and past the SQL script mentioned earlier in the post into the Query String window. You can click on the Query Builder button to get a visual breakdown of the tables and relationships as well as run the query in the UI to view what the results will look like. Click Next.

    5. At the Select the Report Type window, leave it default Tabular radio button selected and click Next.

    6. At the Design the Table screen, group the fields by Name and then place the remaining four fields into the Details window. Click Next.

    7. Accept the default Stepped radio button at the Choose the Table Layout window. Click Next.

    8. Select whatever style you want to apply on the Choose the Table Style window. Click Next.

    9. On the Choose the Deployment Location window, key in the proper server name for the Report Server. The format will be http://SERVER01/ReportServer. Also select a folder to publish the report into and click Next.

    10. Name the report on the final page and select the Preview Report checkbox at the bottom to have the report immediately generated.

    A quick snapshot of the layout page when you are done with a little applied formatting and spacing might look something like this:

    Creating a Report with Parameter Input

    Let’s say that you only want the drive space information for a single server instead of all servers. In order to accomplish that, you will need to add input parameters to the report. In the Solution Explorer, right click on the Reports folder and select Add New Report:

    Follow the previous steps to create the initial Data Source and configure the basics of the report. When finished, go to the Data tab of the new report and add a New Dataset.

    To create the query that will return the list of the servers which have collected performance data related to the Logical Drive Space rule, fill in the Query tab as follows using the SQL snippet below for the Query String (this list will later be used to populate a drop down to select the target parameter):

    SELECT DISTINCT UPPER(vManagedEntity.Name) AS Name
    FROM	Perf.vPerfHourly AS vPerf INNER JOIN
    	vPerformanceRuleInstance ON vPerformanceRuleInstance.PerformanceRuleInstanceRowId = vPerf.PerformanceRuleInstanceRowId INNER JOIN
    	vManagedEntity ON vPerf.ManagedEntityRowId = vManagedEntity.ManagedEntityRowId INNER JOIN
    	vPerformanceRule ON vPerformanceRuleInstance.RuleRowId = vPerformanceRule.RuleRowId
    WHERE	(vPerformanceRule.CounterName IN ('TotalCapacity')) AND (vPerformanceRuleInstance.InstanceName LIKE '%:')    
    ORDER BY UPPER(vManagedEntity.Name)

    Click OK to create the Dataset. Next, create an additional Dataset that will be used to query the DW using the select server as the parameter in the same manner. In the Name field put in something relevant like OpsMgrDWbyName and then use the following SQL snippet for the Query String:

    SELECT	vPerf.DateTime,  vPerf.AverageValue, vPerformanceRuleInstance.InstanceName,
    	vManagedEntity.Name,  vPerformanceRule.CounterName
    FROM	Perf.vPerfHourly AS vPerf INNER JOIN
    	vPerformanceRuleInstance ON vPerformanceRuleInstance.PerformanceRuleInstanceRowId = vPerf.PerformanceRuleInstanceRowId INNER JOIN
    	vManagedEntity ON vPerf.ManagedEntityRowId = vManagedEntity.ManagedEntityRowId INNER JOIN
    	vPerformanceRule ON vPerformanceRuleInstance.RuleRowId = vPerformanceRule.RuleRowId
    WHERE	(vPerformanceRule.CounterName IN ('TotalCapacity')) AND (vPerformanceRuleInstance.InstanceName LIKE '%:') AND (vPerf.DateTime > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)) AND  ( vManagedEntity.Name = @servername)
    	OR
    	(vPerformanceRule.CounterName IN ('FreeSpace')) AND (vPerformanceRuleInstance.InstanceName LIKE '%:') AND (vPerf.DateTime > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0))AND  ( vManagedEntity.Name = @servername)
    	OR
    	(vPerformanceRule.CounterName IN ('UsedSpace')) AND (vPerformanceRuleInstance.InstanceName LIKE '%:') AND (vPerf.DateTime > DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0))AND  ( vManagedEntity.Name = @servername)
    ORDER BY vManagedEntity.Name, vPerformanceRuleInstance.InstanceName,  vPerformanceRule.CounterName DESC

    Select the Fields tab and fill in the fields as follows:

    Move over to the Parameters tab and verify that it columns look as follows:

    These should auto populate from the query entered in the Query tab, but if nothing appears here you can populate the columns by keying in @servername into the Name column and then clicking the dropdown in the Value column. Select Edit Expression and then select Parameters in the left hand column. This will bring up a third column on the right with the servername parameter. From here, simply click OK to enter the proper value into the field. No other tabs need to be modified, so click OK to create the third DataSet.

    We now need to configure the parameters within the report itself so that when the report is run, the user has a way to actually select the specific server they want to run the report against. To accomplish this, select the Layout tab from the main design window in Business Intelligence Development Studio. You should see the graphical representation of the report in a design format. Right click anywhere in the empty space outside the report design inside the Layout tab and select Report Parameters. Fill out the properties page as follows:

    To clean up the output of the report a little, let’s change some of the column names to friendlier names and expand some column widths. This is something you’ll need to play with a little, but a basic example of final result might look something like this:

    You may also want to format the output of the Size column (or Average if you haven’t changed the name) so that the data is rounded out to two decimal places. To do this, right click the field that starts with =FormatNumber and select Expression from the menu. Paste the following into the expression window to clean up the output when the report is run:

    =FormatNumber(Fields!AverageValue.Value, 2) & ” GB”

    A good resource for understanding editing expressions can be found at http://msdn.microsoft.com/en-us/library/ms159238.aspx.

    Now that the report is done, it needs to be deployed to the Reporting Server. To do this, simply right click on the solution name in the Solution Explorer (top level of the tree) and select Deploy.

    Rather than extend this already long post with examples of publishing to SharePoint, I’ll just point you to the link here on the OpsMgr Team Blog. It’s a very simple process with only a few steps.

    While this and the previous post are fairly rudimentary examples of how you can collect data and effectively report on it, I hope they mainly served as a basic walkthrough of the entire process which can be extended to fit your personal needs for custom data collection and reporting in Operations Manager 2007.