How to use .NET managed code in a Management Pack for Operations Manager 2007 R2 - Part 1 - The Overview

How to use .NET managed code in a Management Pack for Operations Manager 2007 R2 - Part 1 - The Overview

 

I recently attended and participated in the Microsoft Management Summit 2011 (MMS 2011) in Las Vegas, NV. While I was working at the Datacenter Services booth I was approached by a guy that asked me a question "Hey is there any way to use .NET code in a management pack?" I responded and told him that there's nothing native that supports using .NET code, but since the arrival of R2 there is a native PowerShell provider that will allow you to do pretty much everything in .NET in PowerShell. After a lengthy conversation I was then left with the curiosity of can it be done? Is there an easy supportable and efficient way to implement .NET code in a management pack? The answer is YES! This post will provide an overview of how I accomplished the task.

The PowerShell Add-Type Cmdlet (The secret sauce)

 

When I started to research this possibility, I discussed this with a co-worker Don and he led me to the PowerShell Add-Type cmdlet ( https://technet.microsoft.com/en-us/library/dd315241.aspx) . This cmdlet allows you to define a .NET class in your PowerShell script. As you can see from the TechNet example below, you simply create a variable and encapsulate your .NET code within the @" <.NET code here> ". You can then instantiate your class for use.

 

C:\PS>$source = @"

public class BasicTest

{

    public static int Add(int a, int b)

    {

        return (a + b);

    }

 

    public int Multiply(int a, int b)

    {

        return (a * b);

    }

}

"@

 

C:\PS> Add-Type -TypeDefinition $source

 

C:\PS> [BasicTest]::Add(4, 3)

 

C:\PS> $basicTestObject = New-Object BasicTest

C:\PS> $basicTestObject.Multiply(5, 2)

 

 

Creating the PowerShell Script

 

Now that I have an understanding of how to encapsulate .NET code in a PowerShell script, I now need to come up with an example to use. I've found this to be the most challenging part because everything I could code in .NET I could do in PowerShell and in most cases with much less lines of code. So I decided to go with a common example in the management pack documentation, I will return the number of files in a folder.  This is the C# class I will use below.

public static int FileCount(string FolderName)

        {

            string s = FolderName;

            int files;

 

            System.IO.DirectoryInfo f = new System.IO.DirectoryInfo(FolderName);

            files = f.GetFiles().Length;

 

            return files;

        }

 

So from looking at the C# class, it is roughly 8 lines of code. Compared to doing the functionality in PowerShell in one line of code like this (Get-ChildItem C:\Temp).Count . Again if it was me I would just write a PowerShell script and use the native script module provider in R2, but since this post is about using .NET code in a management pack we will continue on. Also one thing to note is I had to fully qualify my method calls such as System.IO.DirectoryInfo whereas if you are using a directive such as "using System.IO;" I could just call DirectoryInfo instead of System.IO.DirectoryInfo. I'm sure there's a way to utilize directives, but I just did not investigate all the Add-Type cmdlet options and in my testing the script didn't work when using it.

Now that I know what I want to monitor and have my .NET C# class, I now need to put it in a script for Operations Manager to consume.  Below is the PowerShell script containing the .NET C# class that I will use when creating the management pack.

param([string]$MonitoredFolder)

 

$api = New-Object -comObject 'MOM.ScriptAPI'

               

$api.LogScriptEvent("CheckFolderFileCount.ps1",101,4,"Script started.")

$api.LogScriptEvent("CheckFolderFileCount.ps1",101,4,"The monitored folder is $MonitoredFolder")

 

$bag = $api.CreatePropertyBag()

 

$CSharpCode = @"

 

public class Folder

{

   

   

    public static int FileCount(string FolderName)

        {

            string s = FolderName;

            int files;

 

            System.IO.DirectoryInfo f = new System.IO.DirectoryInfo(FolderName);

            files = f.GetFiles().Length;

 

            return files;

        }

   

}

"@

 

Add-Type -TypeDefinition $CSharpCode

 

$api.LogScriptEvent("CheckFolderFileCount.ps1",101,4,"The amount of files in $MonitoredFolder is {0}" -f [Folder]::FileCount($MonitoredFolder))

 

$bag.AddValue('FolderFileCount', '[Folder]::FileCount($MonitoredFolder)')

 

$bag

 

$api.LogScriptEvent("CheckFolderFileCount.ps1",101,4,"Script complete.")

 

Part 2 of this post will discuss implementing the script into a custom management pack.