Windows Server Max Concurrent API Probe Module

Microsoft.Windows.Server.MaxConcurrentAPI.Probe (ProbeActionModuleType)

Element properties:

TypeProbeActionModuleType
IsolationAny
AccessibilityPublic
RunAsDefault
OutputTypeSystem.PropertyBagData

Member Modules:

ID Module Type TypeId RunAs 
PassThrough ProbeAction System.PassThroughProbe Default
Probe ProbeAction Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe Default
RegistryProbe ProbeAction Microsoft.Windows.RegistryProbe Default
Filter ConditionDetection System.ExpressionFilter Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
TimeoutSecondsint$Config/TimeoutSeconds$Timeout SecondsExpecting time (in seconds) that the module wait to finish the execution.
ThresholdWaitersint$Config/ThresholdWaiters$Threshold WaitersLimit to consider in calculation.
ThresholdTimeoutsint$Config/ThresholdTimeouts$Threshold TimeoutsLimit to consider in calculation.

Source Code:

<ProbeActionModuleType ID="Microsoft.Windows.Server.MaxConcurrentAPI.Probe" Accessibility="Public" Batching="false" PassThrough="false">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="DiagnosticMode" type="xsd:integer"/>
<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="ThresholdWaiters" type="xsd:integer" minOccurs="0"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ThresholdTimeouts" type="xsd:integer" minOccurs="0"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
<OverrideableParameter ID="ThresholdWaiters" Selector="$Config/ThresholdWaiters$" ParameterType="int"/>
<OverrideableParameter ID="ThresholdTimeouts" Selector="$Config/ThresholdTimeouts$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<ProbeAction ID="Probe" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe">
<ScriptName>CheckMaxConcurrentAPI.ps1</ScriptName>
<ScriptBody><Script>

param([Int] $DiagnosticMode, [Int] $ThresholdWaiters, [Int] $ThresholdTimeouts)
$SCRIPT_NAME = "CheckMaxConcurrentAPI"
$ErrorActionPreference = "Stop"

# Event type constants
$EVENT_TYPE_LOG = 0
$EVENT_TYPE_ERROR = 1
$EVENT_TYPE_WARNING = 2
$EVENT_TYPE_INFORMATION = 4

# Typed property bag constants
$PROPERTY_TYPE_ALERT = 0
$PROPERTY_TYPE_EVENT = 1
$PROPERTY_TYPE_PERFORMANCE = 2
$PROPERTY_TYPE_STATE = 3

# State type constants
$STATE_SUCCESS = "Success"
$STATE_WARNING = "Warning"
$STATE_ERROR = "Error"

$momAPI = new-object -comObject MOM.ScriptAPI
Import-Module CimCmdlets -ErrorAction SilentlyContinue
Write-Host "$SCRIPT_NAME - Executing Windows Server Max Concurrent API Probe Powershell Script"

$SemWaitersDefaultThreshold = 50
$SemTimeoutsDefaultThreshold = 2000

$WIN_SRV_2012_OSVer = "6.2"
#******************************************************************************
# FUNCTION: CheckByOSCurrentVersion
# DESCRIPTION: Returns True if the Registry Key for CurrentVersion
# is equal the target OS Versions Number.
# RETURNS: Boolean: True, if build is greater or equal than the given number
#******************************************************************************
function CheckByOSCurrentVersion()
{
$strCurrentOSVer = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\"
$strCurrentOSVer = $strCurrentOSVer.CurrentVersion
$CheckByOSCurrentVersion = $false
if($strCurrentOSVer -ge $WIN_SRV_2012_OSVer){
$CheckByOSCurrentVersion = $true
}else{
$CheckByOSCurrentVersion = $false
}
return $CheckByOSCurrentVersion;
}
function MCAProblemCheckLite
{
param([string] $InstanceName)

#Returns PS Object with performance data related to the Netlogon being used to determine if Max Concurrent API Scenario is present. (Used by CSS)
$DetectionTime = Get-Date
$ProblemDetected = $False

if($IsCategoryTypeEmpty -eq $true)
{
$SemAcquiresCounter = "\\.\Netlogon(" + $InstanceName + ")\Semaphore Acquires"
$SemTimeoutsCounter = "\\.\Netlogon(" + $InstanceName + ")\Semaphore Timeouts"
$SemWaitersCounter = "\\.\Netlogon(" + $InstanceName + ")\Semaphore Waiters"
$SemHoldersCounter = "\\.\Netlogon(" + $InstanceName + ")\Semaphore Holders"
$SemHoldTimeCounter = "\\.\Netlogon(" + $InstanceName + ")\Average Semaphore Hold Time"

$SemAcquiresData = Get-Counter -Counter $SemAcquiresCounter -ComputerName . -SampleInterval 1 -MaxSamples 1
$SemTimeoutsData = Get-Counter -Counter $SemTimeoutsCounter -ComputerName . -SampleInterval 1 -MaxSamples 1
$SemWaitersData = Get-Counter -Counter $SemWaitersCounter -ComputerName . -SampleInterval 1 -MaxSamples 1
$SemHoldersData = Get-Counter -Counter $SemHoldersCounter -ComputerName . -SampleInterval 1 -MaxSamples 1
$SemHoldTimeData = Get-Counter -Counter $SemHoldTimeCounter -ComputerName . -SampleInterval 1 -MaxSamples 1

$SemAcquires = $SemAcquiresData.CounterSamples[0].CookedValue
$SemTimeouts = $SemTimeoutsData.CounterSamples[0].CookedValue
$SemWaiters = $SemWaitersData.CounterSamples[0].CookedValue
$SemHolders = $SemHoldersData.CounterSamples[0].CookedValue
$SemHoldTime = $SemHoldTimeData.CounterSamples[0].CookedValue
}
else
{
$SA = New-Object System.Diagnostics.PerformanceCounter("Netlogon", "Semaphore Acquires", $InstanceName)
$ST = New-Object System.Diagnostics.PerformanceCounter("Netlogon", "Semaphore Timeouts", $InstanceName)
$SW = New-Object System.Diagnostics.PerformanceCounter("Netlogon", "Semaphore Waiters", $InstanceName)
$SH = New-Object System.Diagnostics.PerformanceCounter("Netlogon", "Semaphore Holders", $InstanceName)
$ASHT = New-Object System.Diagnostics.PerformanceCounter("Netlogon", "Average Semaphore Hold Time", $InstanceName)

$SemAcquires = $SA.NextValue()
$SemTimeouts = $ST.NextValue()
$SemWaiters = $SW.NextValue()
$SemHolders = $SH.NextValue()
$SemHoldTime = $ASHT.NextValue()
}

#Detect problems. Exclude false positives if the counter has seen the buffer overrun bug from KB2685888.
if ((($SemWaiters -gt $ThresholdWaiters) -and (-not($SemWaiters -gt 4GB))) -or (($SemTimeouts -gt $ThresholdTimeouts) -and (-not($SemTimeouts -gt 4GB))))
{
$ProblemDetected = $true
}

$ReturnValues = new-object PSObject
$InstanceName = $InstanceName.replace('\','')

add-member -inputobject $ReturnValues -membertype noteproperty -name "DetectionTime" -value $DetectionTime
add-member -inputobject $ReturnValues -membertype noteproperty -name "SecureChannel" -value $InstanceName
add-member -inputobject $ReturnValues -membertype noteproperty -name "SemaphoreTimeouts" -value $SemTimeouts
add-member -inputobject $ReturnValues -membertype noteproperty -name "SemaphoreWaiters" -value $SemWaiters
add-member -inputobject $ReturnValues -membertype noteproperty -name "SemaphoreAcquires" -value $SemAcquires
add-member -inputobject $ReturnValues -membertype noteproperty -name "SemaphoreHolders" -value $SemHolders
add-member -inputobject $ReturnValues -membertype noteproperty -name "AverageSemaphoreHoldTime" -value $SemHoldTime
add-member -inputobject $ReturnValues -membertype noteproperty -name "ProblemDetected" -value $ProblemDetected

if (($SemWaiters -gt 4GB) -or ($SemHolders -gt 4GB) -or ($SemTimeouts -gt 4GB))
{
add-member -inputobject $ReturnValues -membertype noteproperty -name "BufferOverFlowDetected" -value $true
}
else
{
add-member -inputobject $ReturnValues -membertype noteproperty -name "BufferOverFlowDetected" -value $false
}

return $ReturnValues
}

# System.Diagnostics.PerformanceCounterCategory is not available
function NetlogonPerfCounterNanoServer
{
$useCIM = CheckByOSCurrentVersion
$query = "Select * From Win32_PerfFormattedData_Counters_Netlogon"
if($useCIM){

Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -SessionOption $cimSessionOption
$Instances = Get-CimInstance -CimSession $cimsession -Query $query
}
catch
{
$Instances = Get-WMIObject -Query $query
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
}else{
$Instances = Get-WMIObject -Query $query
}
foreach ($Instance in $Instances)
{
if (($DiagnosticMode -ne 0) -or (($Instance.Name -match "_Total") -eq $true))
{
$DetectionTime = Get-Date
$State = 1
if ((($Instance.SemaphoreWaiters -gt $ThresholdWaiters) -and (-not($Instance.SemaphoreWaiters -gt 4GB))) -or (($Instance.SemaphoreTimeouts -gt $ThresholdTimeouts) -and (-not($Instance.SemaphoreTimeouts -gt 4GB))))
{
$State = 0
}
$ErrorNumber = 0
$ErrorDesc = ""

$PerformancePropertyBag = $momAPI.CreatePropertyBag()
$PerformancePropertyBag.AddValue("Detection Time",$DetectionTime)
$PerformancePropertyBag.AddValue("Secure Channel",$Instance.Name.replace('\',''))
$PerformancePropertyBag.AddValue("Semaphore Timeouts",$Instance.SemaphoreTimeouts)
$PerformancePropertyBag.AddValue("Semaphore Waiters",$Instance.SemaphoreWaiters)
$PerformancePropertyBag.AddValue("Semaphore Acquires",$Instance.SemaphoreAcquires)
$PerformancePropertyBag.AddValue("Semaphore Holders",$Instance.SemaphoreHolders)
$PerformancePropertyBag.AddValue("Average Semaphore Hold Time",$Instance.AverageSemaphoreHoldTime)
$PerformancePropertyBag.AddValue("State",$State)
$PerformancePropertyBag.AddValue("ErrorNumber", $ErrorNumber)
$PerformancePropertyBag.AddValue("ErrorDescription", $ErrorDesc)

$PerformancePropertyBag
}
}
}

function GetSecureChannelNames
{
#Returns an array of secure channel names from the Netlogon performannce counter.
$Instances = New-Object System.Diagnostics.PerformanceCounterCategory("Netlogon")

if($Instances.CategoryType -eq 'MultiInstance')
{
Set-Variable -Name IsCategoryTypeEmpty -Value $false -Scope script

$AllInstanceNames = $Instances.GetInstanceNames()

if($AllInstanceNames.Count -eq 1)
{
$AllInstanceNamesToUse = @(1)
$AllInstanceNamesToUse[0] = $AllInstanceNames
}
else
{
if($DiagnosticMode -eq 0)
{
$AllInstanceNamesToUse = $AllInstanceNames -match '_Total'
}
else
{
$AllInstanceNamesToUse = $AllInstanceNames
}
}
}
else
{
Set-Variable -Name IsCategoryTypeEmpty -Value $true -Scope script
$AllInstanceNamesToUse = @()

if($DiagnosticMode -eq 0)
{
$AllInstanceNamesToUse += "_Total"
}
else
{
$PerfInstanceList = Get-Counter -Counter "\\.\Netlogon(*)\Semaphore Acquires"

foreach ($PerfInstance in $PerfInstanceList.CounterSamples)
{
$AllInstanceNamesToUse += $PerfInstance.InstanceName
}
}
}
return $AllInstanceNamesToUse
}

try
{
#Check if this computer is joined to Active Directory domain. Workgroup members does not have Netlogon counters so nothing to check with these machines
$JoinedDomain = (gwmi win32_computersystem).partofdomain
If ($JoinedDomain -eq $True)
{
if($ThresholdWaiters -eq $null)
{
$ThresholdWaiters = $SemWaitersDefaultThreshold
}

if($ThresholdTimeouts -eq $null)
{
$ThresholdTimeouts = $SemTimeoutsDefaultThreshold
}

$nanoRegKey = (Get-Item "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Server\ServerLevels" -ErrorAction SilentlyContinue)
$isNano = $false
if($nanoRegKey -eq $null)
{
$isNano = $false
}elseif($nanoRegKey.GetValue("NanoServer") -eq 1)
{
$isNano = $true
}
if ($isNano)
{
NetlogonPerfCounterNanoServer
return
}

$SCNames = GetSecureChannelNames

$LoopCounter = $SCNames.Count

for ($i = 0; $i -lt $LoopCounter; $i++)
{
$NameToUse = if($SCNames.Count -eq 1){$SCNames}else{$SCNames[$i]}

$InformationCollected = MCAProblemCheckLite ($NameToUse)

if ($InformationCollected.ProblemDetected -eq $true)
{
$State = 0
}
else
{
$State = 1
}

$ErrorNumber = 0
$ErrorDesc = ""

$PerformancePropertyBag = $momAPI.CreatePropertyBag()
$PerformancePropertyBag.AddValue("Detection Time",$InformationCollected.DetectionTime)
$PerformancePropertyBag.AddValue("Secure Channel",$InformationCollected.SecureChannel)
$PerformancePropertyBag.AddValue("Semaphore Timeouts",$InformationCollected.SemaphoreTimeouts)
$PerformancePropertyBag.AddValue("Semaphore Waiters",$InformationCollected.SemaphoreWaiters)
$PerformancePropertyBag.AddValue("Semaphore Acquires",$InformationCollected.SemaphoreAcquires)
$PerformancePropertyBag.AddValue("Semaphore Holders",$InformationCollected.SemaphoreHolders)
$PerformancePropertyBag.AddValue("Average Semaphore Hold Time",$InformationCollected.AverageSemaphoreHoldTime)
$PerformancePropertyBag.AddValue("State",$State)
$PerformancePropertyBag.AddValue("ErrorNumber", $ErrorNumber)
$PerformancePropertyBag.AddValue("ErrorDescription", $ErrorDesc)

$PerformancePropertyBag
}
}
else
{
$State = 1
$DetectionTime = Get-Date
$PerformancePropertyBag = $momAPI.CreatePropertyBag()
$PerformancePropertyBag.AddValue("Detection Time",$DetectionTime)
$PerformancePropertyBag.AddValue("Secure Channel","Monitor is not applicable for workgroup members")
$PerformancePropertyBag.AddValue("Semaphore Timeouts",0)
$PerformancePropertyBag.AddValue("Semaphore Waiters",0)
$PerformancePropertyBag.AddValue("Semaphore Acquires",0)
$PerformancePropertyBag.AddValue("Semaphore Holders",0)
$PerformancePropertyBag.AddValue("Average Semaphore Hold Time", $DetectionTime)
$PerformancePropertyBag.AddValue("State",$State)
$PerformancePropertyBag.AddValue("ErrorNumber", "No errors")
$PerformancePropertyBag.AddValue("ErrorDescription", "")
$PerformancePropertyBag
}
}
catch [System.Exception]
{
$Description = $_.ToString()
$ErrNumber = $_.Exception.ErrorCode

Write-Warning "$SCRIPT_NAME - $Description"
$DetectionTime = Get-Date
$State = 0

$PerformancePropertyBag = $momAPI.CreatePropertyBag()
$PerformancePropertyBag.AddValue("Detection Time",$DetectionTime)
$PerformancePropertyBag.AddValue("Secure Channel","Error")
$PerformancePropertyBag.AddValue("Semaphore Timeouts",0)
$PerformancePropertyBag.AddValue("Semaphore Waiters",0)
$PerformancePropertyBag.AddValue("Semaphore Acquires",0)
$PerformancePropertyBag.AddValue("Semaphore Holders",0)
$PerformancePropertyBag.AddValue("Average Semaphore Hold Time", $DetectionTime)
$PerformancePropertyBag.AddValue("State",$State)
$PerformancePropertyBag.AddValue("ErrorNumber", $ErrNumber)
$PerformancePropertyBag.AddValue("ErrorDescription", $Description)

$PerformancePropertyBag
}
finally
{
if($DiagnosticMode -eq 0)
{
Write-Host "$SCRIPT_NAME - single performance property bag returned"
}
else
{
Write-Host "$SCRIPT_NAME - multiple performance property bag returned"
}
}

Function Load-CimModules
{
$error.Clear()

$CimModule = Get-Module CimCmdlets

if ($null -eq $CimModule)
{
Import-Module CimCmdlets
$error.Clear()
}
}</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>DiagnosticMode</Name>
<Value>$Config/DiagnosticMode$</Value>
</Parameter>
<Parameter>
<Name>ThresholdWaiters</Name>
<Value>$Config/ThresholdWaiters$</Value>
</Parameter>
<Parameter>
<Name>ThresholdTimeouts</Name>
<Value>$Config/ThresholdTimeouts$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</ProbeAction>
<ProbeAction ID="RegistryProbe" TypeID="Windows!Microsoft.Windows.RegistryProbe">
<ComputerName>$Target/Host/Property[Type='Windows!Microsoft.Windows.Computer']/NetworkName$</ComputerName>
<RegistryAttributeDefinitions>
<RegistryAttributeDefinition>
<AttributeName>SERVER_VERSION_IS_2008</AttributeName>
<Path>SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentVersion</Path>
<PathType>1</PathType>
<AttributeType>1</AttributeType>
</RegistryAttributeDefinition>
</RegistryAttributeDefinitions>
</ProbeAction>
<ProbeAction ID="PassThrough" TypeID="System!System.PassThroughProbe"/>
<ConditionDetection ID="Filter" TypeID="System!System.ExpressionFilter">
<Expression>
<Not>
<Expression>
<RegExExpression>
<ValueExpression>
<XPathQuery>Values/SERVER_VERSION_IS_2008</XPathQuery>
</ValueExpression>
<Operator>ContainsSubstring</Operator>
<Pattern>6.0</Pattern>
</RegExExpression>
</Expression>
</Not>
</Expression>
</ConditionDetection>
</MemberModules>
<Composition>
<Node ID="Probe">
<Node ID="Filter">
<Node ID="RegistryProbe">
<Node ID="PassThrough"/>
</Node>
</Node>
</Node>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
<TriggerOnly>true</TriggerOnly>
</ProbeActionModuleType>