Microsoft_Exchange_2010_Execute_CI_Troubleshooter (DataSourceModuleType)

Element properties:

TypeDataSourceModuleType
IsolationAny
AccessibilityInternal
RunAsSystem.PrivilegedMonitoringAccount
OutputTypeSystem.PropertyBagData

Member Modules:

ID Module Type TypeId RunAs 
DS DataSource Microsoft.Exchange.2010.TimedCITroubleshooterScript.PropertyBagProvider Default

Overrideable Parameters:

IDParameterTypeSelector
IntervalSecondsint$Config/IntervalSeconds$
SyncTimestring$Config/SyncTime$
TimeoutSecondsint$Config/TimeoutSeconds$
Argumentsstring$Config/Arguments$
MonitoringDataSourcestring$Config/MonitoringDataSource$
MaxStartDelaySecondsint$Config/MaxStartDelaySeconds$

Source Code:

<DataSourceModuleType ID="Microsoft_Exchange_2010_Execute_CI_Troubleshooter" Accessibility="Internal" RunAs="System!System.PrivilegedMonitoringAccount">
<Configuration>
<xsd:element name="IntervalSeconds" type="xsd:int"/>
<xsd:element name="SyncTime" type="xsd:string"/>
<xsd:element name="TimeoutSeconds" type="xsd:int"/>
<xsd:element name="ScriptName" type="xsd:string"/>
<xsd:element name="Arguments" type="xsd:string"/>
<xsd:element name="ScriptBody" type="xsd:string"/>
<xsd:element name="MonitoringDataSource" type="xsd:string"/>
<xsd:element name="MaxStartDelaySeconds" type="xsd:int"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="IntervalSeconds" ParameterType="int" Selector="$Config/IntervalSeconds$"/>
<OverrideableParameter ID="SyncTime" ParameterType="string" Selector="$Config/SyncTime$"/>
<OverrideableParameter ID="TimeoutSeconds" ParameterType="int" Selector="$Config/TimeoutSeconds$"/>
<OverrideableParameter ID="Arguments" ParameterType="string" Selector="$Config/Arguments$"/>
<OverrideableParameter ID="MonitoringDataSource" ParameterType="string" Selector="$Config/MonitoringDataSource$"/>
<OverrideableParameter ID="MaxStartDelaySeconds" ParameterType="int" Selector="$Config/MaxStartDelaySeconds$"/>
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<DataSource ID="DS" TypeID="Microsoft.Exchange.2010.TimedCITroubleshooterScript.PropertyBagProvider">
<IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>
<SyncTime>$Config/SyncTime$</SyncTime>
<!-- Diagnostic script common library -->
<CommonLibraryScriptName>DiagnosticScriptCommonLibrary.ps1</CommonLibraryScriptName>
<CommonLibraryScriptBody>
# Copyright (c) 2010 Microsoft Corporation. All rights reserved.
#
# THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK
# OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
#
# This script is a library of functions for common diagnostic script executions.
# Diagnostic scripts need to dot source this file to invoke the functions.

# Event types.
$EVENT_TYPE_SUCCESS = 0;
$EVENT_TYPE_ERROR = 1;
$EVENT_TYPE_WARNING = 2;
$EVENT_TYPE_INFORMATION = 4;

# Writes to both log and console.
#
function Write-Log (
[string] $message)
{
[string] $time = [DateTime]::UtcNow.ToString("u");
$logEntry = "[$($time)] $($message)";
$logEntry &gt;&gt; "DiagnosticScriptExecution.log";
Write-Host $logEntry;
}

# Adds a monitoring event to the collection of monitoring events.
#
function Add-MonitoringEvent (
[int] $id = $(throw "Id must be specified."),

[int] $type = $(throw "Type must be specified."),

[string] $message = $(throw "Message must be specified."),

[string] $instanceName)
{
$event = New-Object System.Management.Automation.PSObject;
$event | Add-Member -MemberType NoteProperty -Name "EventId" -Value $id;
$event | Add-Member -MemberType NoteProperty -Name "EventType" -Value $type;
$event | Add-Member -MemberType NoteProperty -Name "EventMessage" -Value $message;

if (![String]::IsNullOrEmpty($instanceName))
{
$event | Add-Member -MemberType NoteProperty -Name "EventInstanceName" -Value $instanceName;
}

if ($script:monitoringEvents -eq $null)
{
$script:monitoringEvents = @();
}
$script:monitoringEvents += $event;
}

# Writes the collection of monitoring events to the pipeline.
#
function Write-MonitoringEvents
{
Write-Output $script:monitoringEvents;
}

</CommonLibraryScriptBody>
<!-- Wrapper script to execute the diagnostic script -->
<ExecutionScriptName>ExecuteDiagnosticScript.ps1</ExecutionScriptName>
<ExecutionArguments>-MonitoringDataSource '$Config/MonitoringDataSource$' -MaxStartDelaySeconds '$Config/MaxStartDelaySeconds$'</ExecutionArguments>
<ExecutionScriptBody>
# Copyright (c) 2010 Microsoft Corporation. All rights reserved.
#
# THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK
# OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
#
# Executes a diagnostic PowerShell script and output results as typed property bags that
# can be mapped to SCOM monitoring events in the management pack to drive states of monitors.
#
# Usage:
# .\ExecuteDiagnosticScript.ps1 -MonitoringDataSource &lt;event data source&gt; [-MaxStartDelaySeconds &lt;max. seconds to sleep before executing diagnostic PS script&gt;] -DiagnosticScriptName &lt;diagnostic PS script name to execute&gt; [-DiagnosticScriptArguments &lt;arguments into diagnostic PS script&gt;]
#
# Examples:
# .\ExecuteDiagnosticScript.ps1 -MonitoringDataSource 'MSExchange Monitoring TestSampleHealth' -MaxStartDelaySeconds 15 -DiagnosticScriptName '.\TestSampleHealth.ps1' -DiagnosticScriptArguments '-VerboseLogging:$true'

param(
# Monitoring event data source.
[string] $MonitoringDataSource = $(throw "MonitoringDataSource must be specified."),

# Max. seconds to sleep before executing diagnostic PS script.
[UInt16] $MaxStartDelaySeconds,

# Name of the diagnostic script to execute.
[string] $DiagnosticScriptName = $(throw "DiagnosticScriptName must be specified."),

# Arguments to the diagnostic script as string.
[string] $DiagnosticScriptArguments
)

# Dot source the common library.
. ".\DiagnosticScriptCommonLibrary.ps1";

# Event IDs and messages for logging execution results.
$SUCCESSFUL_EXECUTION_ID = 400;
$SUCCESSFUL_EXECUTION_MSG = "Exchange diagnostic PowerShell script invocation succeeded.";
$NO_EVENTS_FROM_SCRIPT_ID = 401;
$NO_EVENTS_FROM_SCRIPT_MSG = "The diagnostic PowerShell script did not return any monitoring event.";
$SCRIPT_EXECUTION_ERROR_ID = 402;

# Creates an event property bag that can be mapped to a monitoring event in the MP.
#
function Create-Event (
[string] $source,
[int] $id,
[int] $type,
[string] $message,
[string] $instanceName,
[string] $computer)
{
$event = $api.CreateTypedPropertyBag(1); # 1 = Event Data.

$message = Truncate-Message($message);
$event.AddValue("Message", $message);

$event.AddValue("EventNumber", $id);
$event.AddValue("EventType", $type);
$event.AddValue("EventSource", $source);

if ($instanceName -eq $null)
{
$instanceName = "";
}
$event.AddValue("EventInstanceName", $instanceName);

if ([String]::IsNullOrEmpty($computer))
{
$localServerName = [System.Net.Dns]::GetHostName();
$localIPHostEntry = [System.Net.Dns]::GetHostEntry($localServerName);
$localServerFQDN = $localIPHostEntry.HostName;

$computer = $localServerFQDN;
}
$event.AddValue("LoggingComputer", $computer);

$api.AddItem($event);
}

# Truncates a message if necessary, and appending the appropriate suffix.
#
function Truncate-Message (
[string] $message)
{
# For OpsMgr 2007 R2, the limit can be higher; but for SP1 it is around 128K for some monitors.
$MaxOpsMgrMessageLength = 128000;

$truncatedMessageSuffix = "...";
$defaultMessageSuffix = "";

$defaultMessageSuffix += "`n`nDiagnostic command: ""$($DiagnosticScriptName) $($DiagnosticScriptArguments)""";
$truncatedMessageSuffix += $defaultMessageSuffix;

if (($message.Length + $defaultMessageSuffix.Length) -gt $MaxOpsMgrMessageLength)
{
$message = $message.SubString(0, $MaxOpsMgrMessageLength - $truncatedMessageSuffix.Length) + $truncatedMessageSuffix;
}
else
{
$message = $message + $defaultMessageSuffix;
}

return $message;
}

# Main entry function.
#
function Main
{
# Adding random sleep if specified.
#
if ($MaxStartDelaySeconds -gt 0)
{
if ($MaxStartDelaySeconds -lt [UInt16]::MaxValue)
{
# Add one to include the max value in the randomly generated value.
$MaxStartDelaySeconds++;
}
$r = New-Object System.Random;
Start-Sleep -Seconds $r.Next($MaxStartDelaySeconds);
}

# Execute the diagnostic script.
#
$results = $null;
$results = Invoke-Expression "&amp; '$DiagnosticScriptName' $DiagnosticScriptArguments";
trap
{
Write-Log "Diagnostic script failed with the following error: $($Error[0])";

Create-Event `
-Source $MonitoringDataSource `
-Id $SCRIPT_EXECUTION_ERROR_ID `
-Type $EVENT_TYPE_ERROR `
-Message $($Error[0]) `
-InstanceName "" `
-Computer "";

return;
}

# Process event objects emitted from the diagnostic script.
#
$eventCount = 0;
foreach ($result in $results)
{
if (($result -ne $null) -and
($result.GetType().ToString() -eq "System.Management.Automation.PSCustomObject"))
{
if (($result.EventId -is [int]) -and
($result.EventType -is [int]) -and
(($result.EventMessage -is [string]) -and ![String]::IsNullOrEmpty($result.EventMessage)))
{
Create-Event `
-Source $MonitoringDataSource `
-Id $result.EventId `
-Type $result.EventType `
-Message $result.EventMessage `
-InstanceName $result.EventInstanceName `
-Computer "";

$eventCount++;
}
}
}

# Diagnostic scripts must return a collection of valid event objects.
#
if (($results -eq $null) -or ($eventCount -eq 0))
{
Write-Log "No monitoring events returned from diagnostic script.";

Create-Event `
-Source $MonitoringDataSource `
-Id $NO_EVENTS_FROM_SCRIPT_ID `
-Type $EVENT_TYPE_ERROR `
-Message $NO_EVENTS_FROM_SCRIPT_MSG `
-InstanceName "" `
-Computer "";
}
else
{
Write-Log "Monitoring events successfully returned from diagnostic script.";

Create-Event `
-Source $MonitoringDataSource `
-Id $SUCCESSFUL_EXECUTION_ID `
-Type $EVENT_TYPE_SUCCESS `
-Message $SUCCESSFUL_EXECUTION_MSG `
-InstanceName "" `
-Computer "";
}
}

Write-Log "Starting 'ExecuteDiagnosticScript.ps1' ('$($MonitoringDataSource)'; '$($MaxStartDelaySeconds)'; '$($DiagnosticScriptName)'; '$($DiagnosticScriptArguments)')...";

# For PS V1, we need to add MOM snapin from the wrapper script even though
# [Microsoft.EnterpriseManagement.Configuration.HealthState] does not get
# referenced until being used by TestGenericRollupHealth.ps1.
#
$momSnapinName = "Microsoft.EnterpriseManagement.OperationsManager.Client";
$momSnapin = Get-PSSnapin -Name $momSnapinName -ErrorAction SilentlyContinue;
if ($momSnapin -eq $null)
{
# Attempt to add the MOM snapin but don't fail if it cannot be added.
# When executing scripts on a machine where the SCOM console is not installed,
# it is expected that the snapin won't be added.
Add-PSSnapin -Name $momSnapinName -ErrorAction SilentlyContinue;

$momSnapin = Get-PSSnapin -Name $momSnapinName -ErrorAction SilentlyContinue;
if ($momSnapin -eq $null)
{
Write-Log "The '$($momSnapinName)' snap-in was not added: $($Error[0])";
}
}

# Create the OpsMgr Scripting API object.
$api = New-Object -ComObject "MOM.ScriptAPI";

Main;

# Return event property bags to OpsMgr.
$api.ReturnItems();

Write-Log "Completed 'ExecuteDiagnosticScript.ps1'.";

</ExecutionScriptBody>
<!-- Custom diagnostic script -->
<ScriptName>$Config/ScriptName$</ScriptName>
<Arguments>$Config/Arguments$</Arguments>
<ScriptBody><Script>$Config/ScriptBody$</Script></ScriptBody>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</DataSource>
</MemberModules>
<Composition>
<Node ID="DS"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
</DataSourceModuleType>