Writing C# applications to do complex monitoring with SCOM

I ran into an issue where I needed to count the number of xml files in a directory.  The problem was there are 10,000 other files in the directory.  The application team didn’t care about the extra files and didn’t want to clean them out.  All they wanted to know was when the number of XML files was over 15.

First I tried a basic vb script, like this.

 

Set objFSO=CreateObject(“Scripting.FileSystemObject”)

Set oArgs = WScript.Arguments

 

FolderName = oArgs(0)

Set objFolder=objFSO.GetFolder(FolderName)

 

Set Dirfiles = objFolder.Files

 

Int filecount = 0

 

For each file In Dirfiles

 

            sext = objFSO.GetExtensionName(file.Path)

     

If LCase(sext) = “xml” Then

           

            filecount = filecount+1

     

End If     

      Next

           

 WScript.Echo filecount

 

This works fine in a directory with only a few files but my directory has 10,000 other files in it.  I ran this script waited 10 minutes and then canceled it.  Obviously this was not going to work as the script has to touch every file in the directory.  Operations Manager would time out way before the script finishes.

So after many Google and Bing searches looking for a different vb scripts to count only the xml files, I decided to see how easy it would be in C#.

In C# it was a piece of cake.  You can download the C# project file with source here.
http://www.scom2k7.com/downloads/filecount.zip 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

 

namespace filecount

{

    class Program

    {

        static void Main(string[] args)

        {

 

            string directoryPath = args[0];

            string eXtension = “*.” + args[1];

 

 

            int fileCount = System.IO.Directory.GetFiles(directoryPath,

            eXtension).Length;

 

            Console.WriteLine(fileCount);

 

        }

    }

}

 

I ran the executable that visual studio created with two parameters “directory” and “extension” and it took one second to count the number of xml files in the directory.  This is what I was looking for, way faster and more efficient. 

Commandline

So now I have a working executable the takes two parameters.  How do I get it to work with SCOM? 

The easiest way was to remove the Console.WriteLine(fileCount) and set the count to the exit code. 

 

Environment.Exit(fileCount);

 

Now all I need to do is wrap this executable with a vbscipt and have SCOM call it. You can download the vb script here. http://www.scom2k7.com/downloads/advanced.zip

 

Dim oAPI, oBag, objShell, objFSO, objFile, myCMD, bWaitOnReturn, returnCmd, oArgs

 

Set oAPI = CreateObject(“MOM.ScriptAPI”)

Set oBag = oAPI.CreateTypedPropertyBag(StateDataType)

Set oArgs = WScript.Arguments

 

If oArgs.Count < 3 Then

Call oAPI.LogScriptEvent(“FileCountCSharp.vbs”, 500, 0, “Script aborted. Not enough parameters provided.”)

WScript.Quit -1

End If

 

folder = oArgs(0)

extension = oArgs(1)

userCount = cint(oArgs(2))

 

bWaitOnReturn= True

 

 

Set objShell=CreateObject(“WScript.Shell”)

Set objFSO=CreateObject(“Scripting.FileSystemObject”)

 

 

strPath=“C:\ScomTools\filecount.exe”

 

If objFSO.FileExists(strPath) Then

set objFile=objFSO.GetFile(strPath)

 

 

myCMD = strPath & ” “ & folder & ” “ & extension

returnCmd = objShell.Run (myCMD,0,bWaitOnReturn)

 

Else

 

Call oAPI.LogScriptEvent(“filecount.exe”, 510, 0, “Can’t find EXE to run Script”)

WScript.Quit

 

End If

 

If returnCmd > userCount Then

 

            strReturn = userCount

           

            Call oBag.AddValue(“State”,“BAD”)

            Call oBag.AddValue(“ret”,strReturn)

 

      Else

 

            Call oBag.AddValue(“State”,“GOOD”)

 

End If

 

Call oAPI.Return(oBag)

 

To test it I ran this command cscript c:\temp\newtest.vbs “c:\temp” “xml” 4 saying if there are more than 4 files in the directory and should return BAD state and how many files actual files are in the directory.  This is what I got back.

 

<DataItem type=”System.PropertyBagData” time=”2009-06-17T10:58:59.3066298-04:00″
sourceHealthServiceId=”B3B5A38D-0DBE-5CA9-592D-B76333A989D8″>
<Property Name=”State”VariantType=”8″>BAD</Property>
<Property Name=”ret” VariantType=”3″>5</Property></DataItem>

 

Looks good now to test a good condition.  cscript c:\temp\newtest.vbs “c:\temp” “xml” 25 saying if there is more than 25 xml files create an alert.  There is not  more than 25 files so the scom script should return good.

 

<DataItem type=”System.PropertyBagData” time=”2009-06-17T10:59:34.5256052-04:00″
sourceHealthServiceId=”B3B5A38D-0DBE-5CA9-592D-B76333A989D8″>
<Property Name=”State” VariantType=”8″>GOOD</Property></DataItem>

 

Command2

Ok now we have a good working script and c# executable.  Now we just need to put the script into a monitor and copy the file to the server we want to monitor and we are done.  You can follow these directions if you don’t know how to put the script into a monitor.  http://www.scom2k7.com/create-a-script-based-unit-monitor-in-opsmgr2007-via-the-gui/

So now think of the possibilities.  Anything that can be called from C# can now be monitored in SCOM.  SDKs, APIs, Web Services, are all easily leveraged in C#.    The only downside is you need the executable on the server the monitor is running on, but that could be fixed by having the script to check for the executable and if it wasn’t there you could copy it from a centralized network location.

 

10 Responses to Writing C# applications to do complex monitoring with SCOM

  1. Tao June 21, 2009 at 6:50 am #

    the vbscript you used was filtering the result on the client side. of cause it is going to be slow. and the code in C# uses server side filtering, that’s why it’s much quicker.

  2. Tim June 21, 2009 at 10:52 am #

    Not true. I am copying the C# application down to the client that I running it on. They both are running on the client. The reason it is so much quicker is that in the vbscirpt I am touching every file. In the c# program I am just hitting the directory and using the System.IO.Directory.GetFiles method on the directory. This is much more efficient as it just hits the directory. Vbscrpt doesn’t have this method, but the real point was to show how to you can write c# apps and leverage them in SCOM.

  3. marcus July 2, 2009 at 8:55 am #

    hey tim – great blog & info. i don’t have a directory with enough files to process but was curious if you would have achieved better results digging through with wmi – such as:

    sComputer = “.”
    Set oWMIService = GetObject(“winmgmts:” _
    & “{impersonationLevel=impersonate}!\\” & sComputer & “\root\cimv2”)

    Set cFiles = oWMIService.ExecQuery(“Select * from CIM_DataFile where Drive = ‘c:’ and Path = ‘\\temp\\’ and Extension = ‘xml'”)

    i = 0
    For Each oFile in cFiles
    Wscript.Echo oFile.Name
    i = i + 1
    Next

    WScript.Echo “Count: ” & i

  4. Tim July 7, 2009 at 9:56 am #

    I would bet that will work as well. I figured there was a way to do it in VB as well. Good Stuff

    Thanks

  5. Hu Bo September 21, 2009 at 4:40 am #

    I would bet it is much easier to use powershell

    [int]([object[]](dir *.xml)).length

  6. Tim September 28, 2009 at 8:31 pm #

    Nice work. I prefer C# as everything is exposed and only requires the .net framework which is installed more often then powershell on our servers.

  7. Mukul July 31, 2012 at 5:54 am #

    Hey Tim,

    This is really helpful. I am looking to go an extra mile.
    I want to do something similar like:
    1. Instead of returning filecount from C# application, can i return an object to VbScript and utilize the same object into VbScript code.
    2. If a list of objects is returned, what changes will be there in C# and VbScript.
    3. I tried below code as well:
    MOMScriptAPI MA = new MOMScriptAPI();
    dynamic d = MA.CreatePropertyBag();
    d.AddValue(“Key”, “Value”);
    MA.Return(d);

    But how to place this code in C# application and how to return the MOMScriptAPI object to SCOM.

    A quick help is appreciated.

  8. Mukul August 3, 2012 at 12:35 am #

    Tim,

    I was doing the things same way but want to return a list of objects instead of a file.
    Can you please help on this. I want to return data after connecting to a device and getting some device configuration and now i have to upload it to SCOM.

    Thanks,
    Mukul

  9. Tim McFadden August 3, 2012 at 8:42 am #

    There is no way to move an object from C# to vbscript. You can use c# to write a native module (this is difficult) or just write to a text file. Then have vbscript read the text file.

  10. Mukul August 6, 2012 at 5:14 am #

    Ok, thanks much.

    I already have the management pack which has around 50 VbScript associated with different purpose i.e. discovery, creating cache, etc.
    I want to remove all these VBscript code from the management pack. I want to develop an agent for my device which is not a windows or unix box.
    The agent will do all the tasks like Discovery, Fault Gathering, Event collection etc from device. VbScript is doing the task right now.
    I want to migrate them to C# and develop some agent to do this. Management pack will have class defination.

    Please help how to do this. Which managed module will help to do this or how to migrate this task to agent.

    A help is highly appreciated as the numbers of scripts queued for execution is 50 right now and they run at regular interval of 5 to 15 minutes. But in my enterprise network where there can be 100 to 1000 devices, it will become problem for SCOM management server.

    If i develop some agent or managed module, I will be able to reduce the workload by utilizing the threading capabilites of C#.

    Thanks,
    Mukul

Leave a Reply