SCOM: Monitoring an Interactive Process and The Recovery Task
Recently I’m working on a management pack for a series of apps for a business unit of my employer. There is a large number of processes that I need to monitor and they run interactively on the console session. Auto Admin Logon is enabled on these servers, when the server starts up, it automatically logged on using the account configured and the the interactive processes are automatically started.
Setting up monitors for these processes is easy. However, I went a step further and created a generic write action module to be used as recovery task that restarts the process interactively on the console session.
There is one pre-requisite for the recovery task: I had to use PsExec to launch the process on console session. PsExec can be downloaded here: http://technet.microsoft.com/en-us/sysinternals/bb897553. PsExec needs to be copied locally to the computers that are being monitored.
I’ll now use use an example to go through how I setup the monitor, write action module and recovery task for notepad.exe
-
First of all, I created a class and its discovery to target my test machine “Client01”
-
Added “Microsoft.SystemCenter.ProcessMonitoring.Library” as a reference in my MP.
- Created a process monitor for notepad.exe
-
Monitor Type: Process Instance Count Monitor Type (from “Microsoft.SystemCenter.ProcessMonitoring.Library”)
-
Monitor Configuration:
- ProcessName: notepad.exe
- Frequency: 60
- MinInstanceCount: 1
- MaxInstanceCount: 1
-
InstanceCountOutOfRangeTimeThresholdInSeconds: 5
Note: While I was setting up the monitor, I realised the process name is case sensitive. Also, Frequency is in seconds
This is pretty much the same as using the Process Monitoring template from from the SCOM operations console (under Authoring Pane) – Except I used my own class rather than targeting to a group. Below is from the process monitoring wizard:
- Now once I import the MP into my SCOM management group, I can verify it is working (from health explorer):
- Because the way this monitor works, it is only healthy when the process count is in between MinInstanceCount and MaxInstanceCount (both set to 1 in this case). So the monitor’s health turns to Errorif there are say 2 instance of notepad running. Therefore I need to run a diagnostic task to determine how many instances are actually running because I only want to run the recovery task when the instance count is less than 1. I created a diagnostic task to run when the monitor’s health is in Error state. This diagnostic has only 1 action module: “Microsoft.Windows.ScriptPropertyBagProbe”:
- Module configuration:
- ScriptName: CheckProcessDiagnostic.vbs
- Arguments: notepad.exe
- ScriptBody: refer to the vbscript below
- TimeoutSeconds: 60
Here’s the script:
'==========================================
' AUTHOR: Tao Yang
' Script Name: CheckProcessDiagnostic.vbs
' DATE: 27/01/2012
' Version: 1.0
' COMMENT: - Script to check process state.
' - Used for OpsMgr Management Pack diagnostic tasks.
'==========================================
ProcessName = WScript.Arguments.Item(0)
Set oAPI = CreateObject("MOM.ScriptAPI")
Set oBag = oAPI.CreatePropertyBag()
WMIQuery = "Select * From Win32_process WHERE name = '" + ProcessName + "'"
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colProcesses = objWMIService.ExecQuery (WMIQuery)
Call oBag.AddValue("ProcessName",ProcessName)
If colProcesses.count< 1 Then
Call oBag.AddValue("Result","Positive")
Else
Call oBag.AddValue("Result","Negative")
End If
oAPI.Return(oBag)
This script returns a property bag variable”Result”. The value of “Result” is “Positive” if there is less than 1 instance of notepad.exe running. otherwise, the value is “Negative”. I will use the the value of “Result” to determine whether to run the recovery task or not by using a condition detection module in recovery task later.
- Create a Write Actions module for the recovery task. I’m creating a separate module for this so I can use it in recovery tasks of multiple monitors.
-
Member Module: “Microsoft.Windows.PowerShellWriteAction”
-
Module Configuration:
While editing this module, Add below secion between </ScriptBody> and</Configuration>:
<Parameters>
<Parameter>
<Name>PsExecPath</Name>
<Value>$Config/PsExecPath$</Value>
</Parameter>
<Parameter>
<Name>PathToExe</Name>
<Value>$Config/PathToExe$</Value>
</Parameter>
<Parameter>
<Name>Context</Name>
<Value>$Config/Context$</Value>
</Parameter>
<Parameter>
<Name>Arguments</Name>
<Value>$Config/Arguments$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
Place the PowerShell script below between
#=================================================
# AUTHOR: Tao Yang
# DATE: 16/01/2012
# Version: 1.0
# COMMENT: Start a exe on console session under LocalSystem Context
#=================================================
param([string]$PsExecPath, [string]$PathToExe, [string]$Context, [string]$Arguments)
# $Context should have only 2 possible values: "System" or "User". "User" needs Auto Admin Logon Enabled
Function Get-ConsoleSessionInfo
{
$results = Query Session
$ConsoleSession = $results | select-string "console\s+(\w+)\s+(\d+)\s+(\w+)"
if ($ConsoleSession)
{
$UserName = $ConsoleSession.Matches[0].groups[1].value
$SessionID = $ConsoleSession.Matches[0].groups[2].value
$State = $ConsoleSession.Matches[0].groups[3].value
$objConsoleSession = New-Object psobject
Add-Member -InputObject $objConsoleSession -Name "UserName" -Value $UserName -MemberType NoteProperty
Add-Member -InputObject $objConsoleSession -Name "SessionID" -Value $SessionID -MemberType NoteProperty
Add-Member -InputObject $objConsoleSession -Name "State" -Value $State -MemberType NoteProperty
} else { $objConsoleSession = $null }
Return $objConsoleSession
}
$Mode = $null
#Determine UserID
If ($Context -ieq "User")
{
$strUserName = $null
$DefaultPassword = $null
#detect if auto admin is enabled, if so, retrieve username and password from registry
$WinlogonRegKey = get-itemproperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\"
If ($WinlogonRegKey.AutoAdminLogon = "1")
{
$DefaultUserName = $WinlogonRegKey.DefaultUserName
$DefaultDomainName = $WinlogonRegKey.DefaultDomainName
$DefaultPassword = $WinlogonRegKey.DefaultPassword
$strUserName = "$DefaultDomainName`\$DefaultUserName"
}
If ($strUserName -and $DefaultPassword)
{
$Mode = "User"
} else {
Write-Error "Owner variable set to `"User`" but Auto Admin Logon is not configured!"
}
} elseif ($Context -ieq "System") {
$Mode = "System"
} else {
Write-Error "Incorrect Owner variable. it can only be `"User`" or `"System`""
}
#$thisScript = Split-Path $myInvocation.MyCommand.Path -Leaf
#$scriptRoot = Split-Path(Resolve-Path $myInvocation.MyCommand.Path)
#$PsExecPath = Join-Path $scriptRoot "PsExec.exe"
If (!(Test-Path $PsExecPath))
{
Write-Error "Unable to locate PsExec.exe in $scriptRoot. Please make sure it is located in this directory!"
} else {
#Get Console Session ID
$ConsoleSessionID = (Get-ConsoleSessionInfo).SessionID
if ($ConsoleSessionID)
{
If ($Mode -eq "User")
{
$strCmd = "$PsExecPath -accepteula -i $ConsoleSessionID -d -u $strUsername -p $DefaultPassword $PathToExe $arguments"
Write-Host "Executing $strCmd`..."
Invoke-Expression $strCmd
} elseif ($Mode -eq "System") {
$strCmd = "$PsExecPath -accepteula -i $ConsoleSessionID -d -s $PathToExe $arguments"
#run app under LOCALSYSTEM context
Write-Host "Executing $strCmd`..."
Invoke-Expression $strCmd
}
} else {
Write-Error "No one is currently logged on to the console session at the moment."
}
}
Note: this PowerShell script uses command “query session” to detect the session ID of the console session. When you save the configuration of this module, please ignore this error:
Add the following item under Configuration Schema tab:
**Note: Make sure “TimeoutSeconds” type is set to “Integer” and others are set to “String”
I also defined “TimeoutSeconds” as an overridable paramter:
Finally, set the Accessibility to Public (so it can be used in other management pack once this management pack is sealed”):
- Create a recovery task to run after Diagnostic Task that I created from the step 5.
This recovery task has 2 modules: a condition detection module (System.ExpressionFilter) and an Actions module (From the Write Actions module I created from Step 6)
- Condition Detection Module (System.ExpressionFilter):
Click Edit and add below:
<Expression>
<SimpleExpression>
<ValueExpression>
<XPathQuery Type="String">Diagnostic/DataItem/Property[@Name='Result']</XPathQuery>
</ValueExpression>
<Operator>Equal</Operator>
<ValueExpression>
<Value Type="String">Positive</Value>
</ValueExpression>
</SimpleExpression>
</Expression>
Actions Module (Module Type from the write action module created in Step 6)
- PsExecPath: Path to PsExec.exe on the target computer
- PathToExe: The executable that you want PsExec to run
- Context: 2 Possible values: “User” or “System”
- Argument: arguments for the executable that PsExec is executing
- TimeoutSeconds: i.e. 60
Note: Regarding to the Context variable, I designed the script to launch PsExec to execute the executable either under LOCALSYSTEM ( with –s operator in PsExec) or under the user that’s configured for Auto Admin Logon (with –u
and –p operators in PsExec). Because when Auto Admin Logon is enabled, the default username and password is stored in the registry key (**HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon**). If "Context" is set to "User", the script reads the username and password from registry and pass them into PsExec. So, if Auto Admin Logon is not configured, the script won’t work if "Context" is set to "User"
Note: In this example, the recovery task simply launch notepad.exe on the console session. I can also tell notepad to open a txt file if I add the path of the txt file to “Arguments”.
Note: This recovery task will error out if no one has logged on to the console session of the target computer.
Now, everything is setup, time to put it to test.
From screen capture below, I can see the monitor’s health became Error at 10:44pm 27/01/2012. After the Diagnostic task determined there is no notepad.exe running, the recovery task kicks in, at 10:45pm, it launched notepad.exe on console session (session ID 2). The PID of notepad.exe is 4000.
Now, when I go to the target computer, notepad is launched on the console session and I can easily get the details of notepad.exe process:
You can see from above screen capture, notepad.exe was started at the same time when the recovery task ran, the session ID is 2, Owner is the account configured for Auto Admin Logon and process ID is same as the output from PsExec. Therefore, this instance of notepad.exe is the one started by the recovery task!
I’ve attached the 2 scripts used in Diagnostic and recovery tasks below. as well as my sample unsealed MP.
Please feel free to contact me if you have any questions or suggestions.
Leave a comment