How to create a PowerShell task for OpsMgr using the Authoring Console

This is a step-by-step guide on how to create a PowerShell tasks using the authoring console.This will only work for OpsMgr R2 installations!

I am not exactly a certified-OpsMgr-under-the-hood-specialist – I had the honor to be part of a workshop where Brian Wren (http://blogs.technet.com/brianwren/) revealed some OpsMgr secrets. So this post is for one part storing my gained knowledge in the Interwebz so that Google can index it and I can find it again, another part of course is to give something back to the community. So if you have suggestions for improvements or any questions, go ahead and comment on this post.

For this guide we create a task which allows us to set a registry value on a remote machine.

Why do we want to do this? First of all, it is a great example to show some concepts behind Module Types. Secondly, we use a task like this to set some custom computer attributes. We use some additional computer attributes to mark a computers productive, test, etc. We do that by looking for a registry value and discover these attributes (maybe a topic for another guide). To easily move a computer from test to production we just need to set a registry value.

Here a short overview of this blog post:

  1. We need a PowerShell script: SetRegistryValue.ps1
  2. We will create a generic module type allowing us to set any registry value
  3. We will create a wrapper for this module type to set a registry value in a specific key using our generic module type
  4. We will create an agent task consuming this module and provide two overridable parameters. One for debugging, and one providing the value for the registry

1. The Script:

# Script Name:  SetRegistryValue.ps1
# Parameter 1:  path  (e.g. "HKLM:SoftwareSomekeySomesubkey")
# Parameter 2:  name  (e.g. "SomeValueName")
# Parameter 3:  value (e.g. "SomeValue")
# Parameter 4:  type (e.g. "String", "Binary", "DWord", "MultString", "ExpandString")
# Parameter 5:  debug (e.g. "false", "true")
# -----------------------------------------------------------------------------
# Parameters
param([string]$path,[string]$name,[string]$value,[string]$type,[string]$debug)

if ($debug -ne "true"){$debug = [bool]$false}else{$debug = [bool]$true}
$Script:API = new-object -comObject "MOM.ScriptAPI"
$Script:LOG_ERROR       = 1
$Script:LOG_WARNING     = 2
$Script:LOG_INFORMATION = 4
$Script:ScriptName = "SetRegistryValue.ps1"
$Script:Arguments  = "Received Arguments: `rPath='$path' `rName='$name' `rValue='$value' `rDebug='$debug'"

function Write-DebugInfo
{
    param ([string] $msg)
    if ($debug) 
    {
        $API.LogScriptEvent("$ScriptName",100,$Script:LOG_INFORMATION,"`r$Arguments`r`r$msg")
    }
}
function Write-ErrorInfo
{
    param ([string] $msg)
    $API.LogScriptEvent("$ScriptName",500,$Script:LOG_ERROR,"`r$Arguments`r`r$msg")
}

Write-DebugInfo("Script started.")

# check if registry key exists
if (Test-Path $path)
{
    Write-DebugInfo("Path $path found in registry.") 
}
else
{
    Write-DebugInfo("Path $path doesn't exist. Creating registry keys...")
    New-Item -Path $path -force | Out-Null
}
New-ItemProperty -Path $path -name $name -value $value -Type $type -force | Out-Null
Write-DebugInfo("Registry value $value of type $type in $path $name created/updated.")
Write-Host "Registry value $value of type $type in $path $name created/updated."
Write-DebugInfo("Script ended.")

This script will create/set a registry value of a specific type. Disclaimer: Use this at your own risk. Always use a test environment! Writing/Overwriting registry values can harm your system. You really need to know what you are doing! There’s also no error handling in this script and it’s far from production quality! Works on my machine!

2. Generic Module Type to Set a Registry Value

Now let’s start up the authoring console and create a new empty management pack using the “File->New…” menu command:
In my example the MP ID is “code4ward.Sample”
The friendly name is “code4ward Sample”
Of course you can use your own IDs and names.

Now let’s navigate to the “Type Library” space and select “Probe Actions” in the “Module Types”:
Right-click in the Probe Actions pane and select “New->Composite Probe Action…” command.
Set the ID to “code4ward.Sample.Action.SetRegistryValue”. Click OK; the property pages for this new module type will open.
Name it “Set Registry Value”

Here we are going to create a very generic module of our own, capable of settings registry values on a target machine.

Change to the “Member Modules” tab and click on “Add…”.
Look for: “PowerShellProbe”, select the “Microsoft.Windows.PowerShellProbe” and specify a Module ID – in my case the ID is “Script”. Click OK.
Some of the modules are documented on Technet already (more to come soon): http://technet.microsoft.com/en-us/library/dd789057.aspx

Now the configuration window for the PowerShellProbe opens up. Click on “Edit…” and if not already configured, choose a text editor (notepad.exe) to open the configuration in an external editor.

Now we need to fill in the configuration of this PowerShellModule:
Type a script name “SetRegistryValue.ps1” in the ScriptName tags, copy the script above into the ScriptBody tag, be sure to wrap a “” tag around it (without the quotes), set the TimeoutSeconds to 300 or something.
Note that there’s no Parameters section in the configuration XML when we open it. We need to create our own. Also note that the script on top of this post allows named parameters. For each Parameter in your script create a parameter element containing the Name element which must correspond to the actual name of the parameter (this is not case-sensitive) and a value element like “$Config/SomeValue$. The name of the value element is important when we wrap another module type around it. This basically says, the value will be submitted to the module from its consumer (task or other module, etc.).
It is also very important that the Parameters element is right after the ScriptBody element(see screenshot!).

Before we continue, we also need to select “Module Output” in the “Next Module” column.

Now let’s continue to the “Configuration Schema” tab.
Just add all the parameters of the script using the the “Add…” button in the “Simple Configuration Schema” section.
Verify, that every parameter has the appropriate type selected (in our case Debug must be a boolean, all other parameters are strings (default)).

Next stop: Overridable Parameters
Use the “Add… “ button at the bottom to enable overrides for all parameters (I used the same names as the parameters to avoid confusion).

Next stop: Overridable Parameters
Use the “Add… “ button at the bottom to enable overrides for all parameters (I used the same names as the parameters to avoid confusion).
Now we created a very generic module allowing us to set any registry values. Now let’s pretend we need to set in HKLM:Softwarecode4ward the value “Environment” to some value. Let’s wrap another module type around the one we just created:

3. The Wrapper Module Type

As explained above, right-click and select “New->Composite Probe Action…” and type in an ID like “code4ward.Sample.SetRegistryEnvironment” and a name like “Set Registry Environment”.
In the “Member Modules” tab we add our previously created module and provide an ID like “Probe”. The configuration of our module looks like this:

Next to the value and debug field you can use the “Promote” menu item to automatically fill in the $Config/…$
Using this configuration, we tell our new module to consume our previously created module where the Path, Name and Type parameter is pre-set and the value and debug parameter will be set by it’s consumer (later on by the task or by providing an override).
Also be sure to select “Module Output” in the “Next Module” column.

Now we only need to provide two configuration values (all the others are pre-set). Be sure that the Debug type is Boolean.

Also create two overridable parameters, only this time we call the $Config/Value$ parameter “Environment”. This is the name presented to you by the override dialog!
In the next tab “Data Types” we also need to check “This module requires input data” again.
Click on “OK” and save your MP.
So far we are ready with our modules.

4. Now let’s put all together to create a Task

Let’s switch to the “Health Model” space and select “TasksAgent Tasks”. Right-click on the Agent Task panel and select “New->Custom Task”. Provide an ID like “code4ward.Sample.Task.SetEnvironment” and a display name “Set Environment”. As target we select “Microsoft.Windows.Computer” – this way we can use the task in the computers state view.

In the “Configuration” tab, click on the “Browse for a type” link and select the “code4ward.Sample.SetRegistryEnvironment” module type we created before.

After we selected the module type, we can pre-set the parameters. In our case we leave the value blank and should be specified using an override, the debug parameter is set to false by default and can be set to true for debugging using the override parameters dialog.

Here the result:

You can download this MP here:code4ward.Sample.xml

I am also thinking of posting a step-by-step guide like this one on how to set up a 2 state monitor using a powershell script with the “Recalculate Health” ability. If you’re interested in such a guide, please let me know and give me some feedback?

Leave a Reply