Blog
By Andreas Zuckerhut on 11/11/2009 7:09:18 AM • Rank (3425) • Views 3591
1

1

This is a step-by-step guide in multiple parts:

Preface

Part 1 will cover the Class

Part 2 will cover the Probe Actions Module Type

Part 3 will cover the Data Source Module Type

Part 4 will cover the Discovery

Part 5 will be our Discovery Test

Part 6 will cover the Write Action Module needed for the Task

Part 6 will cover the On-Demand Discovery Task

Part 7 will be our On-Demand Discovery Task Test

As always be careful with the samples provided here. Always use a test environment first to try those examples!

Will only work with OpsMgr 2007 R2 and Authoring Console R2 !

 

Preface

It’s best practice to not just attach a Script to a single Workflow but create Modules holding the Scripts that can be used by Workflows like Monitors or Discoveries. In this Blog, I will walk you through creating a Management Pack that does just this, in the second Act I want to get into more detail on the Powershell side of this, therefore the coding stuff.

Also check out Stefan Koell’s Blog that covers the Monitors.

In this example we assume that we want to provide a Monitor that an Administrator can configure himself using the Registry. However, this example will only cover the Discovery and not the Monitor.

 

Part 1: Creating the Class

In the first step we create a class that has the properties for all the configuration parameters that are needed for the Monitor. In the case of the File Content Check Monitor we have: File and ErrorText. Additionally we need a Key-Property called: ID.

01

 

Open up the “Authoring Console” (needs to be installed separately and can be found on the SCOM R2 media) and let’s create a new management pack using File->New…->Empty Management Pack 

The MP ID is: code4ward.Sample.PowerShellDiscovery

The Display Name is: code4ward Sample PowerShell Discovery

 
02

 

Now let’s navigate to the Service Model space, and select Classes in the tree view.

Right-click in the Classes and select New->Custom Class.

Type in an ID: code4ward.Sample.PowerShellDiscovery.Classes.CheckFileContent

Type in a Name: Check File Content

Set the Base Class to: Microsoft.Windows.LocalApplication

 

Navigate to the Properties Tab.

03
image
05
 18

There's already a property there called DisplayName, it's a property every class has, and it must be set.

Additionally we create the following properties: File, ID and ErrorText

For this, right-click in the left pane under DisplayName and select Add Property.



Enter a name for the property: File

Click OK.


Additionally we give our property a Display Name: File














Repeat that process for the ErrorText property so we have both parameters that are needed.

For the ID property, do the same but tick the Key box.

Click Apply and OK.

 

Part 2: Probe Action Module

We are not going to just use a Script Discovery as we want to have our Script available for a Task as well. Therefore we will create a Probe Action Module first and afterwards a Data Source Module.

The Probe Action Module will contain the script and therefore the discovery Logic, the Data Source will then add the Interval and the SyncTime configurations that are needed so we can use it as a Discovery Module.

The reason for doing it this way is because we can use the Probe Action Module for a Task as well. Therefore if we just made changes to the Registry and need to discover them NOW we can just fire the On-Demand Discovery Task from the Console.

This is the configuration needed for the Probe Action later, it’s pretty much the same as a commond Discovery Script configuration but the SyncTime and Interval are not needed:

   1: <ScriptName>DiscoverFileContentChecks.ps1</ScriptName>
   2:                 <ScriptBody><![CDATA[
   3: param($mapElement, $targetID, $computerName, $debug) 
   4:  
   5: #Error-Handler
   6: trap 
   7: { 
   8:     continue;
   9: }
  10:  
  11: function Main
  12: {
  13:     trap{continue}
  14:     #Set Error and Debug Strings
  15:     $Error.Clear()
  16:     if ($debug -ne "true"){$debug = [bool]$false}else{$debug = [bool]$true}
  17:     $Script:Err             = @()
  18:     $Script:API             = new-object -comObject "MOM.ScriptAPI"
  19:     $Script:LOG_ERROR       = 1
  20:     $Script:LOG_WARNING     = 2
  21:     $Script:LOG_INFORMATION = 4
  22:     $Script:ScriptName      = "code4ward.Sample.PowerShellDiscovery.ps1"
  23:     $Script:Arguments       = "Received Arguments: `r MPElement = $mapElement, `rTargetID = $targetID, `rComputerName = $computerName, `rDebug = $debug"
  24:     
  25:     #Set the Discovery Object and the Check-Hive
  26:     $Script:Discovery        = $Script:API.CreateDiscoveryData(0, $mapElement, $targetID)
  27:     $Script:CheckHive         = "HKLM:\SOFTWARE\code4ward\SCOM"
  28:     
  29:     # Discover File-Content-Checks all Checks
  30:     Discover-FileContentChecks("$Script:CheckHive\FileContentChecks")
  31:     
  32:     #Return Discovery Data
  33:     Write-DebugInfo("Returning Discovery Data")
  34:     $Script:Discovery
  35: }
  36:  
  37: function Discover-FileContentChecks([string]$fileContentChecksPath)
  38: {
  39:     Write-DebugInfo("Running Discovery for the FileContentChecks")
  40:     
  41:     if (-not (Test-Path $fileContentChecksPath))
  42:     {
  43:         Write-DebugInfo("The path specified for the FileContentChecksPath [$fileContentChecksPath] can't be found on this computer, skipping this Discovery.")
  44:     }
  45:     else
  46:     {
  47:         $FileContentChecks = @(Get-ChildItem $fileContentChecksPath)
  48:         
  49:         foreach ($FileContentCheckPath in $FileContentChecks)
  50:         {    
  51:             #Get Values and add them to Variables
  52:             #Inherited Properties
  53:             $PropertyName = $FileContentCheckPath.Name.Replace($fileContentChecksPath.Replace("HKLM:", "HKEY_LOCAL_MACHINE") + "\", "")
  54:             $PropertyID = "FileContentCheck." + $PropertyName.Replace(" ", "")
  55:             
  56:             #Class-Properties
  57:             $PropertyFile = $FileContentCheckPath.GetValue("File")
  58:             $PropertyErrorText = $FileContentCheckPath.GetValue("ErrorText")
  59:       
  60:       write-debuginfo("Received Name: $PropertyName ID: $PropertyID File: $PropertyFile ErrorText: $PropertyErrorText")
  61:                         
  62:             $Instance = $Script:Discovery.CreateClassInstance("$MPElement[Name='code4ward.Sample.PowerShellDiscovery.Classes.CheckFileContent']$")
  63:             $Instance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", $PropertyName)
  64:             $Instance.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $computerName)
  65:             $Instance.AddProperty("$MPElement[Name='code4ward.Sample.PowerShellDiscovery.Classes.CheckFileContent']/ID$", $PropertyID)
  66:             $Instance.AddProperty("$MPElement[Name='code4ward.Sample.PowerShellDiscovery.Classes.CheckFileContent']/File$", $PropertyFile)
  67:             $Instance.AddProperty("$MPElement[Name='code4ward.Sample.PowerShellDiscovery.Classes.CheckFileContent']/ErrorText$", $PropertyErrorText)
  68:             
  69:             #Return Instance to Discovery Data
  70:             Write-DebugInfo("Adding discovered Instance to Discovery")
  71:             if(-not $Error.Count -gt 0){$Script:Discovery.AddInstance($Instance)}else{Write-ErrorInfo("Discover-FileContentChecks-$TargetID")}
  72:         }  
  73:     }
  74: }
  75:  
  76: function Write-DebugInfo
  77: {
  78:     param ([string] $msg)
  79:     if ($debug -eq $true) 
  80:     {
  81:         $API.LogScriptEvent("$ScriptName",100,$Script:LOG_INFORMATION,"`r$Arguments`r`r$msg")
  82:     }
  83: }
  84:  
  85: function Write-WarningInfo
  86: {
  87:     param ([string] $msg)
  88:     $API.LogScriptEvent("$ScriptName",200,$Script:LOG_WARNING,"`r$Arguments`r`r$msg")
  89: }
  90:  
  91: function Write-ErrorInfo
  92: {
  93:     param ([string] $msg)
  94:     $API.LogScriptEvent("$ScriptName",500,$Script:LOG_ERROR,"`r$Arguments`r`r$msg")
  95: }
  96:  
  97: #Call the MainFunction
  98: Main
  99:        ]]></ScriptBody>
 100:                 <Parameters>
 101:                   <Parameter>
 102:                     <Name>MapElement</Name>
 103:                     <Value>$Config/MapElement$</Value>
 104:                   </Parameter>
 105:                   <Parameter>
 106:                     <Name>TargetID</Name>
 107:                     <Value>$Config/TargetID$</Value>
 108:                   </Parameter>
 109:                   <Parameter>
 110:                     <Name>ComputerName</Name>
 111:                     <Value>$Config/ComputerName$</Value>
 112:                   </Parameter>
 113:                   <Parameter>
 114:                     <Name>Debug</Name>
 115:                     <Value>$Config/Debug$</Value>
 116:                   </Parameter>
 117:                 </Parameters>
 118:                 <TimeoutSeconds>600</TimeoutSeconds>

 

07

Navigate to the Type Library space, and select Type Library\Module Types\Probe Actions in the tree view.

Right-click in the Probe Actions and select New->Composite Probe Action.

Type in an ID: code4ward.Sample.PowerShellDiscovery.Probe.DiscoverFileContentCheck

Type in a Name: Discover File Content Check

 

Switch to to the Member Modules Tab.

 

 

08
Click Add... and look for microsoft.windows.powershelldiscoveryprobe.

Select it, give it an ID and click OK.
09
You will then be prompted for the Configuration.

Click Edit... (I personally use Notepad as the Editor, if you want to use something else, feel free to do so.
 10

Replace the XML stuff inside the <Configuration> element with the code above.

Save and close.

11
As you may notice, the values for the parameters are using variables $Config/TargetID$. We are going to create them soon.

Click OK.







 
12
Select Module Output in the drop down list in the Next Module column.

Switch to the Configuration Schema Tab.
13
Under Simple Configuration Schema click Add...

Enter the name: MapElement

Click OK and verify that it's type is String.

Do the same for TargetID and ComputerName.

For Debug, do the same but set it's type to Boolean.


Switch to the Overrideable Parameters Tab.
14
15
16

Click Add...












Choose MapElement and give it the unique identifier MapElement, click OK.





Verify that the type in the Configuration Element column is String.

Do the same for TargetID and ComputerName.

For Debug, do the same but set it's type to Boolean.


Switch to the Data Types Tab.
17

 

Set the Input Data to This module requires Input data and in the drop-down list choose System.BaseData.

Set the Output Data Data Type to: System.Discovery.Data

 

 

Switch to the Options Tab.

18

Change the Accessibility property to Public. This is optional and may be useful when you seal your MP and provide these modules to use in other MPs.

Click Apply and OK.

 

Part 3: Data Source Module

19
20

Navigate to the Type Library space, and select Type Library\Module Types\Data Source in the tree view.

Right-click in the Probe Actions and select New->Composite Data Source.

Type in an ID: code4ward.Sample.PowerShellDiscovery.DataSource.DiscoverFileContentCheck

 

Type in a Name: Discover File Content Check

 

Switch to to the Member Modules Tab.

21
Click Add... and look for code4ward, you should find our previously created Probe Module.

Select it, give it an ID and click OK.
22
23
24

You are then prompted for the configuration of the Module.

Clear all the values.











At each value box, click the arrow on the right side and choose Promote.









Once finished, click Apply and OK.
25
We need an additional Member Module now that extends the Data Source with the Interval and SyncTime configurations needed for the Discovery Module later.

In the Member Modules Tab click Add... and look for System.Discovery.Scheduler

Select it, give it an ID and click OK.
26
You will then be prompted for the configuration.

Clear the Interval and SyncTime and use the right arrow next to these values again and choose Promote.

Click Apply and OK.
27
Now we need to configure the sequence order of the Member Modules.

At the Discovery Scheduler set the Next Module to the ID of the Discovery Probe.

At the Discovery Probe set the Next Module to Module Output.

Consider the Discovery Scheduler as our trigger that then launches the Discovery Probe.


Switch to the Configuration Schema Tab.
28
As you can see, the Simple Configuration Schema items have already been created. That's what Promote did earlier.

All we need to do is changing the Type of Debug to Boolean.


Switch to the Overridable Parameters Tab.
15
 29

Click Add...

Choose MapElement and give it the unique identifier MapElement, click OK.


Verify that the type in the Configuration Element column is String.

Do the same for TargetID, ComputerName and SyncTime.

For Debug, do the same but set it's type to Boolean.

For Interval, do the same but set it's type to Integer.


Switch to the Data Types Tab.
30

Set the Output Data Data Type to: System.Discovery.Data

 

 

Switch to the Options Tab.

31

Change the Accessibility property to Public. This is optional and may be useful when you seal your MP and provide these modules to use in other MPs.

 

Click Apply and OK.

01
02
03

It can happen that the values in the Probe Action Module configuration get cleared which causes an error once you click Apply.

In this case, switch back to the Member Modules Tab and edit the Probe Action Module again.

As you can see (in case it happened), the previously created values were cleared, I guess this is some weird Authoring Console Bug that may be fixed by now (with the new version containing the Workflow Debugger).








On the right side of each value click the arrow and select the matching $Config\.

For MapElement it’s $Config\MapElement$

For TargetID it’s $Config\TargetID$

And so on…



Once finished click Apply, Apply, OK.

 

Part 4: Discovery

Now that our modules are ready, we can create the actual Discovery. The Discovery will use the DataSource module we just created and will discover instances of the class we created earlier.

19   

Navigate to the Health Model space, and select Discoveries in the tree view.

Right-click in the Discoveries and select New-> Custom Discovery

Type in an ID: code4ward.Sample.PowerShellDiscovery.Discoveries.DiscoverFileContentCheck

04

 

Type in a Name: Discover File Content Checks

Change the Target to: Microsoft.Windows.OperatingSystem

 

Switch to the Discovered Classes Tab.

21

At Discovered Classes and their attributes click Add... and select Add discovered type.

22

Look for code4ward and you should find our previously created class.

Select it and click OK.

 

Switch to the Configuration Tab.

45
Click Browse for a type...
32

Look for code4ward and you should find our previously created DataSource Module.

Select it, give it an ID and click OK.

33
Now we need to configure our Discovery. SyncTime, IntervalSeconds and Debug is variable. Therefore adjust them so they fit your needs. (For testing you should set the IntervalSeconds way lower).

SyncTime: 00:00
IntervalSeconds: 600
MapElemenet: $MPElement$
TargetID: $Target/Id$
ComputerName: Click the arrow on the right side and choose Principal Name under (Host = Windows Computer).
Debug: true

Click Apply and OK.

 

Part 5: Testing the Discovery

So, now that we have our discovery ready we want to test it of course. For this we will create our Registry Keys and import the Management Pack, afterwards we will check the Discovered Inventory to see if our Instance has actually been discovered.

34
Open the Registry on the machine of your choice with Start->Run->regedit->OK
35
Open the HKEY_LOCAL_MACHINE tree, right-click SOFTWARE and choose New->Key

36

Name it code4ward and hit Enter.
37
Under code4ward create another Key SCOM, under SCOM create another Key FileContentChecks and under FileContentChecks another Key called TestCheck (or anything else, this will be the DisplayName of our Check and it will also be contained in our ID).
38
39
40

Time to configure it. All we need to provide now are 2 String Values called File and ErrorText.

Select the TestCheck Key, and in the right pane right-click, New->String Value.




Name it File, double-click it and give it a Value data: c:\test.txt <- or something else.





Create another String Value called ErrorText and give it some Value Data like: ERROR.

Now we have everything set up in the Registry so we have some data we can discover. Time to Import our Management Pack.

41
42

In the Authoring Console click File->Save As->Standard Management Pack





And drop it somewhere called: code4ward.Sample.PowerShellDiscovery.xml
43
Now it's time to switch to the Operations Console.

Let’s navigate to the Administration space, right-click Management Packs in the tree-view and select Import Management Packs...

 

 

44
45

Click Add->Add from disk...











We don't need to search for dependencies, therefore click No.
46
Locate the Management Pack, select it and click Open.
47
Next, click Install and wait for the Import process to be finished.
48

Navigate to the Monitoring space, select Discovered Inventory in the right pane under Actions select Change Target Type...

Look for code4ward and you should see our Class we created in the Management Pack.

Select it and click OK.

49
And after a while, depending on the Interval you chose and the SyncTime, our Instance should be discovered. In our case the Discovery will run at every full 10 minutes, therefore 15:00, 15:10, 15:20 and so on.

If it doesn't, check the Event Log for Operations Manager, the Debug Information and Error Information from the Script should be there.

 

Part 6: Write Action Module

Since our Discovery Probe only provides the Discovery Data and doesn't write into the Operations Manager Database we need an additional module that does that Write Action for us.

78

Open up the Authoring Console again and open our previously created Management Pack.

Navigate to the Type Library space, and select Module Types->Write Actions in the tree view.

Right-click in the Write Actions and select New-> Composite Write Action...

63
Give it the ID: code4ward.Sample.PowerShellDiscovery.WriteAction.OnDemandFileContentCheckDiscovery

Click OK.
64
Give it the Display Name: Discover File Content Check

Switch to the Member Modules Tab.
65
Click Add... and look for System.Discovery.PublishData

Select it, give it an ID and click OK.
66
Leave the configuration alone and just click OK.
67
Since we need our Discovery Probe as well, click Add... again and look for code4ward.

You'll find 2 available modules, choose the one of type Probe Action.

Give it an ID and click OK.
 
68
You are then prompted for the configuration of the module.

Clear all the values and use the right arrow next to each value and choose Promote.
69
For the module Write Action choose Module Output as NextModule.

For the module Probe Action choose the Write Action as NextModule.

This launches the Probe Action first and then forwards the Discovery Data to the Write Action.


Switch to the Configuration Schema Tab.
70
As you can see, the Simple Configuration Schema items have already been created (by Promote).

Verify that ComputerName, MapElement and TargetID are of Type String and that Debug is of Type Boolean.


Switch to the Overridable Parameters Tab.
71

Click Add...

Choose MapElement and give it the unique identifier MapElement, click OK.

Verify that the type in the Configuration Element column is String.

Do the same for TargetID and ComputerName.

For Debug, do the same but set it's type to Boolean.

 

Switch to the Data Types Tab.

79
Verify that the Input Data type is System.BaseData.


Switch to the Options Tab.
73

Change the Accessibility property to Public. This is optional and may be useful when you seal your MP and provide these modules to use in other MPs.

Click Apply and OK.

01
02
03

It can happen that the values in the Probe Action Module configuration get cleared which causes an error once you click Apply.

In this case, switch back to the Member Modules Tab and edit the Probe Action Module again.

As you can see (in case it happened), the previously created values were cleared, I guess this is some weird Authoring Console Bug that may be fixed by now (with the new version containing the Workflow Debugger).







On the right side of each value click the arrow and select the matching $Config\.

For MapElement it’s $Config\MapElement$

For TargetID it’s $Config\TargetID$

And so on…



Once finished click Apply, Apply, OK.

 

Part 7: On-Demand Discovery Task

So, finally we can create our Task using the previously created Write Action module.

50

Navigate to the Health Model space, and select Tasks->Agent Tasks in the tree view.

Right-click in the Agent Tasks and select New-> Custom Task

 

51
Give it the ID: code4ward.Sample.PowerShellDiscovery.AgentTasks.OnDemandFileContentCheckDiscovery and click OK.

52
For Display Name: Discover File Content Checks

And for Target: Microsoft.Windows.Computer


Switch to the Configuration Tab.
80
Click Browse for a Type... and look for code4ward.

You should find 2 modules, Discovery Probe and the Write Action we created earlier.

Select the one containing WriteAction, give it an ID and click OK.
58
Now we need to configure our Write Action. Debug is variable. You can set it to false as well.

MapElemenet: $MPElement$
TargetID: $Target/Id$
ComputerName: Click the arrow on the right side and choose Principal Name.
Debug: true
 
55
Since we want to verify that the Task works we will now disable the Discovery.

Navigate to the Health Model space, select Discoveries and open the properties of our Discovery.

56
Switch to the Options Tab.

Set Enabled to false.


Now save the Management Pack again.

 

Part 8: Testing the Agent Task

59


 05

In the Operations Console, delete the previous Management Pack first (so our previously discovered Instance gets deleted) and import the "new" one.

Navigate to the Monitoring space, and select Windows Computers in the tree view.

 

Select the Computer on which you created the Registry Keys and in the right pane under Windows Computer Tasks click Discover File Content Checks.

 

In the Run Task configuration you can override parameters, the only interesting parameter here would be the Debug parameter. Since it's already set to true and the rest looks just fine, click Run.

 

61

The Task will then start to run. Wait for it to be finished.

06
Once finished, you'll receive an Information that it was either successful or not.

49

Navigate to Monitoring again and select Discovered Inventory in the tree-view.

Change the Target to our class again and check if it's been discovered.

If it doesn't, check the Event Log for Operations Manager, the Debug Information and Error Information from the Script should be there.
Comments (3) - Comment RSS
Pete Zerger wrote: on Nov 08, 2009 06:41 PM
Awesome as usual. Just tweeted this to TechEd twitter feed...
Andreas Zuckerhut wrote: on Nov 09, 2009 04:08 AM
Yea, had problems with the Screenshots though, gotta ask Stefan how he did it as mine are not clickable. I'm wondering though what drove some person to give 1,5 stars for this without commenting it ^^ Tested this back and forth and it should work just fine.
Pete Zerger wrote: on Nov 09, 2009 05:27 PM
He's probably using Live Writer. I am going to send you some info offline in hopes I can be helpful.


Who Viewed
Who Reviewed
Categories
Related Pages
Shortened URL
http://tinyurl.com/yhkl3f7

Top Contributors
Featured Members
Pete Zerger
Points: 72533
Level: System Center Expert
Tommy Gunn
Points: 47345
Level: System Center Expert
Simon Skinner
Points: 40804
Level: System Center Expert
Andreas Zuckerhut
Points: 30700
Level: System Center Expert
Stefan Koell
Points: 30179
Level: System Center Expert