This is an updated version of GreenMachine that works better on SCOM 2012 and SCOM 2012 R2
Minor update. Added the ability to filter by groups using the -group option.
Example command line:
The group must contain objects of the class we are scanning. So, if you use -class microsoft.unix.computer, with -group, the group must contain microsoft.unix.computer objects.
Also contained in this release is the full source code.
Note: Subgroups are not supported.
V1.03 Changes:
- Minor bug fixes
- Cleaned up -h output
- Added the ability to specify the friendly name of a class with the -class option
- Will now scan the top node of a monitor
- Also displays if a monitor is in MM (and the -i option can be used to scan monitors in MM)
Kevin Holman had some great feature requests, and a few others were gettings this error when attempting to run against an R2 RTM server:
Unhandled Exception: System.ArgumentOutOfRangeException: MonitoringObjectCriteria cannot be applied to an abstract class.Parameter name: monitoringClass at Microsoft.EnterpriseManagement.Monitoring.MonitoringObjectCriteria..ctor(String criteria, MonitoringClass monitoringClass) at GreenMachine.Program.Main(String[] args)
I have completly re-worked this part of the code, and now offer a couple new command line switches.
-class <Class to Scan>
The old version it was only possible to scan the Microsoft.Windows.Computer. In this version, any class, such as Microsoft.Unix.Computer, or Microsoft.SystemCenter.HealthService can be used.
The other option is -i, which will ignore the state of the object when scanning them. This is the only way to recursively scan objects in an Unmonitored state.
Should work on SP1, and definately works on R2 RTM!
No code changes were made, but this was re-compiled against R2 dll's.
If you try to run the old version on an R2 server, it will fail in non-obvious ways. Here is the re-compiled version.
GreenMachine is an OpsMgr Utility that can be used to reset or recalculate all monitors for a single agent, or for all agents in your management group.
Command line tool that facilitates bulk reset of health monitors.
This can be very useful if you just had an event storm, and you want to reset everything back to "green". It also has the ability to identify "ManualReset" monitors, and reset or recalculate only them.
It displays most of the same data as healthexplorer, as well as some additional information.
DISCLAIMER:
Please evaluate in your test environment first! this solution is provided AS-IS, with no warranties and confers no rights. Use is subject to the terms specified at Microsoft.
Below is the command line arguments for the utility. I am also including the source code. This is NOT open source, and may not be reused without permission.
Command Line Usage: -q Quiet - print NO output -v Print verbose messages -r Reset the health of any monitors in an error or warning state Use this to reset the health of monitors
-rr Recalculate health of any monitors in an error or warning state Use this to recalculate the health of monitors. Can be used with -r Recalculate only works for monitors that have designed to be recalculated
-ra Reset or Recalculate ALL monitors. Only unit monitors are reset by default By default, only unit monitors are reset. Use this to reset all monitors. Including Aggregrate or Dependancy monitors that are in a Error or Warning state
-man Only Reset 'Manual Reset' monitors Some monitors are of a type of 'Manual Reset', for example, the Manual Reset Event log Detection monitor. This will check the type of each monitor, and only reset those of a 'Manual Reset' type. All other monitor types will be skipped, and not reset. Requires -r or -rr (also works with -v -all to identify monitors)
-d Debug -c Display last 3 state change events This will display the state change events for monitors in an error or warning state.
-M <RMS> Sets the name of the RMS to connect to Use this option to connect to a remote RMS. Requires OpsMgr DLL's are installed
-A <Agent> Scan only the agent name specified By default, we will scan all windows computer objects in the management group. You can specify a wildcard scan with -A. Similar to Select * where name like '%name%'
-w Scan for agents in a warning state By default, only agents in an ERROR state are scanned. Use -w to also scan warning
-s Scan for agents in a success state Same as -w, but for agents in a success state
-all Display all monitors for an agent (not just those in a warning or error state -all is noisy. Use this to show ALL monitors on a scanned agent. Including those in an Unitialized or Success state
-noresize Don't resize the console to 150 width by 50 height -bp, -bs, -bc, -ba Scan only a single tree: Performance, Security, Configuration, Availability
----- OpsMgr SDK Client Cache mode settings -- Experimental -- May help performance --- See msdn for ManagementGroupConnectionSettings() for documentation -cc Configuration cache mode (default) -cm Management packs cache mode -cn No caching
Below is the source code. The source is also included in the attached zip.
// todo:
// fix colors
// v.next: csv output, GUI, restructure
// Changelog:
// Version 1 - 14
// Did stuff
// Version 15
// Added debug statments
// Renamed dumpschild
// Added Cachemode command line options
// added -noresize
// Minor cleanup
// undocumented options:
// -level <x>
// -ba, -bs, -bp, -bc
// the above are used for scanning only 1 tree (like the Performance Tree (-bp))
// Version 16
// Hopefully Final version.
// added -ba -bs -bp -bc to -h
// Reports of broken -c
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Text;
using Microsoft.EnterpriseManagement;
using Microsoft.EnterpriseManagement.Monitoring;
using Microsoft.EnterpriseManagement.ConnectorFramework;
using Microsoft.EnterpriseManagement.Common;
using Microsoft.EnterpriseManagement.Configuration;
using Microsoft.EnterpriseManagement.Administration;
using System.Threading;
namespace GreenMachine
{
public class RecursiveMonitorSearch
const short LOG_NONE = -1;
const short LOG_OUTPUT = 0;
const short LOG_INFO = 1;
const short LOG_VERBOSE = 2;
const short LOG_DEBUG = 3;
internal ManagementGroup mgmtGroup = null;
internal bool bResetHealth = false;
internal bool bRecalcHealth = false;
internal bool bPrintVerbose = false;
internal bool bDisplayAll = false;
internal bool bState = false;
internal bool bResetMan = false;
internal bool bResetAll = false;
internal bool bPrintDebug = false;
internal bool bPrintInfo = true;
internal bool bPrintNone = false;
internal bool bConfigCache = true;
internal bool bMPCache = false;
internal bool bNoCache = false;
internal short sMaxLevel = 25;
internal bool bAllTrees = true;
internal bool bAvailabilityTree = false;
internal bool bSecurityTree = false;
internal bool bPerformanceTree = false;
internal bool bConfigurationTree = false;
internal int count = 0;
private ReadOnlyCollection<UnitMonitorType> UMtypes;
internal void ViewSettings()
print("bResetHealth=" + bResetHealth, LOG_INFO);
print("bRecalcHealth=" + bRecalcHealth, LOG_INFO);
print("bPrintVerbose=" + bPrintVerbose, LOG_INFO);
print("bState=" + bState, LOG_INFO);
print("bResetMan=" + bResetMan, LOG_INFO);
print("bResetAll=" + bResetAll, LOG_INFO);
print("bPrintDebug=" + bPrintDebug, LOG_INFO);
print("bPrintInfo=" + bPrintInfo, LOG_INFO);
print("bPrintNone=" + bPrintNone, LOG_INFO);
print("bConfigCache=" + bConfigCache, LOG_INFO);
print("bMPCache=" + bMPCache, LOG_INFO);
print("bNoCache=" + bNoCache, LOG_INFO);
print("mgmtGroup=" + mgmtGroup.Name, LOG_INFO);
print(" connected:" + mgmtGroup.IsConnected, LOG_INFO);
}
internal void About()
print("Starting GreenMachine v1.00.016 RC2!", LOG_OUTPUT, ConsoleColor.DarkGreen);
print("", LOG_OUTPUT);
print("Written by Tim Helton (timhe)", LOG_OUTPUT);
print("Portions written and testing by Charles Champion (cchamp)", LOG_OUTPUT);
print("Inspired by a discussion at the 2008 R2 Tap Event.", LOG_OUTPUT);
print("Shoutouts to the OpsMgr MVPs. Keep up the good work!", LOG_OUTPUT);
print("This utility is provided \"AS IS\" with no warranties, and confers no rights.", LOG_OUTPUT, ConsoleColor.White);
print("Use of included utilities are subject to the terms specified at", LOG_OUTPUT, ConsoleColor.White);
print("http://www.microsoft.com/info/cpyright.htm", LOG_OUTPUT, ConsoleColor.White);
internal void PrintSpecial(string Blank, bool avail, HealthState ErrorLevel, ManagementPackMonitor mon, string CIMDN, string MODN, string MCDN)
// Wrote this at the last minute for ultra-cool color coding.
// Looks hackish, but works.
if (bPrintNone) return;
ConsoleColor color = ConsoleColor.Gray;
Console.Write(Blank);
if (avail)
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("(+)");
else
Console.ForegroundColor = ConsoleColor.Gray;
Console.Write("(-)");
switch (ErrorLevel)
case HealthState.Error:
color = ConsoleColor.Red;
Console.ForegroundColor = color;
Console.Write("[E]");
break;
case HealthState.Warning:
color = ConsoleColor.Yellow;
Console.Write("[W]");
case HealthState.Success:
color = ConsoleColor.DarkGreen;
Console.Write("[S]");
case HealthState.Uninitialized:
color = ConsoleColor.Gray;
Console.Write("[ ]");
if (!avail) color = ConsoleColor.Gray;
if (mon is ManagementPackAggregateMonitor)
Console.ForegroundColor = ConsoleColor.Magenta;
Console.Write("{A} ");
if (mon is ManagementPackDependencyMonitor)
Console.ForegroundColor = ConsoleColor.Blue;
Console.Write("{D} ");
if (mon is ManagementPackUnitMonitor)
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("{U} ");
Console.Write(CIMDN);
Console.ForegroundColor = ConsoleColor.White;
Console.Write(" - ");
Console.Write(MODN);
Console.Write("(" + MCDN + ")\r\n");
Console.ResetColor();
internal void print(string output, int loglevel, ConsoleColor Color)
Console.ForegroundColor = Color;
print(output, loglevel);
internal void print(string output, int loglevel)
bool bPrint = true;
if (bPrintNone) bPrint = false;
switch (loglevel)
case LOG_NONE:
bPrint = false;
case LOG_OUTPUT:
case LOG_INFO:
if ((!bPrintInfo) && (!bPrintVerbose) && (!bPrintDebug)) bPrint = false;
case LOG_VERBOSE:
if ((!bPrintVerbose) && (!bPrintDebug)) bPrint = false;
case LOG_DEBUG:
if (!bPrintDebug) bPrint = false;
if (bPrint) Console.WriteLine(output);
// Connect to the Management group, and print out some useful information if verbose is set
internal void Usage()
print("Command Line Usage:", LOG_OUTPUT);
print("-q Quiet - print NO output", LOG_OUTPUT, ConsoleColor.White);
print("-v Print verbose messages", LOG_OUTPUT, ConsoleColor.White);
print("-r Reset the health of any monitors in an error or warning state", LOG_OUTPUT, ConsoleColor.White);
print(" Use this to reset the health of monitors", LOG_OUTPUT);
print("-rr Recalculate health of any monitors in an error or warning state", LOG_OUTPUT, ConsoleColor.White);
print(" Use this to recalculate the health of monitors. Can be used with -r", LOG_OUTPUT);
print(" Recalculate only works for monitors that have designed to be recalculated", LOG_OUTPUT);
print("-ra Reset or Recalculate ALL monitors. Only unit monitors are reset by default", LOG_OUTPUT, ConsoleColor.White);
print(" By default, only unit monitors are reset. Use this to reset all monitors.", LOG_OUTPUT);
print(" Including Aggregrate or Dependancy monitors that are in a Error or Warning state", LOG_OUTPUT);
print("-man Only Reset 'Manual Reset' monitors", LOG_OUTPUT, ConsoleColor.White);
print(" Some monitors are of a type of 'Manual Reset', for example, the Manual Reset Event log", LOG_OUTPUT);
print(" Detection monitor. This will check the type of each monitor, and only reset those of a", LOG_OUTPUT);
print(" 'Manual Reset' type. All other monitor types will be skipped, and not reset.", LOG_OUTPUT);
print(" Requires -r or -rr (also works with -v -all to identify monitors)", LOG_OUTPUT);
print("-d Debug", LOG_OUTPUT, ConsoleColor.White);
print("-c Display last 3 state change events", LOG_OUTPUT, ConsoleColor.White);
print(" This will display the state change events for monitors in an error or warning state.", LOG_OUTPUT);
print("-M <RMS> Sets the name of the RMS to connect to", LOG_OUTPUT, ConsoleColor.White);
print(" Use this option to connect to a remote RMS. Requires OpsMgr DLL's are installed", LOG_OUTPUT);
print("-A <Agent> Scan only the agent name specified", LOG_OUTPUT, ConsoleColor.White);
print(" By default, we will scan all windows computer objects in the management group.", LOG_OUTPUT);
print(" You can specify a wildcard scan with -A. Similar to Select * where name like '%name%'", LOG_OUTPUT);
print("-w Scan for agents in a warning state", LOG_OUTPUT, ConsoleColor.White);
print(" By default, only agents in an ERROR state are scanned. Use -w to also scan warning", LOG_OUTPUT);
print("-s Scan for agents in a success state", LOG_OUTPUT, ConsoleColor.White);
print(" Same as -w, but for agents in a success state", LOG_OUTPUT);
print("-all Display all monitors for an agent (not just those in a warning or error state", LOG_OUTPUT, ConsoleColor.White);
print(" -all is noisy. Use this to show ALL monitors on a scanned agent. Including those in", LOG_OUTPUT);
print(" a an Unitialized or Success state", LOG_OUTPUT);
print("-noresize Don't resize the console to 150 width by 50 height", LOG_OUTPUT,ConsoleColor.White);
print("-bp, -bs, -bc, -ba Scan only a single tree: Performance, Security, Configuration, Availability", LOG_OUTPUT, ConsoleColor.White);
print("----- OpsMgr SDK Client Cache mode settings -- Experimental -- May help performance ---", LOG_OUTPUT);
print("See msdn for ManagementGroupConnectionSettings() for documentation", LOG_OUTPUT);
print("-cc Configuration cache mode (default)", LOG_OUTPUT);
print("-cm Management packs cache mode", LOG_OUTPUT);
print("-cn No caching", LOG_OUTPUT);
internal void mgmtgroup(string MgmtGroupName)
try
ManagementGroupConnectionSettings mgSettings =
new ManagementGroupConnectionSettings(MgmtGroupName);
if (bConfigCache)
mgSettings.CacheMode = CacheMode.Configuration;
if (bMPCache)
mgSettings.CacheMode = CacheMode.ManagementPacks;
if (bNoCache)
mgSettings.CacheMode = CacheMode.None;
mgSettings.ServerName = MgmtGroupName;
//todo:
// Alternative Credentials:
// mgSettings.UserName = name;
// mgSettings.Domain = userDomain;
// mgSettings.Password = password;
print("Connecting to ManagementGroup " + MgmtGroupName, LOG_VERBOSE, ConsoleColor.White);
print("SDK Cache mode: " + mgSettings.CacheMode, LOG_VERBOSE, ConsoleColor.White);
mgmtGroup = ManagementGroup.Connect(mgSettings);
// mgmtGroup = ManagementGroup.Connect(MgmtGroupName);
catch (System.Exception e)
print(String.Format("Could not connect to {0}: " + e.Message, MgmtGroupName), LOG_INFO, ConsoleColor.Red);
mgmtGroup = null;
if (mgmtGroup != null)
print(string.Format("Connected to {0}!", MgmtGroupName), LOG_INFO, ConsoleColor.White);
print(string.Format("Management group: {0}", mgmtGroup.Name), LOG_VERBOSE);
print(string.Format("Product ID: {0}", mgmtGroup.ProductId), LOG_DEBUG);
print(string.Format("Version: {0}", mgmtGroup.Version), LOG_VERBOSE);
print(string.Format("SkuForLicense: {0} SkuForProduct: {1}", mgmtGroup.SkuForLicense, mgmtGroup.SkuForProduct), LOG_DEBUG);
print(string.Format("Time of Expiration: {0}", mgmtGroup.TimeOfExpiration), LOG_DEBUG);
print(string.Format("Management group ID: {0}", mgmtGroup.Id), LOG_DEBUG);
print(string.Format("Cache Settings: {0}", mgmtGroup.ConnectionSettings.CacheMode),LOG_DEBUG);
// Need a better place for this...
if (bResetMan)
print("Reset only manual enabled. Collecting Monitor Types", LOG_DEBUG);
UnitMonitorTypeCriteria criteriaUM = new UnitMonitorTypeCriteria("Name like '%ManualReset%'");
UMtypes = mgmtGroup.GetUnitMonitorTypes(criteriaUM);
print(string.Format("Not connected to {0}!", MgmtGroupName), LOG_INFO, ConsoleColor.Red);
internal void DumpStateChild(MonitoringHierarchyNode<MonitoringState> state, int level)
ExternalRollupMonitoringState eRollup;
print("Entering DumpStateChild() for " + state.Item.MonitorDisplayName + " Level: "+ level, LOG_DEBUG);
if (level > sMaxLevel) return;
// Hacked this in. Dirty but it works.
if (level == 2 && !bAllTrees)
switch (state.Item.MonitorDisplayName)
case "Configuration":
if (!bConfigurationTree) return;
case "Availability":
if (!bAvailabilityTree) return;
case "Performance":
if (!bPerformanceTree) return;
case "Security":
if (!bSecurityTree) return;
default:
return;
if (state.TotalChildNodeCount > 0)
foreach (MonitoringHierarchyNode<MonitoringState> child in state.ChildNodes)
if (child != null)
printandreset(child, level);
if (state.Item is ExternalRollupMonitoringState)
print(state.Item.MonitorName + " is an ExternalRollupMonitorState item", LOG_DEBUG);
eRollup = state.Item as ExternalRollupMonitoringState;
if (eRollup != null)
List<MonitoringHierarchyNode<MonitoringState>> eStates = new List<MonitoringHierarchyNode<MonitoringState>>(eRollup.GetExternalMonitoringStateHierarchies());
if (eStates.Count > 0)
foreach (MonitoringHierarchyNode<MonitoringState> echild in eStates)
if (echild != null)
printandreset(echild, level);
internal void resetentry(MonitoringObject mo, int level)
print("Entering resetentry() for: " + mo.Name + " Level: " + level, LOG_DEBUG);
string Blank = "";
Blank = Blank.PadLeft((level) * 3);
if (mo.IsAvailable)
if (bResetHealth)
MonitoringTaskResult result = mo.ResetMonitoringState();
if (result != null)
print(string.Format(Blank + "ResetMonitoringState Result Id {0} on {1}: {2}", result.Id, mo.Name, result.Status), LOG_VERBOSE, ConsoleColor.White);
print(string.Format(Blank + "ResetMonitoringState failed for {0}", mo.Name), LOG_INFO, ConsoleColor.Red);
if (bRecalcHealth)
MonitoringTaskResult result = mo.RecalculateMonitoringState();
print(string.Format(Blank + "RecalculateMonitoringState Result Id {0} on {1}: {2}", result.Id, mo.Name, result.Status), LOG_VERBOSE, ConsoleColor.White);
print(string.Format(Blank + "RecalculateMonitoringState failed for {0}", mo.Name), LOG_INFO, ConsoleColor.Red);
else print(string.Format(Blank + "Not going to reset/recalulate offline monitor: {0}", mo.Name), LOG_VERBOSE, ConsoleColor.White);
internal void PrintStateChangeEvents(MonitoringHierarchyNode<MonitoringState> child, int level)
print("Entering PrintStateChangeEvents() for: " + child.Item.MonitorName + " Level: "+level, LOG_DEBUG);
int i = 1;
foreach (MonitoringStateChangeEvent mStateChangeEvent in child.Item.GetMonitoringStateChangeEvents())
// eh print up to three of the last state change events
if (i > child.Item.GetMonitoringStateChangeEvents().Count - 3)
if (mStateChangeEvent.Context != null)
print("mStateChangeEvent.Context = " + mStateChangeEvent.Context, LOG_DEBUG);
string mStateEventString = mStateChangeEvent.Context;
if (mStateEventString.ToLower().Contains("<context>")) // cheap and ugly
print(string.Format(Blank + " {0} - {1}: {2}", mStateChangeEvent.TimeAdded, mStateChangeEvent.NewHealthState, PullString(mStateEventString, "<context>", "</context>")), LOG_INFO, ConsoleColor.White);
else if (mStateEventString.ToLower().Contains("<param>"))
print(string.Format(Blank + " {0} - {1}: {2}", mStateChangeEvent.TimeAdded, mStateChangeEvent.NewHealthState, PullString(mStateEventString, "<param>", "</param>")), LOG_INFO, ConsoleColor.White);
print(string.Format(Blank + " {0} - {1}", mStateChangeEvent.TimeAdded, mStateChangeEvent.NewHealthState), LOG_INFO, ConsoleColor.White);
i++;
internal void printentry(MonitoringHierarchyNode<MonitoringState> child, int level)
print("Entering printentry() for: " + child.Item.MonitorName + " Level: " + level, LOG_DEBUG);
MonitoringClass mc = mgmtGroup.GetMonitoringClass(child.Item.MonitorTargetMonitoringClassId);
MonitoringObject mo = mgmtGroup.GetMonitoringObject(child.Item.MonitoringObjectId);
bool MonitorisManual = false;
ManagementPackMonitor mon = mgmtGroup.GetMonitor(child.Item.MonitorId);
PrintSpecial(Blank, mo.IsAvailable, child.Item.HealthState, mon, child.Item.MonitorDisplayName, mo.DisplayName, mc.DisplayName);
ManagementPackUnitMonitor monUM = mon as ManagementPackUnitMonitor;
foreach (UnitMonitorType UMtype in UMtypes)
if (monUM.TypeID != null)
if (UMtype.Id == monUM.TypeID.Id)
MonitorisManual = true;
print(Blank + "Monitor is a Manual reset monitor of type: " + UMtype.Name, LOG_VERBOSE, ConsoleColor.White);
if (child.Item.HealthState == HealthState.Warning || child.Item.HealthState == HealthState.Error)
if (bState)
PrintStateChangeEvents(child, level);
if ((mon is ManagementPackUnitMonitor) || bResetAll)
if ((bResetMan && MonitorisManual) || bResetMan == false)
resetentry(mo, level);
internal void printandreset(MonitoringHierarchyNode<MonitoringState> child, int level)
print("Entering printandreset() for item: " + child.Item.MonitorName + " Level: " + level, LOG_DEBUG);
if (bDisplayAll || child.Item.HealthState == HealthState.Error || child.Item.HealthState == HealthState.Warning)
printentry(child, level);
DumpStateChild(child, level + 1);
catch (ObjectNotFoundException)
print("ObjectNotFoundException caught in DumpStateChild()", LOG_DEBUG, ConsoleColor.Red);
static string PullString(string strSearchString, string strBeginString, string strEndString)
if (strBeginString.Length + strEndString.Length >= strSearchString.Length) return "";
int first = strSearchString.IndexOf(strBeginString, StringComparison.CurrentCultureIgnoreCase) + strBeginString.Length;
int last = strSearchString.LastIndexOf(strEndString, StringComparison.CurrentCultureIgnoreCase);
if ((last - first < 1) || (first < 0)) return "";
return strSearchString.Substring(first, last - first);
internal void legend()
print("Legend:", LOG_OUTPUT);
print("(-) = Monitor is not available (Gray)", LOG_OUTPUT, ConsoleColor.Gray);
print("(+) = Monitor is available (Green)", LOG_OUTPUT, ConsoleColor.Green);
print("[E] = Monitor is in an ERROR state", LOG_OUTPUT, ConsoleColor.Red);
print("[W] = Monitor is in an WARNING state", LOG_OUTPUT, ConsoleColor.Yellow);
print("[S] = Monitor is in an SUCCESS state", LOG_OUTPUT, ConsoleColor.DarkGreen);
print("[ ] = Monitor is in an UNINITIALIZED state", LOG_OUTPUT, ConsoleColor.Gray);
print("{A} = Monitor is an Aggregrate Monitor", LOG_OUTPUT, ConsoleColor.Magenta);
print("{D} = Monitor is a Dependancy Monitor", LOG_OUTPUT, ConsoleColor.Blue);
print("{U} = Monitor is an Unit Monitor", LOG_OUTPUT, ConsoleColor.Cyan);
print("-----------------------------------------------------", LOG_OUTPUT);
internal void DisplayMonitoringStateHierarchy(MonitoringObject mObject)
count++;
print("Entering DisplayMonitoringStateHierarchy() for item: " + mObject.Name + " Count: " + count, LOG_DEBUG);
print(string.Format("{0}: ", mObject.DisplayName), LOG_OUTPUT, ConsoleColor.White);
MonitoringHierarchyNode<MonitoringState> state = mObject.GetMonitoringStateHierarchy();
print(" Monitor: " + state.Item.MonitorDisplayName +
" - " + state.Item.HealthState.ToString(), LOG_OUTPUT, ConsoleColor.White);
print(" Description: " + state.Item.MonitorDescription, LOG_VERBOSE);
// Parent node information.
if (state.ParentNode != null)
print(" Parent node: " +
state.ParentNode.Item.MonitorDisplayName, LOG_VERBOSE);
DumpStateChild(state, 1);
class Program
static void Main(string[] args)
bool bScanError = true;
bool bScanWarning = false;
bool bScanSuccess = false;
string sMG = "localhost";
string sAgentName = null;
bool getMG = false;
bool scanall = true;
bool getAN = false;
bool resize = true;
bool mlevel = false;
// Need an option for this maybe?
//origWidth = Console.WindowWidth
//origHeight = Console.WindowHeight
RecursiveMonitorSearch hsod = new RecursiveMonitorSearch();
hsod.About();
foreach (string arg in Environment.GetCommandLineArgs())
if (arg == Environment.GetCommandLineArgs()[0]) continue;
if (getMG)
getMG = false;
sMG = arg;
hsod.print(string.Format("Management group set to {0}", sMG), LOG_VERBOSE);
continue;
if (getAN)
getAN = false;
scanall = false;
sAgentName = arg;
hsod.print(string.Format("Agent Name set to {0}", sAgentName), LOG_VERBOSE);
if (mlevel)
mlevel = false;
hsod.sMaxLevel = Convert.ToInt16( arg);
hsod.print(string.Format("Max Level set to {0}", hsod.sMaxLevel), LOG_VERBOSE);
switch (arg.ToLower())
case "-q":
hsod.bPrintNone = true;
hsod.print("Quiet mode activated", LOG_VERBOSE);
case "-v":
hsod.bPrintVerbose = true;
hsod.print("Verbose mode activated", LOG_VERBOSE);
case "-d":
hsod.bPrintDebug = true;
hsod.print("Debug mode activated -- sorta implemented", LOG_VERBOSE);
case "-r":
hsod.print("Reset Health mode activated.", LOG_VERBOSE);
hsod.bResetHealth = true;
case "-rr":
hsod.print("Recalculate Health mode activated.", LOG_VERBOSE);
hsod.bRecalcHealth = true;
case "-w":
hsod.print("Scanning for warning level agents enabled", LOG_VERBOSE);
bScanWarning = true;
case "-s":
hsod.print("Scanning for success level agents enabled", LOG_VERBOSE);
bScanSuccess = true;
case "-c":
hsod.print("Displaying State change events", LOG_VERBOSE);
hsod.bState = true;
case "-m":
getMG = true;
case "-a":
getAN = true;
case "-all":
hsod.print("Display all monitors set to true", LOG_VERBOSE);
hsod.bDisplayAll = true;
case "-man":
hsod.print("Only resetting Manual Reset Monitors set to true", LOG_VERBOSE);
hsod.bResetMan = true;
case "-ra":
hsod.print("Resetting/Recalcing all monitors instead of only unit monitors set to true", LOG_VERBOSE);
hsod.bResetAll = true;
case "-cm":
hsod.print("SDK Management pack Cache mode activated", LOG_VERBOSE);
hsod.bMPCache = true;
case "-cn":
hsod.print("SDK No cache option found", LOG_VERBOSE);
hsod.bNoCache = true;
case "-cc":
hsod.print("SDK Configuration Cache mode activated", LOG_VERBOSE);
hsod.bConfigCache = true;
case "-noresize":
hsod.print("Not resizing the window", LOG_VERBOSE);
resize = false;
case "-level":
hsod.print("max scan level enabled", LOG_VERBOSE);
mlevel = true;
case "-ba":
hsod.bAllTrees=false;
hsod.bAvailabilityTree=true;
hsod.print("Availability Tree Enabled",LOG_VERBOSE);
case "-bs":
hsod.bSecurityTree=true;
hsod.print("Security Tree Enabled",LOG_VERBOSE);
case "-bp":
hsod.bPerformanceTree=true;
hsod.print("Performance Tree Enabled",LOG_VERBOSE);
case "-bc":
hsod.bConfigurationTree=true;
hsod.print("Configuration Tree Enabled", LOG_VERBOSE);
case "-h":
hsod.Usage();
hsod.print(string.Format("Unknown command line option {0}", arg), LOG_OUTPUT);
hsod.print("", LOG_OUTPUT);
if (resize)
hsod.print(string.Format("Window settings: Max {0}x{1} Current {2}x{3}",Console.LargestWindowWidth,Console.LargestWindowHeight,Console.WindowWidth,Console.WindowHeight),LOG_DEBUG);
if (Console.LargestWindowHeight >= 50 && Console.LargestWindowWidth >= 150)
Console.SetWindowSize(150, 50);
ReadOnlyCollection<MonitoringObject> monitoringObjects;
MonitoringClass computerMonitoringClass;
MonitoringObjectCriteria criteria;
hsod.mgmtgroup(sMG);
if (hsod.mgmtGroup == null) return;
if (hsod.bPrintDebug) hsod.ViewSettings();
computerMonitoringClass = hsod.mgmtGroup.GetMonitoringClass(SystemMonitoringClass.WindowsComputer);
// criteria = new MonitoringObjectCriteria( string.Format("HealthState='{0}'", (int)HealthState.Error), computerMonitoringClass);
hsod.legend();
if (scanall)
criteria = new MonitoringObjectCriteria("", computerMonitoringClass);
else criteria = new MonitoringObjectCriteria("Name like '%" + sAgentName + "%'", computerMonitoringClass);
monitoringObjects = hsod.mgmtGroup.GetMonitoringObjects(criteria);
hsod.print(monitoringObjects.Count + " Monitoring objects found.", LOG_INFO);
foreach (MonitoringObject monitoringObject in monitoringObjects)
hsod.print(string.Format("Agent {0} is in a state of {1}", monitoringObject.DisplayName, monitoringObject.HealthState), LOG_VERBOSE);
switch (monitoringObject.HealthState)
if (bScanError) hsod.DisplayMonitoringStateHierarchy(monitoringObject);
if (bScanWarning) hsod.DisplayMonitoringStateHierarchy(monitoringObject);
if (bScanSuccess) hsod.DisplayMonitoringStateHierarchy(monitoringObject);
hsod.print(string.Format("Not Scanning: {0} which in a state of {1}", monitoringObject.DisplayName, monitoringObject.HealthState), LOG_VERBOSE, ConsoleColor.White);
hsod.print(hsod.count + " Monitoring objects scanned.", LOG_INFO);
Keywords:
Greenmachine timhe "reset monitor" "recalc monitors" "recalculate monitor" "reset manual monitor" OpsMgr OperationsManager SCOM
I wrote this script to demonstrate some of the new scripting techniques in SCOM, and to remedy a problem I noticed when monitoring logical disk counters.
The default rule included in SCOM will perform an AND query for "% Free Space", and "Free Megabytes". There is no easy method to monitor just one counter of these values.
Install this script as a timed rule in scom. Target it to something like windows servers or windows computers.
The script will generate up to 4 events in the Operations Manager log:
10111 - Warning - Warning Threshold for MB Free has been reached
10111 - Error - Error Threshold for MB Free has been reached
10112 - Warning - Warning Threshold for % Disk Free has been reached
10112 - Error - Error Threshold for % Disk Free has been reached
The script takes up to 5 parameters:
Example: Diskspace.vbs 2000 4000 5 10 1
1st param - Error condition for MB free. This will trigger the 10111 Error Event
2nd Param - Warning Condition for MB free. This will trigger the 10111 Warning Event
3rd Param - Error condition for % free. This will trigger the 10112 Error Event
4th Param - Warning condition for % free. This will trigger the 10112 Warning Event
5th Param - Enable Debug logging. This param is optional. Log defaults to C:\temp\diskspace.log (Note: The scripts checks for the presence of the 5th parameter to enable logging. Changing it to a "0" has no effect)
Here's an example of what the event log text looks like:
Diskspace.vbs : Drive C: has 1403.79MB(11.43%) out of 12284.08MB Free [Alert on: 2000MB Free]
You can use the $Data/EventDescription$ variable in your alert rule to get this information
Also see this link for more information on scripting for SCOM
http://www.systemcenterforum.org/using-property-bags-with-custom-scripting-in-operations-manager-2007/
===============
Const HARD_DISK = 3
Dim AlertSizeinMB
Dim AlertPercent
Dim SpaceinMB
Dim SizeinMB
Dim PercentFree
Dim StrComputer
Dim Logging
Dim oAPI,oArgs
Set oAPI = CreateObject("MOM.ScriptAPI")
Set oArgs = WScript.Arguments
if oArgs.Count < 4 Then
WriteLog ("Argument Error")
DumpInfo()
Call oApi.LogScriptEvent ("Diskspace.vbs",101,1, "Diskspace.vbs script was called with less than 4 arguments")
Wscript.Quit -1
End If
Logging = 0
if oArgs.Count = 5 then
Logging = 1
'1st Arg Error Size in MB
'2nd Arg Warning Size in MB
'3rd Arg Error Size in %
'4th Arg Warning Size in %
'If the 5th Argument exists, turn on logging to C:\temp\diskspace.log
AlertSizeinMB_ERR = oArgs(0)
AlertSizeinMB_WARN = oArgs(1)
AlertPercent_ERR = oArgs(2)
AlertPercent_WARN = oArgs(3)
WriteLog ("Script Startup V3.02")
WriteLog ("AlertSize in MB = " & AlertSizeinMB_ERR & " Alert Percent = " & AlertPercent_ERR)
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colDisks = objWMIService.ExecQuery _
("Select * from Win32_LogicalDisk Where DriveType = " & HARD_DISK & "")
WriteLog ("WMI Query Complete on " & strComputer )
For Each objDisk in colDisks
SpaceinMB=round (objDisk.FreeSpace/1024/1024,2)
SizeinMB=round (objDisk.Size/1024/1024,2)
WriteLog("SizeinMB: " & SizeinMB & " SPaceinMB: " & SpaceinMB)
PercentFree=round(((objDisk.FreeSpace / objDisk.Size) * 100),2)
WriteLog("Percent Free: " & PercentFree)
if (SpaceinMB < round(AlertSizeinMB_ERR) ) then
WriteLog ("SpaceinMB: " & SpaceinMB & " < " & "AlertSizeinMB: " & AlertSizeinMB_ERR & " 10111")
WriteLog ("Drive " & objDisk.DeviceID & " has " & SpaceinMB & "MB" & "("& PercentFree & "%) out of " & SizeinMB & "MB Free [Error Alert on: " & AlertSizeinMB_ERR & "MB Free]")
Call oApi.LogScriptEvent ("Diskspace.vbs",10111,1, "Drive " & objDisk.DeviceID & " has " & SpaceinMB & "MB" & "("& PercentFree & "%) out of " & SizeinMB & "MB Free [Error Alert on: " & AlertSizeinMB_ERR & "MB Free]")
elseif (SpaceinMB < round(AlertSizeinMB_WARN) ) then
WriteLog ("SpaceinMB: " & SpaceinMB & " < " & "AlertSizeinMB: " & AlertSizeinMB_WARN & " 10111")
WriteLog ("Drive " & objDisk.DeviceID & " has " & SpaceinMB & "MB" & "("& PercentFree & "%) out of " & SizeinMB & "MB Free [Warning Alert on: " & AlertSizeinMB_WARN & "MB Free]")
Call oApi.LogScriptEvent ("Diskspace.vbs",10111,2, "Drive " & objDisk.DeviceID & " has " & SpaceinMB & "MB" & "("& PercentFree & "%) out of " & SizeinMB & "MB Free [Warning Alert on: " & AlertSizeinMB_WARN & "MB Free]")
if (PercentFree < round(AlertPercent_ERR) ) then
WriteLog("PercentFree < AlertPercent_ERR 10112")
WriteLog ("Drive " & objDisk.DeviceID & " has " & SpaceinMB & "MB" & "("& PercentFree & "%) out of " & SizeinMB & "MB Free [Error Alert on: " & AlertPercent_ERR & "%]")
Call oApi.LogScriptEvent ("Diskspace.vbs",10112,1, "Drive " & objDisk.DeviceID & " has " & SpaceinMB & "MB" & "("& PercentFree & "%) out of " & SizeinMB & "MB Free [Error Alert on: " & AlertPercent_ERR & "%]")
elseif (PercentFree < round(AlertPercent_WARN) ) then
WriteLog("PercentFree < AlertPercent_WARN 10112")
WriteLog ("Drive " & objDisk.DeviceID & " has " & SpaceinMB & "MB" & "("& PercentFree & "%) out of " & SizeinMB & "MB Free [Warning Alert on: " & AlertPercent_WARN & "%]")
Call oApi.LogScriptEvent ("Diskspace.vbs",10112,2, "Drive " & objDisk.DeviceID & " has " & SpaceinMB & "MB" & "("& PercentFree & "%) out of " & SizeinMB & "MB Free [Warning Alert on: " & AlertPercent_WARN & "%]")
Next
WriteLog ("Script Ended")
Function WriteLog (strLogText)
Dim objfs
Dim objf
Dim strTimeStamp
Dim FileName
if ( Logging = 1 ) then
Filename = "c:\temp\diskspace.log"
On Error Resume Next
Err.Clear
Set objfs = CreateObject("Scripting.FileSystemObject")
Set objf = objfs.OpentextFile(FileName, 8, False)
' If log file doesn't exist - create it
If Err.Number <> 0 Then
Set objf = objfs.CreatetextFile(FileName, False)
strTimeStamp = "[" & Date & " " & Time & "] "
objf.WriteLine(strTimeStamp & strLogText)
Set objfs = Nothing
Set objf = Nothing
End Function
Function DumpInfo()
WriteLog "--- Beginning DumpInfo()"
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem",,48)
For Each objItem in colItems
WriteLog "Computer Name: " & objItem.CSName & " " & objItem.Caption & "SP "& objItem.ServicePackMajorVersion & "." & objItem.ServicePackMinorVersion & " (" & objItem.Version & ")"
next
Set colItems = objWMIService.ExecQuery("Select * from Win32_Process",,48)
WriteLog "== PID: " & objItem.ProcessId & " " & objItem.Name & " ++ Parent PID: " & objItem.ParentProcessId
if objItem.CommandLine <> "" then WriteLog "--- CommandLine: " & objItem.CommandLine
if objItem.ExecutablePath <> "" then if objItem.ExecutablePath <> objItem.CommandLine then Writelog "--- ExecutablePath: " & objItem.ExecutablePath
WriteLog "--- Exiting DumpInfo()"
Howto create a generic text log (alert)
From Authoring, right click on "rules", and select "Create a new rule..."
Select "Generic Text Log (Alert)", and your target management pack
Enter the rule name, and description. Hit Select to pick a target.
In this case, I am selecting the "Windows Server" Target.
Enter the location of the log. If you expect the log file to change names (ie test07072007.log), you could use something like test*.log. This pattern should only match 1 active log at a time
On the next screen, enter in "Params/Param[1]" into the Parameter box. For operator, enter what you need, I used "Matches wildcard" in this example.. For value, enter the text you are looking for.
Modify your alert priority/severity and description, then click create.