Posted by Tao Yang on 27/01/2012 in
SCOM |
∞
When writing a Probe Action Module to run a trigger only PowerShell script and return property bags, Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe module can be used. However, there is no trigger only probe module if you want to run VBScript.
Below are 2 examples how to create trigger only probe modules for both PowerShell and VBScript:
1. PowerShell
Member Modules:
Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe

Data Types:
Input: Trigger Only
Output: System.PropertyBag Data

2. VBScript:
Member Modules:
System.PassThroughProbe
Microsoft.Windows.ScriptPropertyBagProbe

Data Type:
Input: Trigger Only
Output: System.PropertyBag Data

Tags: MP Authoring, SCOM
Posted by Tao Yang on 25/01/2012 in
SCOM |
∞
This is how I configured recovery task to run a batch file:
Actions Module Type: System.CommandExecuter
Module Configuration
Application Name: C:\Windows\System32\cmd.exe
Working Directory: C:\Windows\System32
CommandLine: /c <Path to Batch file> (i.e. /c C:\Apps\DelFile.bat)
TimeoutSeconds: <i.e. 60>
RequiredOutput: true
Tags: SCOM
Posted by Tao Yang on 11/01/2012 in
PowerShell |
∞
I wrote this function in the script from my previous post “SCOM MP Authoring Example: Generate alerts based on entries from SQL Database (Part 2 of 2)”. It comes handy sometimes so I thought I’ll blog it separately as well.
In PowerShell Datetime object, there is a ToUniversalTime() method that converts local time to UTC time.

However, there isn’t a native way to convert FROM UTC To local time. So I wrote this function:
Function Get-LocalTime($UTCTime)
{
$strCurrentTimeZone = (Get-WmiObject win32_timezone).StandardName
$TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById($strCurrentTimeZone)
$LocalTime = [System.TimeZoneInfo]::ConvertTimeFromUtc($UTCTime, $TZ)
Return $LocalTime
}

Tags: Powershell
Posted by Tao Yang on 05/01/2012 in
SCOM |
∞
This is the 2nd part of the 2-part series. Part 1 can be found here.
In Part 2, I’ll cover the steps involved to create each module type and the rule in this article. all these objects will be created in SCOM 2007 R2 Authoring Console. You can create a new management pack for this or use an existing one.
Firstly, we will need create the probe action and data source modules:
Probe Action Module:
1. Under Type Library pane, go to “Probe Actions” under Module Types and click New—>”Composite Probe Action…”
2. Give it a unique identifier such as “Your.Management.pack.Prefix.Database.Catcher.Probe.Action”
3. in general tab, give it a name:

4. Under Member Modules, add “Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe” and give it a Module ID of “PSScript”

5. Click on Edit
6. Enter the ScriptName and TImeoutSeconds. Then Edit again in the Configuration tab of the probe action module

6. When the text editor is launched, Enter the powershell script in between <ScriptBody> and </ScriptBody> tags
7. Below is the script I used in my management pack. please edit it to suit your needs:
#-----------------------------------
#Alarms capture via AuditDB
#Name: AuditDBAlarmCatcher.PS1
#Param 0: SQL Database Instance Name
#Param 2: Database name
#Param 2: The inteval in seconds
#Author: Tao Yang
#Date: 07/12/2011
#-----------------------------------
param([string]$SQLInstance,[String]$Database,[Int]$Interval)
$EVENT_TYPE_ERROR = 1
$EVENT_TYPE_WARNING = 2
$EVENT_TYPE_INFORMATION = 4
Function Get-LocalTime($UTCTime)
{
$strCurrentTimeZone = (Get-WmiObject win32_timezone).StandardName
$TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById($strCurrentTimeZone)
$LocalTime = [System.TimeZoneInfo]::ConvertTimeFromUtc($UTCTime, $TZ)
Return $LocalTime
}
$oAPI = New-Object -ComObject "MOM.ScriptAPI"
$oBag = $oAPI.CreatePropertyBag()
$strServer = ".\$SQLInstance"
$ADOCon = New-Object -ComObject "ADODB.Connection"
$oResults = New-Object -ComObject "ADODB.Recordset"
$adOpenStatic = 3
$adLockOptimistic = 3
$ADOCon.Provider = "sqloledb"
$ADOCon.ConnectionTimeout = 60
$nowInUTC = (Get-Date).ToUniversalTime()
$StartTime = $nowInUTC.AddSeconds(-$Interval)
$conString = "Server=$strServer;Database=$Database;Integrated Security=SSPI"
$strQuery = "Select * from V_Audit Where EventTypeCaption LIKE 'Alarm triggered' AND EventDate >= '$StartTime'"
$ADOCon.Open($conString)
$oResults.Open($strQuery, $ADOCon, $adOpenStatic, $adLockOptimistic)
$oBag.AddValue('Interval', $Interval)
If (!$oResults.EOF)
{
If (!([appdomain]::currentdomain.getassemblies() | Where-Object {$_.FullName -ieq "system.core"}))
{
Try {
Write-Host "Loading .NET DLL into Powershell..." -ForegroundColor Green
[Void][System.Reflection.Assembly]::LoadWithPartialName("System.Core")
} Catch {
#We cannot use Write-Error cmdlet here because $ErrorActionPreference is set to "SilentlyContinue" so it won't display on the screen.
Write-Host "Unable to load .NET Framework into Powershell, please make sure it is installed!" -foregroundColor Red
Exit
}
}
$oBag.AddValue('GenerateAlert', 'True')
$arrLogEntries = @()
$oResults.MoveFirst()
Do {
$EventDate = $oResults.Fields.Item("EventDate").Value
$EventDate = Get-LocalTime $EventDate
$Description = $oResults.Fields.Item("Description").Value
$arrLogEntries += "- $EventDate`: $Description"
$oResults.MoveNext()
} until ($oResults.EOF)
$LogDetail = [System.String]::Join(" ", $arrLogEntries)
$intEntryCount = $arrLogEntries.count
Remove-Variable arrLogEntries
} else {
$oBag.AddValue('GenerateAlert', 'False')
$intEntryCount = 0
}
$oResults.Close()
$ADOCon.Close()
$oBag.AddValue('LogEntry', $LogDetail)
$oBag.AddValue('LogEntryCount', $intEntryCount)
$oBag
8. Enter below sections after </ScriptBody> and before <TimeoutSeoncds>:
<Parameters>
<Parameter>
<Name>SQLInstance</Name>
<Value>$Config/SQLInstance$</Value>
</Parameter>
<Parameter>
<Name>Database</Name>
<Value>$Config/Database$</Value>
</Parameter>
<Parameter>
<Name>Interval</Name>
<Value>$Config/Interval$</Value>
</Parameter>
</Parameters>

9. Click Save in the text editor and close it. you should now see what you’ve entered in the configuration tab of the probe action module:

10. Click OK to exit the configuration tab. Under Configuration Schema tab, add 3 parameters (in same order) as shown below:

11. Under Data Types, make sure the input and output data is set as below (should be default anyway):

12. Under Options, I left Accessibility to “Internal”, but if you are going to use this module outside of this management pack, set it to public.

13. Now click OK to exit the probe module window. the probe action module is now created. Now it’s a good time to save the management pack.
Data Sources Module:
1. Under Type Library pane, go to “Data Sources” under Module Types and click New—>”Composite Data Source…”
2. Give it a unique identifier such as “Your.Management.pack.Prefix.Database.Catcher.DataSource”
3. Open the data source module you’ve just created and give it a display name under “General” tab:

4. Add 2 member modules:
|
Module ID
|
Role
|
Type
|
Next Module
|
| Schedule |
Data Source |
System.SimpleScheduler |
Probe |
| Probe |
Probe Action |
Probe Action module you’ve just created |
Module Output |

5. Edit the SimpleScheduler module, for the IntervalSeconds value, click on “promote…”. this will set it to “$Config/IntervalSeconds$”. and leave SyncTime to blank:

6. Edit the probe action module, use promote to set values for all 3 parameters:

7. Configure “Configuration Schema” tab as below (again, make sure these parameters are in the right order”):

8. Configure Overridable Parameters as below:

9. Make sure output data type is set to System.PropertyBagData

10. Set accessibility to “public” if you are going to access this module from other management packs.
Now the data source module is complete. We are going to create the rule next.
Rule:
1. Under Health Model pane, go to “Rules” and click New—>”Custom Rule…”
2. Give it a unique identifier such as “Your.Management.pack.Prefix.Database.Catcher.Rule”
3. Give the rule a display name and select the target class where you want to run the rule under general tab

4. In Modules tab, create a data source module with the type of the data source module type you’ve created previously. give it a module ID of DataSource

5. Edit the data source module configuration, enter the values for all 3 parameters: SQLInstance, Database and IntervalSeconds:

According to above example, this rule will connect to the database “AuditDB” in the particular SQL instance that you specified and will run in every 5 minutes (300 seconds)
6. Now, create a condition detect module with type: System.ExpressionFilter and Module ID: Filter_AlertCondition

7. Edit the condition detection module, under configuration tab, click on Configure… button.
8. Enter the expression as below:
Parameter Name: Property[@Name='GenerateAlert']
Operator: Equals
Value: True
Click OK to save.
It looks like this when it’s done:

9. Create an Action module. Type: System.Health.GenerateAlert. ModuleID: Alert.

10. Click Edit for the Action module then click Edit again under Configuration tab to edit the XML.
11. Add below section in the XML before </Configuration> tag:
<AlertParameters>
<AlertParameter1>$Target/Property[Type="System!System.Entity"]/DisplayName$</AlertParameter1>
<AlertParameter2>$Data/Property[@Name='Interval']$</AlertParameter2>
<AlertParameter3>$Data/Property[@Name='LogEntryCount']$</AlertParameter3>
<AlertParameter4>$Data/Property[@Name='LogEntry']$</AlertParameter4>
</AlertParameters>

12. save the XML and exit the text editor. then click on Configure to configure the alert. you may use the parameters from previous step to form the alert description.
13.Edit the Production knowledge of this rule if you like. it will also appear with the alert.
Now we are done. You can save this unsealed management pack or seal it using authoring console. please make sure you test it before import it into your production environment.
Below is a sample alert from my test environment:

Few notes:
- The database that I had to work with was a SQL Express DB. I found this free tool extremely useful since I can’t use SQL management studio to connect to SQL Express databases: Database Browser. The database table screen capture from Part 1 of this series was from this tool.
- When testing the PowerShell Script, I needed to run the script under Local Systems as my account did not have access to the database. Since in my script, I connected to the database using integrated security, I had to make sure I run the script under the account which is going to be used to run the rule (in my case, Local Systems), I had to use PSExec from Sysinternals to launch Powershell as it allows me to run executables under Local System.
- Originally I used a multi-line string variable in PowerShell script to store records returned from SQL query (one record per line). It didn’t work after added the script to the management pack. I figured out i can use the special HTML character for carriage return inside the string variable in Powershell. So the line looks like this:

My sample PowerShell script can be downloaded from HERE.
Tags: Featured, MP Authoring, Powershell, SCOM
Posted by Tao Yang on 04/01/2012 in
SCOM |
∞
This is probably going to be a bit too long for one single blog post. I’ll separate this topic into 2 articles:
- Part 1 includes the background and overview of the rule and it’s workflow
- Part 2 documents all the steps to create all the module types and the rule itself.
This article is the first part of the 2-part series.
Recently, I’ve been writing a SCOM management pack for a new application that my employer is implementing. This application logs any application related alarms into a SQL express database. One of the requirement for the MP is to catch these alarms from the database and generate alerts based on these alarms.
In the database, I’m interested in any records that has the value of “Alarm triggered” in “EventTypeCaption” column.
The the record is added to the database, the application also adds the time stamp in UTC to the “EventDate” field.
Below is a snapshot of a subset of the database. I’ve highlighted the records that I’m interested in:

To achieve this goal, I’ve written some custom modules and created a rule using these modules.
Rule overview:
As usual, the rule contains 3 modules:
- Data Source
- Condition Detection
- Actions

Below is the flow chat for the entire workflow:

To explain the workflow in details:
- The workflow takes 3 inputs:
- IntervalSeconds – how frequent does the rule run
- SQLInstance – Name of the SQL instance
- Database – Name of the database
- The data source member module system.simple.scheduler runs according to the intervalseconds
- The Probe Action member module (a PowerShell script) takes all 3 inputs:
- connect to the database in the SQL instance as specified from the input
- calculate the earliest time (current time minus intervalseconds from the input then convert to UTC). store the earliest time in a datetime variable $starttime
- Build the SQL query: “Select * from <table name> Where EventTypeCaption LIKE ‘Alarm triggered’ AND EventDate >= ‘$StartTime’”
- Execute the SQL query.
- If returned any data:
- Property Bag value “GenerateAlert” = True
- For each record, convert the EventDate from UTC time to local time.
- combine all records from the record set to a multi line string that include converted event date and event description. return this string as Property Bag value “LogEntry”
- return Property Bag Value “LogEntryCount”
- Condition Detection module detects Property Bag value “GenerateAlert” = True
- If passed Condition Detection Module, the Write Action module generates alert with LogEntry and LogEntryCount in alert description field.
Note: I’m using PowerShellPropertyTriggerOnlyProbe rather than VBscript because I found it’s easier to convert UTC and local time back and forth as I can simply use .NET class System.TimeZoneInfo and powershell datetime object ToUTC() method to do the conversion. if we are to use VBScript, there is no equivalent trigger only probe for VBScript. I’ll try to cover this in a separate blog post.
What’s Next?
I’ll go through how to create each module types and the rule itself in part 2 of this series.
To be continued…
Part 2
Tags: Featured, MP Authoring, SCOM
Posted by Tao Yang on 10/12/2011 in
SCOM |
∞
I’ve been asked a question on how to bulk update SMTP server addresses in SMTP notification channels using PowerShell.
Here’s the script to run in OpsMgr Command Shell:
$newSMTP = <name of your new SMTP server>
$SMTPChannels = Get-NotificationAction |Where-Object {$_.Name –imatch “smtp”}
Foreach ($item in $SMTPChannels)
{
$item.Endpoint.PrimaryServer.Address = $newSMTP
$item.Endpoint.update()
}
Tags: Powershell, SCOM
Posted by Tao Yang on 08/11/2011 in
PowerShell,
SCCM |
∞
A colleague came across a problem today. He could run a SCDPM PowerShell script from PowerShell console successfully but could not run it when packaged it in SCCM.
We soon found out it’s because SCCM 2007 is a 32-bit app and DPM PowerShell snapin is only available for 64-bit PowerShell because we could not run the script from a 32-bit PowerShell console.
When a 32-bit application tries to access %WinDir%\system32, Windows redirects it to %WinDir%\SysWOW64. In order for the 32-bit app to access %WinDir%\System32 folder, we have to use %Windir%\sysnative.
So, we set the command line of the program in SCCM package to “%WinDir%\Sysnative\WindowsPowerShell\V1.0\Powershell.exe” –noprofile .\PowerShellScript.ps1 as that’s where the 64-bit version of PowerShell is and the SCCM advertisement ran successfully on the client.
More reading regarding to file system redirection here: http://support.microsoft.com/kb/942589
Tags: Powershell, SCCM
Posted by Tao Yang on 23/10/2011 in
SCOM |
∞
There was a requirement at work that people need to be notified when a USB storage device (USB key or portable USB hard disks) is connected or disconnected from SCOM monitored Windows computers.
So I wrote a 2 very simple alert generating rules to detect USB Mass Storage Device creation and deletion WMI event. I set both rules to run every 60 seconds so within 60 seconds of the event, an Information alert is generated in SCOM:
Alert for USB Storage Device Connection Event:

Alert for USB Storage Device Removal Event:

I have also created a dynamic group called Virtual Windows Computers in the MP so I can disable both rules for virtual machines. This is how I defined the group:

Please note this Virtual Machine discovery only detects virtual machines running on Microsoft’s virtual host platform. If you open System Center Internal Library MP in MPViewer and check the Raw XML for discovery “Discover if Windows Computer is a Virtual Machine”, you’ll see it the WQL:

So if you have non-Microsoft virtual machines (i.e. VMware) in your environment and you want to disable these 2 rules for those virtual machines, you will need to modify my group or create your own group in my management pack.
Download: USB Storage Device Detection Management Pack
Tags: Management Pack, SCOM
Posted by Tao Yang on 12/10/2011 in
SCCM,
SCOM |
∞
Download: MOF Extension for OpsMgr Configurations
I’ve been wanting to do this for a while now and finally found some spare time for it. I want to be able to target OpsMgr (SCOM) agents and servers in ConfigMgr (SCCM) in a more granular way (i.e. all OpsMgr agents that are reporting to a OpsMgr Management Server, or all OpsMgr agents within a OpsMgr management group or All OpsMgr management servers)
Therefore, I created these extensions for configuration.mof and sms_def.mof so OpsMgr settings are captured as part of ConfigMgr client hardware inventory.
Once loaded in to ConfigMgr and after clients have retrieved new policy and performed hardware inventory, you will be able to see this in Resource Explorer:
For OpsMgr Agents:

For OpsMgr Servers:

Note: As always, make sure backup both mof files before editing them. once saved, monitor dataldr.log to make sure they are successfully compiled.
Please refer to my previous blog if you decide to remove this mof extention from your ConfigMgr environment.
More Reading about ConfigMgr Hinv (Hardware Inventory):
Technet: About MOF Files Used by Hardware Inventory
Technet Blog: How to Extend Your Hardware Inventory Using the SMS_DEF.MOF File
Collection Query Samples:
All OpsMgr agents in Management Group TYANG:
select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_CUSTOM_OPSMGR_2007_AGENT_SETTING_2_0 on SMS_G_System_CUSTOM_OPSMGR_2007_AGENT_SETTING_2_0.ResourceId = SMS_R_System.ResourceId where SMS_G_System_CUSTOM_OPSMGR_2007_AGENT_SETTING_2_0.ManagementGroup = "TYANG"
All OpsMgr agents managed by OpsMgr Management Server SCOM02:
select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_CUSTOM_OPSMGR_2007_AGENT_SETTING_2_0 on SMS_G_System_CUSTOM_OPSMGR_2007_AGENT_SETTING_2_0.ResourceId = SMS_R_System.ResourceId where SMS_G_System_CUSTOM_OPSMGR_2007_AGENT_SETTING_2_0.ManagementServer = "SCOM02.corp.tyang.org"
All OpsMgr Management Servers:
select * from SMS_R_System inner join SMS_G_System_CUSTOM_OPSMGR_2007_SERVER_SETTING_2_0 on SMS_G_System_CUSTOM_OPSMGR_2007_SERVER_SETTING_2_0.ResourceId = SMS_R_System.ResourceId where SMS_G_System_CUSTOM_OPSMGR_2007_SERVER_SETTING_2_0.IsServer = 1
Tags: Featured, Hardware Inventory, SCCM, SCOM
Posted by Tao Yang on 09/10/2011 in
SCCM |
∞
In SCCM, after removing WMI classes that are no longer required from configuration.mof and sms_def.mof, the inventory data still exists in few places.
If you decide to clean them up, MyITForum.com has a great WIKI page for SCCM hardware inventory which talked about different ways to clean up hardware inventory data.
I have tried the free SiteSweeper tool from SCCMExpert.com which was mentioned in the WIKI page. It’s easy to use and you can remove multiple classes from site database at once:

Other than removing the data from site databases throughout the hierarchy, the WMI class which you defined in the configuration.mof still exists in the client. I didn’t bother to look further to find tools/utilities to delete WMI classes, but simple found a sample vbscript from MSDN to modify WMI classes, and modified a little bit:
DeleteWMIClass.vbs:
wbemCimtypeString = 8 ' String datatype
Set objSWbemService = GetObject("Winmgmts:root\cimv2")
Set objClass = objSWbemService.Get()
objClass.Path_.Class = "<name of WMI class you wish to delete>"
' Remove the new class and instance from the repository
objClass.Delete_()
If Err <> 0 Then
WScript.Echo Err.Number & " " & Err.Description
Else
WScript.Echo "Delete succeeded"
End If
' Release SwbemServices object
Set objSWbemService = Nothing
To modify it, specify the WMI class you wish to delete on line 4. If the WMI class is not located in root\CIMV2 namespace, change line 2 as well.
I created a package in SCCM and advertised it to all systems.
Note: When you create the program, make sure you use the syntax “Cscript DeleteWMIClass.vbs” so the output is redirected to command prompt rather than a message box.
Tags: Hardware Inventory, SCCM, VBScript, WMI