Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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.