Microsoft.Exchange.2010.ServerRole.RegistryDiscoveryDS (DataSourceModuleType)

Element properties:

TypeDataSourceModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
OutputTypeSystem.Discovery.Data

Member Modules:

ID Module Type TypeId RunAs 
DS DataSource Microsoft.Windows.Discovery.RegistryProvider Default
Script ProbeAction Microsoft.Windows.ScriptDiscoveryProbe Default

Overrideable Parameters:

IDParameterTypeSelector
IntervalSecondsint$Config/IntervalSeconds$
VerboseLoggingbool$Config/VerboseLogging$
StartDelaySecondsint$Config/StartDelaySeconds$

Source Code:

<DataSourceModuleType ID="Microsoft.Exchange.2010.ServerRole.RegistryDiscoveryDS" Accessibility="Internal" Batching="false">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="RoleName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="IntervalSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ClassId" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="VerboseLogging" type="xsd:boolean"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="StartDelaySeconds" type="xsd:integer"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int"/>
<OverrideableParameter ID="VerboseLogging" Selector="$Config/VerboseLogging$" ParameterType="bool"/>
<OverrideableParameter ID="StartDelaySeconds" Selector="$Config/StartDelaySeconds$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<DataSource ID="DS" TypeID="Windows!Microsoft.Windows.Discovery.RegistryProvider">
<ComputerName>\\$Target/Property[Type='Windows!Microsoft.Windows.Computer']/PrincipalName$</ComputerName>
<RegistryAttributeDefinitions>
<RegistryAttributeDefinition>
<AttributeName>Version</AttributeName>
<Path>SOFTWARE\Microsoft\ExchangeServer\v14\$Config/RoleName$Role\ConfiguredVersion</Path>
<PathType>1</PathType>
<AttributeType>1</AttributeType>
</RegistryAttributeDefinition>
<RegistryAttributeDefinition>
<AttributeName>InstallPath</AttributeName>
<Path>SOFTWARE\Microsoft\ExchangeServer\v14\Setup\MsiInstallPath</Path>
<PathType>1</PathType>
<AttributeType>1</AttributeType>
</RegistryAttributeDefinition>
</RegistryAttributeDefinitions>
<Frequency>$Config/IntervalSeconds$</Frequency>
</DataSource>
<ProbeAction ID="Script" TypeID="Windows!Microsoft.Windows.ScriptDiscoveryProbe">
<ScriptName>MicrosoftExchangeServerRoleDiscovery.js</ScriptName>
<Arguments>0 $MPElement$ $Target/Id$ $Config/ClassId$ $Config/RoleName$ $Target/Property[Type='Windows!Microsoft.Windows.Computer']/PrincipalName$ "$Target/Property[Type='Windows!Microsoft.Windows.Computer']/NetbiosComputerName$" "$Target/Property[Type='Windows!Microsoft.Windows.Computer']/ActiveDirectorySite$" "$Target/Property[Type='Windows!Microsoft.Windows.Computer']/DNSName$" "$Data/Values/Version$" "$Data/Values/InstallPath$" "$Target/Property[Type='Windows!Microsoft.Windows.Server.Computer']/IsVirtualNode$" "$Config/VerboseLogging$" "$Config/StartDelaySeconds$"</Arguments>
<ScriptBody><Script>
// ----------------------------------------------------------------------
// Script to discover Exchange 2010 role entities.
// ----------------------------------------------------------------------

var EXPECTED_ARGUMENT_COUNT = 14;
var UNEXPECTED_ARGUMENT_COUNT_ERROR_ID = 101;
var INVALID_ARGUMENT_VALUE_WARNING_ID = 105;
var FILE_CREATION_WARNING_ID = 106;

var DISCOVERY_STARTED_INF_ID = 1470;
var DISCOVERY_ENDED_INF_ID = 1471;
var DISCOVERY_PROGRESS_INF_ID = 1472;

var EVENT_SOURCE = "MicrosoftExchangeServerRoleDiscovery.js";
var EVENT_TYPE_ERROR = 1;
var EVENT_TYPE_WARNING = 2;
var EVENT_TYPE_INFORMATION = 4;

var oAPI = new ActiveXObject("Mom.ScriptAPI");

var argumentsStr = "";
for (var i = 0; i &lt; WScript.Arguments.length; i++)
{
argumentsStr = argumentsStr.concat("\"", WScript.Arguments(i), "\" ");
}

if (WScript.Arguments.length != EXPECTED_ARGUMENT_COUNT)
{
oAPI.LogScriptEvent(
EVENT_SOURCE,
UNEXPECTED_ARGUMENT_COUNT_ERROR_ID,
EVENT_TYPE_ERROR,
"Expected " + EXPECTED_ARGUMENT_COUNT + " arguments. But there were " + WScript.Arguments.length + " arguments. Exiting script.\n Arguments: " + argumentsStr);

WScript.Quit(-1);
}

var sourceType = WScript.Arguments(0);
var sourceId = WScript.Arguments(1);
var managedEntityId = WScript.Arguments(2);
var classId = WScript.Arguments(3);
var roleName = WScript.Arguments(4);
var computerPrincipalName = WScript.Arguments(5);
var computerNetbiosName = WScript.Arguments(6);
var computerActiveDirectorySite = WScript.Arguments(7);
var computerDnsName = WScript.Arguments(8);
var version = WScript.Arguments(9);
var installPath = WScript.Arguments(10);
var isVirtualNodeString = WScript.Arguments(11);
var verboseLoggingString = WScript.Arguments(12);
var startDelaySeconds = WScript.Arguments(13);

// Convert cluster related variables from string to bool.
var isVirtualNode = (isVirtualNodeString.toLowerCase() == "true") ? true : false;
var verboseLogging = (verboseLoggingString.toLowerCase() == "true") ? true : false;

var infoOutput = "Role Discovery script \n"
+ " roleName: " + roleName + "\n"
+ " computerNetbiosName: " + computerNetbiosName + "\n"
+ " Message: ";

function main()
{
LogEvent(DISCOVERY_STARTED_INF_ID, EVENT_TYPE_INFORMATION, infoOutput + "Role Discovery Script started.\n Arguments: " + argumentsStr);

// StartDelaySeconds
LogEvent(DISCOVERY_PROGRESS_INF_ID, EVENT_TYPE_INFORMATION, infoOutput + "Sleeping for " + startDelaySeconds + " seconds.");
WScript.Sleep(startDelaySeconds*1000);

var discoveryData = oAPI.CreateDiscoveryData(sourceType, sourceId, managedEntityId);

// ----------------------------------------------------------------------
// First, let's do a check to:
//
// 1) Check key computer properties to skip malformed entities from MOM (it does happen).
//
// 2) Exclude computers without DNSName (i.e. a Cluster Name that gets discovered
// by MOMv3 as a Windows Server but it is NOT the virtual server we want to monitor).
//
// 3) Prevent creating server roles on a virtual nodes.
//
// 4) Ensure Exchange is installed and is the version we expected.
// ----------------------------------------------------------------------
//
if ((computerPrincipalName.length == 0) ||
(computerNetbiosName.length == 0) ||
((roleName != "EdgeTransport" ) &amp;&amp; (computerActiveDirectorySite.length == 0)) ||
(computerDnsName.length == 0) ||
isVirtualNode ||
!((installPath.length &gt; 0) &amp;&amp; version.match("^14(\.[0-9]+){3}$")))
{
LogEvent(
INVALID_ARGUMENT_VALUE_WARNING_ID,
EVENT_TYPE_ERROR,
"Cannot discover '" + roleName + "'. " +
"One or more key arguments contain invalid values:\n" +
" computerPrincipalName: " + computerPrincipalName + "\n" +
" computerNetbiosName: " + computerNetbiosName + "\n" +
" computerActiveDirectorySite: " + computerActiveDirectorySite + "\n" +
" computerDnsName: " + computerDnsName + "\n" +
" installPath: " + installPath + "\n" +
" version: " + version + "\n" +
"Exiting the discovery."
);

// Even if the discovery isn't met we still have to return an empty object,
// the script module must output a System.Discovery.Data object as expected by the discovery workflow,
// otherwise a warning event is logged by MOMv3.
oAPI.Return(discoveryData);
return;
}

ProcessCapacityThresholds();

LogEvent(DISCOVERY_PROGRESS_INF_ID, EVENT_TYPE_INFORMATION, infoOutput + "Getting CPU and IO capacities.");

// IO Capacity Maximum value to be uploaded to the MOM database
var ioMaximum = GetCapacityMaximumForIO();

// CPU Capacity Maximum value to be uploaded to the MOM database
var cpuMaximum = GetCapacityMaximumForCPU();

LogEvent(DISCOVERY_PROGRESS_INF_ID, EVENT_TYPE_INFORMATION, infoOutput + "CPU capacity = " + cpuMaximum + ", IO capacity = " + ioMaximum);

LogEvent(DISCOVERY_PROGRESS_INF_ID, EVENT_TYPE_INFORMATION, infoOutput + "Creating Microsoft.Exchange.2010.Server class instance");
// Create Microsoft.Exchange.2010.Server class instance.
var oExchangeServer = discoveryData.CreateClassInstance("$MPElement[Name='Microsoft.Exchange.2010.Server']$");
oExchangeServer.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.Server']/PrincipalName$", computerPrincipalName);
oExchangeServer.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.Server']/NetbiosName$", computerNetbiosName);
oExchangeServer.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.Server']/DnsName$", computerDnsName);
oExchangeServer.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.Server']/ActiveDirectorySite$", computerActiveDirectorySite);
oExchangeServer.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.Server']/MaximumIops$", ioMaximum);
oExchangeServer.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.Server']/MaximumCpu$", cpuMaximum);
discoveryData.AddInstance(oExchangeServer);

// ----------------------------------------------------------------------
// Create the ServerRole instance and populate its properties.
// ----------------------------------------------------------------------
//
// Construct the ServerRole class's Name key property.
var roleDisplayName = "";
if (classId == "$MPElement[Name='Microsoft.Exchange.2010.ClientAccessRole']$")
{
roleDisplayName = "Client Access";
}
else if (classId == "$MPElement[Name='Microsoft.Exchange.2010.EdgeTransportRole']$")
{
roleDisplayName = "Edge Transport";
}
else if (classId == "$MPElement[Name='Microsoft.Exchange.2010.HubTransportRole']$")
{
roleDisplayName = "Hub Transport";
}
else if (classId == "$MPElement[Name='Microsoft.Exchange.2010.MailboxRole']$")
{
roleDisplayName = "Mailbox";
}
else if (classId == "$MPElement[Name='Microsoft.Exchange.2010.UnifiedMessagingRole']$")
{
roleDisplayName = "Unified Messaging";
}

var serverRoleName = computerNetbiosName + " (" + roleDisplayName + ")";

if( computerActiveDirectorySite != "" )
{
serverRoleName = serverRoleName.concat(" - ", computerActiveDirectorySite);
}

var syncTimeBasedOnComputerName = GetSyncTime(computerNetbiosName);
var cmdletSyncTimeBasedOnComputerName = GetCmdletSyncTime(computerNetbiosName);

LogEvent(DISCOVERY_PROGRESS_INF_ID, EVENT_TYPE_INFORMATION, infoOutput + "Creating the ServerRole instance.");

// Create the ServerRole instance.
var oServerRole = discoveryData.CreateClassInstance(classId);
oServerRole.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", computerPrincipalName);
oServerRole.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.ServerRole']/RoleName$", serverRoleName);
oServerRole.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.ServerRole']/Version$", version);
oServerRole.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.ServerRole']/InstallPath$", installPath);
oServerRole.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.ServerRole']/SyncTime$", syncTimeBasedOnComputerName);
oServerRole.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.ServerRole']/CmdletSyncTime$", cmdletSyncTimeBasedOnComputerName);

// Discover additional cluster related properties for MailboxRole.
//
if (classId == "$MPElement[Name='Microsoft.Exchange.2010.MailboxRole']$")
{
oServerRole.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.MailboxRole']/IsVirtualServer$", isVirtualNode);
}
discoveryData.AddInstance(oServerRole);


// ----------------------------------------------------------------------
// Create the CommonRole instance and populate its properties.
// ----------------------------------------------------------------------
//
// Construct the CommonRole class's Name key property.
var commonRoleName = computerNetbiosName + " (Common)";

if( computerActiveDirectorySite != "" ){
commonRoleName = commonRoleName.concat(" - ", computerActiveDirectorySite);
}

LogEvent(DISCOVERY_PROGRESS_INF_ID, EVENT_TYPE_INFORMATION, infoOutput + "Constructing the CommonRole class's Name key property.");

// Create the CommonRole instance.
var oCommonRole = discoveryData.CreateClassInstance("$MPElement[Name='Microsoft.Exchange.2010.CommonRole']$");
oCommonRole.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", computerPrincipalName);
oCommonRole.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.ServerRole']/RoleName$", commonRoleName);
oCommonRole.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.ServerRole']/SyncTime$", syncTimeBasedOnComputerName);
oCommonRole.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.ServerRole']/CmdletSyncTime$", cmdletSyncTimeBasedOnComputerName);
oCommonRole.AddProperty("$MPElement[Name='Microsoft.Exchange.2010.ServerRole']/InstallPath$", installPath);
discoveryData.AddInstance(oCommonRole);

// Create containment relationship between Microsoft.Exchange.2010.Server and ServerRole
LogEvent(DISCOVERY_PROGRESS_INF_ID, EVENT_TYPE_INFORMATION, infoOutput + "Creating relationships.");
var oExchangeServerContainsServerRole = discoveryData.CreateRelationshipInstance("$MPElement[Name='Microsoft.Exchange.2010.Server.Contains.Microsoft.Exchange.2010.ServerRole']$");
oExchangeServerContainsServerRole.Source = oExchangeServer;
oExchangeServerContainsServerRole.Target = oServerRole;
discoveryData.AddInstance(oExchangeServerContainsServerRole);

// Create containment relationship between Microsoft.Exchange.2010.Server and CommonRole
var oExchangeServerContainsCommonRole = discoveryData.CreateRelationshipInstance("$MPElement[Name='Microsoft.Exchange.2010.Server.Contains.Microsoft.Exchange.2010.ServerRole']$");
oExchangeServerContainsCommonRole.Source = oExchangeServer;
oExchangeServerContainsCommonRole.Target = oCommonRole;
discoveryData.AddInstance(oExchangeServerContainsCommonRole);

LogEvent(DISCOVERY_PROGRESS_INF_ID, EVENT_TYPE_INFORMATION, infoOutput + "Submitting discovery data to OpsMgr.");
oAPI.Return(discoveryData);

LogEvent(DISCOVERY_ENDED_INF_ID, EVENT_TYPE_INFORMATION, infoOutput + "Exiting RoleDiscovery." );
}

// Gets a deterministic SyncTime based on the name of the computer.
// SyncTime is used to control the start time of MOM modules,
// such as that of a collection rule.
// By using a distinct SyncTime for individual machines,
// we could reduce the load on the AD from intensive modules
// such as those based on scripts with many AD queries.
//
function GetSyncTime(computerName)
{
if (null == computerName)
return "00:00";

computerName = computerName.toString();

if (computerName.length == 0)
return "00:00";

// Finds the first occurrence of a single-digit number starting from the end of the name.
//
var firstSignificantDigit = 0;
for (var i = (computerName.length - 1); i &gt;= 0; i--)
{
var testChar = computerName.charAt(i);

if (!isNaN(testChar))
{
firstSignificantDigit = parseInt(testChar, 10); // Convert a 10-based number.
break;
}
}

switch (firstSignificantDigit)
{
case 0:
return "00:00";
case 1:
return "00:15";
case 2:
return "00:30";
case 3:
return "00:45";
case 4:
return "01:00";
case 5:
return "01:15";
case 6:
return "01:30";
case 7:
return "01:45";
case 8:
return "02:00";
case 9:
return "02:15";
default:
return "00:00";
}
}

// The output value is in format "hh:mm" with leading zeros.
// Parameter "totalMinutes" - is time expressed in minutes.
function ConvertMinutesToTime(totalMinutes) {
var wholeHours = Number(Math.floor(totalMinutes / 60)).toFixed(0);
if (wholeHours.length == 1)
wholeHours = "0" + wholeHours; // Add a leading zero.

var remaindingMinutes = Number(totalMinutes % 60).toFixed(0);
if (remaindingMinutes.length == 1)
remaindingMinutes = "0" + remaindingMinutes; // Add a leading zero.

// Convert to a string of format "hh:mm";
return wholeHours + ":" + remaindingMinutes;
}

// Hash-iterating Function.
// Returns new hash state for given previous state "s" and next word "b".
function Hash(s, b) {
if ((128 &amp; s) == 0)
return Math.round(Math.abs(2 * s + b));
else
return Math.round(Math.abs(2 * s + b) ^ 3397); // the constant is set based on experiments.
}

// Returns hash value of a string as integer value modulo "m".
// The hash is deterministic - the returned value is always the same for given input string.
function GetStrHash(str, m) {
var s = Number(0); // Initialize state of hash.
// Iterate hash state through characters of given string.
for (var i = 0; i &lt; str.length; i++) {
var b = Number(str.charCodeAt(i));
s = Hash(s, b);
}
return (s % m);
}

//
// Returns deterministic synchronization time (one-minute slot of possible 60 one-minute slots of the day's first hour)
// based on computer name.
// This is used to control the start time of diagnostic cmdlets in script response rules. It is designed to prevent simultenious
// execution of test-* cmdlets against CAS in environments with limited mailbox sessions.
//
function GetCmdletSyncTime(computerName) {
var slots = Number(60); // maximum number of one-minute slots;

if (null == computerName)
return "00:00";

computerName = computerName.toString();

if (computerName.length == 0)
return "00:00";

// Assign the value based on computer name.
var timeInMinutes = GetStrHash(computerName, slots);
// Get a string in format "hh:mm" that SCOM recognizes.
return ConvertMinutesToTime(timeInMinutes);
}

// Global file paths that should be used only by the CapacityPlanning Model
var configPath = installPath + "Bin\\Monitoring\\";
var thresholdConfigFile = configPath + "ThresholdConfig.xml";
var jetStressFile = configPath + "JetStress.xml";

// Global strings that should be used only by the CapacityPlanning Model
var ioTag = "IoMaximum";
var cpuTag = "CpuMaximum";
var defaultIoMax = 0;
var defaultCpuMax = 75;

//
// Creates a config file that contains the default Capacity Maximums for CPU and IO
// User can edit this by hand if he wants
//
function CreateThresholdConfig(cpuMaximum, ioMaximum, updateFile) {
var retryCount = 0;

while (retryCount &lt; 3) {
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");

if (!fso.FileExists(thresholdConfigFile) || updateFile) {

// Checking for the two folders below installPath
if (!fso.FolderExists(configPath)) {
var parentFolder = fso.GetParentFolderName(configPath);
if (!fso.FolderExists(parentFolder)) {
fso.CreateFolder(parentFolder);
}
fso.CreateFolder(configPath);
}

var configFile = fso.CreateTextFile(thresholdConfigFile, true);

// Writing the xml for the thresholdconfig file
configFile.WriteLine("&lt;?xml version='1.0' encoding='utf-8' ?&gt;");
configFile.WriteLine("&lt;Configuration&gt;");
configFile.WriteLine(" &lt;" + cpuTag + "&gt;" + cpuMaximum + "&lt;/" + cpuTag + "&gt;");
configFile.WriteLine(" &lt;" + ioTag + "&gt;" + ioMaximum + "&lt;/" + ioTag + "&gt;");
configFile.WriteLine("&lt;/Configuration&gt;");
configFile.Close();
}

break;
}
catch (err) {
retryCount++;
if (retryCount &gt;= 3) {
LogEvent(
FILE_CREATION_WARNING_ID,
EVENT_TYPE_WARNING,
"Attempt to create or write to config file " + thresholdConfigFile + " has failed for at least 3 times");
}

// Adding the sleep here to avoid two server role files try and create or write the threshold config together
WScript.Sleep(2000);
}
}
}

//
// Helper function to get the XMLDOM object
//
function GetXmlDoc() {
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
return xmlDoc;
}

//
// Updates the threshold config file whenever the JetStress log is updated
//
function UpdateThresholdConfig(ioMax) {
var xmlDoc = GetXmlDoc();

var fileLoaded = xmlDoc.load(thresholdConfigFile);

var ioMaxCurr = 0;
var cpuMaxCurr = 0;
var isFileCorrupt = false;

if (fileLoaded) {
var xmlIoNodes = xmlDoc.documentElement.getElementsByTagName(ioTag);
var xmlCpuNodes = xmlDoc.documentElement.getElementsByTagName(cpuTag);

// Fallback to default value if the config value is corrupted
if (xmlIoNodes.length &gt; 0) {
ioMaxCurr = parseFloat(xmlIoNodes[0].text);

if (isNaN(ioMaxCurr)) {
ioMaxCurr = defaultIoMax;
}
}
else {
ioMaxCurr = defaultIoMax;
isFileCorrupt = true;
}

// Fallback to default value if the config value is corrupted
if (xmlCpuNodes.length &gt; 0) {
cpuMaxCurr = parseFloat(xmlCpuNodes[0].text);

if (isNaN(cpuMaxCurr)) {
cpuMaxCurr = defaultCpuMax;
}
}
else {
cpuMaxCurr = defaultCpuMax;
isFileCorrupt = true;
}

// Update only if necessary
if ((ioMax != defaultIoMax &amp;&amp; ioMax != ioMaxCurr) || isFileCorrupt) {
CreateThresholdConfig(cpuMaxCurr, ioMax, true);
}
}
}

//
// Gets the IO Node from the JetStress XML which has the value for IoMaximum
//
function GetIoNode(nodes) {
for (i = 0; i &lt; nodes.length; i++) {
if (nodes[i].getAttribute("name") == "Achieved Transactional I/O per Second") {
return nodes[i];
}
}

return null;
}

//
// Creates a threshold config file when not present.
// After that reads the JetStress Log and updates the config file if required
//
function ProcessCapacityThresholds() {

// Initially setting the default cpuMaximum and ioMaximum to 75 and 0 respectively.
CreateThresholdConfig(defaultCpuMax, defaultIoMax, false);

var xmlDoc = GetXmlDoc();

var fileLoaded = xmlDoc.load(jetStressFile);
var value = defaultIoMax;

if (fileLoaded) {
var xmlNodes = xmlDoc.documentElement.getElementsByTagName("database-sizing");

if (xmlNodes.length &gt; 0 &amp;&amp; xmlNodes[0].hasChildNodes()) {
var xmlIoNode = GetIoNode(xmlNodes[0].childNodes);

if (xmlIoNode != null) {
var attrName = xmlIoNode.getAttribute("name");
var attrValue = xmlIoNode.getAttribute("value");

if (attrValue != null &amp;&amp; !isNaN(parseFloat(attrValue))) {
value = parseFloat(attrValue);
}
}
}
}

if (value != defaultIoMax) {
UpdateThresholdConfig(value);
}
}

//
// Helper function to get the CapacityMaximum from the threshold config
//
function GetCapacityMaximum(categoryTag, defaultMaximum) {
var xmlDoc = GetXmlDoc();

var fileLoaded = xmlDoc.load(thresholdConfigFile);

var capacityMaximum = defaultMaximum;
if (fileLoaded) {
var xmlNodes = xmlDoc.documentElement.getElementsByTagName(categoryTag);

if (xmlNodes.length &gt; 0 &amp;&amp; xmlNodes[0].hasChildNodes()) {
capacityMaximum = parseFloat(xmlNodes[0].text);

if (isNaN(capacityMaximum) || capacityMaximum &lt; 0) {
capacityMaximum = defaultMaximum;
}
}
}

return capacityMaximum;
}

//
// Returns the Capacity Maximum for CPU from the threshold config
//
function GetCapacityMaximumForCPU() {
var categoryTag = cpuTag;
var defaultMaximum = defaultCpuMax;
return GetCapacityMaximum(categoryTag, defaultMaximum);
}

//
// Returns the Capacity Maximum for IO from the threshold config
//
function GetCapacityMaximumForIO() {
var categoryTag = ioTag;
var defaultMaximum = defaultIoMax;
return GetCapacityMaximum(categoryTag, defaultMaximum);
}

//
// Log to EventLog if verboseLogging is set
//
function LogEvent(eventId, eventType, message)
{
if (verboseLogging)
{
oAPI.LogScriptEvent(EVENT_SOURCE, eventId, eventType, message);
}
}

main();
</Script></ScriptBody>
<TimeoutSeconds>1800</TimeoutSeconds>
</ProbeAction>
</MemberModules>
<Composition>
<Node ID="Script">
<Node ID="DS"/>
</Node>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.Discovery.Data</OutputType>
</DataSourceModuleType>