By default the assemblies necessary to complete the discovery and monitoring are installed under the \%ProgramData\% directory. You can set this to any valid path to install them in a different location.
IntervalSeconds
int
$Config/IntervalSeconds$
Interval Seconds
The interval that this Monitor is run
ScriptTraceEnabled
int
$Config/ScriptDebugEnabled$
Script Trace Enabled
To enable detailed logging of this Monitor set this to 1, setting it to 0 will disable logging. The logs are sent to the Windows Event Log and can be found with the other Operations Manager logs.
Source Code:
<UnitMonitorType ID="TeamFoundationServer2015.TfsPowerShellMonitor" Accessibility="Public">
<MonitorTypeStates>
<MonitorTypeState ID="Error" NoDetection="false"/>
<MonitorTypeState ID="Success" NoDetection="false"/>
</MonitorTypeStates>
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="ClassName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="ObjectPath" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="BaseInstallPath" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="IntervalSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="ScriptDebugEnabled" type="xsd:integer"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="BaseInstallPath" Selector="$Config/BaseInstallPath$" ParameterType="string"/>
<OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int"/>
<OverrideableParameter ID="ScriptTraceEnabled" Selector="$Config/ScriptDebugEnabled$" ParameterType="int"/>
</OverrideableParameters>
<MonitorImplementation>
<MemberModules>
<DataSource ID="DataSource" TypeID="System!System.SimpleScheduler">
<IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>
<SyncTime/>
</DataSource>
<ProbeAction ID="Script" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagProbe">
<ScriptName>TfsMonitor.ps1</ScriptName>
<ScriptBody><Script>param($baseInstallPath, $className, $objectPath, $scriptDebugEnabled)
###
# This monitor will check the health of a specific Tfs component via a C# Class
# To insure errors don't go on noticed $ErrorActionPreference will be set to Stop.
###
# $baseInstallPath - An override location to install the binary - if not provided a default will be used, see Compute-InstallPath
# $className - The name of the class (from with in Microsoft.TeamFoundation.Scom.ManagementPack namespace
# /assembly) that should be used for this discovery
# $scriptDebugEnabled - A flag to control if debug information should be logged
# Errors and Warnings are always logged
#
# Verifies that the binary files has been placed in the provided install directory
# It can fail if we can't a lock using the mutex for the install path
function Validate-Install
{
param ([string] $installPath)
## Need void here to prevent powershell from adding a space to the caller outout
[void] [System.Threading.Mutex]$mutex
[bool] $gotMutex = $false
try
{
[string] $mutextName = ("Global\{0}" -f $installPath.Replace("\",";"))
Log-Message -message ("Creating Mutex: {0}" -f $mutextName) -severity $Script:severityInfo
[bool]$wasCreated = $false
$mutex = New-Object System.Threading.Mutex($true, $mutextName, [ref] $wasCreated)
if ($wasCreated)
{
Log-Message -message "Created Mutex" -severity $Script:severityInfo
$gotMutex = $true
}
else
{
Log-Message -message "Waiting for up to 3 secs for Mutext" -severity $Script:severityInfo
try
{
$gotMutex = $mutex.WaitOne(3000)
}
catch [System.Threading.AbandonedMutexException]
{
## We have no problem just taking over an Abandoned Mutex
Log-Message -message "Mutex was Previously Abandoned" -severity $Script:severityInfo
#
# Does the work of Verifying that the binaries files have been placed.
# Assumes the caller already obtained the needed Mutext to prevent raise conditions
function Validate-Install-UnderMutex
{
param ([string] $installPath)
#
# Adds information about the current user to the log
function Log-User
{
$owner = (Get-WmiObject win32_process | Where-Object {$_.ProcessId -eq $pid }).getowner()
#
# Loads an Assembly, and creates a instance of an object from that assembly
# All the TFS Scom MP Objects are Disposable. Failing to create a valid object will get cleaned up here, but if an object is returned it needs to be disposed.
function Get-ObjectFromAssembly
{
param ([string] $fullPath, [string] $fullClassName)
if ($location.ToLower() -ne $fullPath.ToLower())
{
# We set your Discoveries as Isolation="OwnProcess" however that does not effect Monitors, their PowerShell Instance is shared.
throw [Exception] ("Failed to load {0} from the correct location, got {1} instead. Please stop and restart the Health Service" -f $fullPath, $location)
}
}
catch
{
if ($result -ne $null)
{
try
{
$result.Dispose()
# Leaving this as info, the original exception will get logged
Log-Message -message ("Exception was thrown while creating {0} from {1}. Disposed before re-throwing error" -f $fullClassName, $fullPath) -severity $Script:severityInfo
}
catch
{
# This can happen if they have an old copy of the assembly loaded which does not have a Dispose Method
# Marking this as an error, something is going wrong here.
Log-Message -message ("Exception was thrown while creating {0} from {1}, Second Exception was throw during dispose" -f $fullClassName, $fullPath) -severity $Script:severityError
}
$result = $null
}
throw
}
return $result
}
#
# Pulls a specific values from the windows registry
function Get-RegistryValue
{
param ([string] $path, [string] $name)
#
# Takes a string that could be very long and breaks it into smaller chunks
function Get-Chunks
{
param ([string] $message)
$chunkSize = 20480 #20K
$result = @{}
#
# Wrapper to obtain and cache the value to SCOM Script API
function Get-MomSciptApi
{
if ($Script:MomSciptApi -eq $null)
{
$Script:MomSciptApi = new-object -comObject 'MOM.ScriptAPI'
}
return $Script:MomSciptApi
}
#
# Start of Specific Functions
########################################################################################
#
# Checks the Status specific component via a C# Class
function Get-Status
{
param([string] $baseInstallPath, [string]$className, [string]$objectPath)
#
# Log that we are here and validate our input
Log-Message -message ("First Param baseInstallPath:{0}" -f $baseInstallPath) -severity $Script:severityInfo