LS Common Data source module for Property Bag output.

Microsoft.LS.2010.PropertyBag.Common.DS (DataSourceModuleType)

Element properties:

TypeDataSourceModuleType
IsolationAny
AccessibilityInternal
RunAsMicrosoft.LS.2010.RunAsAccount
OutputTypeSystem.PropertyBagData

Member Modules:

ID Module Type TypeId RunAs 
DS DataSource Microsoft.LS.2010.PowerShell.PropertyBag.DS Default

Source Code:

<DataSourceModuleType ID="Microsoft.LS.2010.PropertyBag.Common.DS" Accessibility="Internal" RunAs="Microsoft.LS.2010.RunAsAccount" Batching="false">
<Configuration>
<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="SyncTime" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ScriptName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ScriptFileName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ScriptBody" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="EventId" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="EventParam1" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="EventParam2" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="EventParam3" type="xsd:string"/>
</Configuration>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<DataSource ID="DS" TypeID="Microsoft.LS.2010.PowerShell.PropertyBag.DS">
<ScriptName>$Config/ScriptName$</ScriptName>
<ScriptBody><Script>
#############################################################################
# 1. Initialize MOM api.
# 2. Import Lync Server Powershell module.
# 3. Execute Script Body.
# 4. Log Events based on Event Event Params
#############################################################################

#CONSTANTS###################################################################
$LOG_REG_KEY = "HKLM:\Software\Microsoft\Real-Time Communications\Health"
$INTERNAL_ERROR_REG_KEY = "HKCU:\Software\Microsoft\Real-Time Communications\Health\InternalAlerts"
$EVENT_ERROR = 1
$EVENT_WARNING = 2
$EVENT_INFORMATION = 4
$EVENT_ID = $Config/EventId$
$EVENT_PARAM_1 = "$Config/EventParam1$"
$EVENT_PARAM_2 = "$Config/EventParam2$"
$EVENT_PARAM_3 = "$Config/EventParam3$"
$EVENT_SCRIPT_NAME = "$Config/ScriptFileName$"
$FEATURE_KEY = "[{0}][{1}][{2}]" -f $EVENT_PARAM_1 ,$EVENT_PARAM_2, $EVENT_PARAM_3
$INTERVAL_SECONDS = $Config/IntervalSeconds$
$TIMEOUT_SECONDS = $Config/TimeoutSeconds$
#############################################################################

#LOGS &amp; EXCEPTIONS###########################################################
$CS_MODULE_NAME = "Lync"
$CS_MODULE_PATH = "$env:CommonProgramFiles\Microsoft Lync Server 2010\Modules\" + $CS_MODULE_NAME ;
$CS_MODULE_ADDED = "Lync Server Module is added";
$CS_MODULE_ALREADY_LOADED = "Lync Server Module is already loaded. No need to reload."
$CS_MODULE_FAILED_LOAD = "Failed to load Lync Server Module. Error: {0}."
$EXCEPTION_MESSAGE = "An internal exception occured during script execution, Exception : {0}."
$PROPERTY_VALUE = "Value of {0} is {1}."
$NO_NULL = "Error: {0} can not be null."
$MESSAGE_LENGTH_HIT_LIMIT = "MESSAGE TRUNCATED DUE TO SIZE LIMIT. Max Limit is [{0}]."
#############################################################################

#Helper Functions For Module Loading#########################################
$Script:logMessage = new-object System.Text.StringBuilder
function TRACE ($message)
{
$Script:logMessage.Append($message) | out-null
$Script:logMessage.Append("`n") | out-null
}

$Script:detailLogMessage = new-object System.Text.StringBuilder
function DETAILTRACE ($message)
{
$Script:detailLogMessage.Append($message) | out-null
$Script:detailLogMessage.Append("`n") | out-null
}

function IsCSModuleLoaded()
{
(get-module $CS_MODULE_NAME ) -ne $null
}

function LoadCSModule()
{
# Script execution are managed by SCOM powershell module.
# MonitoringHost.exe is hosting powershell runspaces.
# SCOM might run the scripts on the same process and reuse the app domain if neccesary.
# Double check on wheter module is loaded or not.
if (IsCSModuleLoaded)
{
TRACE ($CS_MODULE_ALREADY_LOADED)
}
else
{
# Due to possible race condition between steps of checking module is loaded and loading module steps,
# we need to double check after module loading attempt.
Import-module $CS_MODULE_PATH -ErrorAction SilentlyContinue
if (IsCSModuleLoaded)
{
TRACE ($CS_MODULE_ADDED)
}
else
{
$lastError = $error[0]
TRACE ($CS_MODULE_FAILED_LOAD -f $lastError)
}
}
}

function GetPropertyBag()
{
$Script:PropertyBag
}
#############################################################################

#Helper Functions For Error Logging##########################################
# We need to log a success event if there is a previous failure.
# if this function returns false then either previous run was success, expired or not exist.
# if this function returns true then previous run was error.
function ReadResultFromRegKey($regPath, $feature)
{
$result = $false
if (test-path $regPath)
{
$InternalErrorKey = (Get-Item $regPath)
if ($InternalErrorKey -ne $null)
{
$prevExecutionResult = $InternalErrorKey.GetValue($feature)
if ($prevExecutionResult -ne $null)
{
$decomposedResult = @($prevExecutionResult.Split(";"))
if ($decomposedResult.Count -eq 2)
{
$prevExecutionDateTimeTicks = [Int64]::Parse($decomposedResult[0])
$prevExecutionResult = $decomposedResult[1] -as [string]
$maxExpirationTicks = [TimeSpan]::FromSeconds($INTERVAL_SECONDS + $TIMEOUT_SECONDS).Ticks
$currentExpirationTicks = [System.DateTime]::UtcNow.Ticks - $prevExecutionDateTimeTicks
# Check whether registry key entry is expired.
if ($currentExpirationTicks -le $maxExpirationTicks)
{
$result = ($prevExecutionResult -eq $true)
}
}
}
}
}
$result
DETAILTRACE ("Read Result {0} From Regkey [Path={1} Property={2}]" -f $result, $regPath, $feature)
return
}

# [$result = $true] =&gt; Success. [$result = $false] =&gt; Error.
function WriteResultIntoRegKey($regPath, $feature, $result)
{
if (!(test-path $regPath))
{
new-item $regPath -force | out-null
}
$regValue = "{0};{1}" -f ([System.DateTime]::UtcNow.Ticks), $result
new-itemProperty -Path $regPath -Name $feature -Value $regValue -force | out-null
DETAILTRACE ("Wrote [Result {0}] To Regkey [Path={1} Property={2}]" -f $regValue, $regPath ,$feature)
}

function ReadPreviousAndUpdateCurrentResultRegKey($regPath, $feature, $currentResult)
{
$previousResult = ReadResultFromRegKey $regPath $feature
WriteResultIntoRegKey $regPath $feature $currentResult
$previousResult
}

# Create an Operations Manager EventLog reference.
$EventLog = New-Object System.Diagnostics.EventLog("Operations Manager")
# Set the Source to Health Service Script. This is used in the expression in the rule.
$EventLog.Source = "Health Service Script"
function WriteResultIntoEventLogIfNecessary($IsExceptionOccuredInCurrentRun)
{
$logFlag = $null
if (test-path $LOG_REG_KEY)
{
$logFlag = (Get-ItemProperty $LOG_REG_KEY).LogOpsMgr
}

$IsInternalExceptionOccuredInPreviousRun = ReadPreviousAndUpdateCurrentResultRegKey $INTERNAL_ERROR_REG_KEY $FEATURE_KEY $IsExceptionOccuredInCurrentRun

# Three conditions should be satisfied to skip event logging.
# * There should not be Internal Exception in previous run.
# * There should not be Internal Exception in current run.
# * Tracing Registry key is not ON.
if (($IsInternalExceptionOccuredInPreviousRun -eq $false) -and
($IsExceptionOccuredInCurrentRun -eq $false) -and
(($logFlag -ne 1) -and ($logFlag -ne 2)))
{
return
}

if($IsExceptionOccuredInCurrentRun -eq $true)
{
$EVENT_SEVERITY = $EVENT_ERROR
}
else
{
$EVENT_SEVERITY = $EVENT_INFORMATION
}

# Create an EventInstance reference. We pass a Task Category of None ( as indicated by 0 )
$EventInstance = New-Object System.Diagnostics.EventInstance($EVENT_ID, 0 , $EVENT_SEVERITY)

$DisplayName = $EVENT_SCRIPT_NAME
$EventLogMessage = ""
if($logFlag -eq 2)
{
$logMessage.Append($detailLogMessage) | out-null
}
# We need to safeguard ourself against the message limit. The documented message limit is 32786 bytes (~32K).
# http://msdn.microsoft.com/en-us/library/aa363679(VS.85).aspx
# however, when we use mom api to log event it adds some characters to the messages.
# Thus, we restrict the message limit here to 30720(30K).
# if the message is greater than this, we simply truncate it and update the log message.
$maxLimit = 30720
if($logMessage.Length -gt $maxLimit)
{
TRACE ($MESSAGE_LENGTH_HIT_LIMIT -f $maxLimit)
$EventLogMessage = $logMessage.ToString().Substring(0, $maxLimit)
}
else
{
$EventLogMessage = $logMessage.ToString()
}

$eventData = @(
$DisplayName ,
$EventLogMessage ,
$EVENT_PARAM_1 ,
$EVENT_PARAM_2 ,
$EVENT_PARAM_3
)

$EventLog.WriteEvent($EventInstance, $eventData)
}
#############################################################################


#SCRIPT INFO#################################################################
$currentUser = whoami
$supportedExecutionPolicies="RemoteSigned","Unrestricted","Bypass"
$executionPolicy = get-executionpolicy
if(!($supportedExecutionPolicies -contains $executionPolicy))
{
set-executionpolicy RemoteSigned
$executionPolicy = get-executionpolicy
}

TRACE ("`n")
TRACE ("--------------------------------------------------------------------------------")
TRACE ("-Script Name: {0}" -f "$Config/ScriptName$")
TRACE ("-Run as account: {0}" -f $currentUser)
TRACE ("-Execution Policy: {0}" -f $executionPolicy)
TRACE ("--------------------------------------------------------------------------------")

#############################################################################
$Script:MOMapi = New-Object -comObject "MOM.ScriptApi"
$exceptionOccured = $false
try
{
# Terminate Execution in Error Conditions.
$ErrorActionPreference = "Stop"
LoadCSModule

$Script:PropertyBag = $MOMapi.CreatePropertyBag()

$Config/ScriptBody$

$Script:PropertyBag
}
catch
{
TRACE ($EXCEPTION_MESSAGE-f $_.Exception.ToString())
$exceptionOccured = $true;
}

TRACE ("--------------------------------------------------------------------------------")

WriteResultIntoEventLogIfNecessary $exceptionOccured
</Script></ScriptBody>
<SnapIns/>
<Parameters/>
<IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>
<SyncTime>$Config/SyncTime$</SyncTime>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</DataSource>
</MemberModules>
<Composition>
<Node ID="DS"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
</DataSourceModuleType>