BizTalk Server Windows Management Instrumentation (WMI) classes whitepaper

BizTalk Server Windows Management Instrumentation (WMI) classes whitepaper

Windows Management Instrumentation (WMI) is the Microsoft implementation of Web-Based Enterprise Management (WBEM). Basically is a set of specifications from Microsoft for consolidating the management of devices and applications in a network from Windows computing systems. You can write WMI scripts or applications to automate administrative tasks on remote computers, but WMI also supplies management data to other parts of the operating system and products—for example, System Center Operations Manager (formerly Microsoft Operations Manager (MOM)), or Windows Remote Management (WinRM).

WMI is designed for programmers who use C/C++, the Microsoft Visual Basic application, or a scripting language that has an engine on Windows and handles Microsoft ActiveX objects. Nevertheless, many administrators and IT professionals access WMI through PowerShell. The Get-WMI cmdlet for PowerShell enables you to retrieve information for a local or remote WMI repository.

WMI comes pre-installed on Microsoft’s newest operating systems.

The purpose of WMI is to help administrators manage different Windows operational environments, including remote systems. One big advantage of WMI is that it reduces maintenance and the cost of managing enterprise network components.

BizTalk Server WMI classes

Windows Management Instrumentation (WMI) classes are used to programmatically access the administrative functions available in Microsoft BizTalk Server. Working together with PowerShell will be a winning match for IT Teams that need to manage BizTalk Server infrastructure and applications.

The Windows Management Instrumentation (WMI) classes in this table are used to manage the core objects associated with BizTalk Server, such as servers, queues, groups, and message handlers.

Class Description
MSBTS_AdapterSetting Registers new adapters with Microsoft® BizTalk® Server.
MSBTS_BTSObject This type of member supports the BizTalk Server infrastructure and is not intended to be used directly from your code.
MSBTS_DeploymentService Encapsulates BizTalk assemblies for deployment or undeployment and bindings export or import.
MSBTS_GroupSetting Represents a logical grouping of BizTalk Servers.
MSBTS_Host Represents a BizTalk Server Host.
MSBTS_HostInstance Represents a single instance of a BizTalk Host.
MSBTS_HostInstanceSetting Updates the IsDisabled property when a host is in the stopped state.
MSBTS_HostQueue Represents an application.
MSBTS_HostSetting Creates a BizTalk Server Host setting.
MSBTS_MessageInstance Represents a message instance.
MSBTS_MessageInstanceSuspendedEvent Represents a suspended event for a BizTalk Message Queuing (MSMQT) message instance.
MSBTS_MsgBoxSetting Represents a single MessageBox setting in the BizTalk Server group.
MSBTS_Orchestration Represents an instance of an orchestration that belongs to the installed module.
MSBTS_ReceiveHandler Represents an individual receive handler defined by BizTalk Server.
MSBTS_ReceiveLocation Represents an individual receive location defined by BizTalk Server.
MSBTS_ReceiveLocationOrchestration Represents all possible combinations of receive locations and orchestrations.
MSBTS_ReceivePort Represents an individual receive port defined by BizTalk Server.
MSBTS_SendHandler Represents an individual send handler defined by BizTalk Server.
MSBTS_SendHandler2 Represents an extended individual send handler defined by BizTalk Server.
MSBTS_SendPort Represents an individual send port defined by BizTalk Server.
MSBTS_SendPortGroup Represents a group of send ports defined by the BizTalk Server.
MSBTS_SendPortGroup2SendPort Represents an extended group of send ports defined by the BizTalk Server.
MSBTS_Server Represents computers within a group that have BizTalk Servers installed.
MSBTS_ServerHost Reflects mappings between BizTalk servers and BizTalk Hosts.
MSBTS_ServerSetting Represents specific computers within the BizTalk group that have BizTalk Servers installed. Instances of this class are intended to be created and deleted internally through BizTalk Server only. Do not create or delete instances of this class explicitly through WMI.
MSBTS_Service This type of member supports the BizTalk Server infrastructure and is not intended to be used directly from your code.
MSBTS_ServiceInstance Provides an instance of service with a start and stop functionality.
MSBTS_ServiceInstanceSuspendedEvent Represents a suspended event for a service instance.
MSBTS_Setting This type of member supports the BizTalk Server infrastructure and is not intended to be used directly from your code.
MSBTS_TrackedMessageInstance Represents a message instance.
MSBTS_TrackedMessageInstance2 Represents an updated message instance.

What’s in store for you?

This whitepaper will give you a complete overview with a detailed understanding of all BizTalk Server WMI classes and how to use them. For each BizTalk Server WMI classes we will provide a sample on how to use it.

Where can I download it?

You can download the whitepaper here:

BizTalk Server Administration Console cannot connect to WMI provider. Ensure that the WMI service is running. (Microsoft.BizTalk.SnapIn.Framework)

BizTalk Server Administration Console cannot connect to WMI provider. Ensure that the WMI service is running. (Microsoft.BizTalk.SnapIn.Framework)

BizTalk Server Administration Console cannot connect to WMI provider? The things I found from playing around with all kind of different environments from different clients and my personal ones (Hehe)… and I thought that I had already found all type of real or imaginary BizTalk errors, but once again I BizTalk Server prove me that I was wrong, this issue was new for me – who says that my BizTalk Consultant life is boring? (hehe).

Joking apart, I got the following error while trying to navigate in the BizTalk Server Administration Console in one of my personal environments:

TITLE: BizTalk Server Administration
——————————
Failed to load Group [BTS2016LAB01:BizTalkMgmtDb] data providers. (Microsoft.BizTalk.Administration.SnapIn)

For help, click: http://go.microsoft.com/fwlink/?LinkId=47400&ProdName=Microsoft+BizTalk+Server+2016&ProdVer=3.12.774.0&EvtSrc=Microsoft.BizTalk.Administration.SnapIn.Properties.Errors&EvtID=FailedLoadingGroupProviders&EvtChain=Microsoft.BizTalk.Administration.SnapIn.Properties.Errors+%2cFailedLoadingGroupProviders%3bMicrosoft.BizTalk.SnapIn.Framework.Properties.ErrorMessages+%2cConnectToWMIProviderFailed
——————————
ADDITIONAL INFORMATION:
Failed to load Group [BTS2016LAB01:BizTalkMgmtDb] data providers. (Microsoft.BizTalk.Administration.SnapIn)

For help, click: http://go.microsoft.com/fwlink/?LinkId=47400&ProdName=Microsoft+BizTalk+Server+2016&ProdVer=3.12.774.0&EvtSrc=Microsoft.BizTalk.Administration.SnapIn.Properties.Errors&EvtID=FailedLoadingGroupProviders&EvtChain=Microsoft.BizTalk.SnapIn.Framework.Properties.ErrorMessages+%2cConnectToWMIProviderFailed
——————————
Cannot connect to WMI provider. Ensure that the WMI service is running. (Microsoft.BizTalk.SnapIn.Framework)

For help, click: http://go.microsoft.com/fwlink/?LinkId=47400&ProdName=Microsoft+BizTalk+Server+2016&ProdVer=3.12.774.0&EvtSrc=Microsoft.BizTalk.SnapIn.Framework.Properties.ErrorMessages&EvtID=ConnectToWMIProviderFailed
——————————
The service cannot be started, either because it is disabled or because it has no enabled devices associated with it. (Exception from HRESULT: 0x80070422) (System.Management)
——————————
BUTTONS:
OK
—————————–

BizTalk Server Administration Console cannot connect to WMI provider

Cause

The reason for the BizTalk Server Administration Console cannot connect to WMI provider is because the BTS Administration Console relies on Windows Management Instrumentation (WMI) service, more specifically, the BizTalk WMI Provider (BTSWMIProvider.dll) to perform all type of different queries into BizTalk Environment (or BizTalk databases)

And for that reason, Windows Management Instrumentation (Winmgmt) service need to be enabled and running on the server in which you are running the BizTalk Server Administration Console.

In my case, the problem was that while I was investigating the unnecessary services that I could disable to optimize BizTalk Server performance, I disable this important service.

Solution

As I mentioned above, the solution to this problem is to Enable and Start the Winmgmt service, you can accomplish that by:

  • If the service is Disabled:
    • Press the “Windows key” to open the Start menu, type “Services” and click on “View local services” option from the Search window.
    • In the Services window, on the Services (Local) panel select the Windows Management Instrumentation service, right click and select “Properties” option.
      • On the Windows Management Instrumentation Properties (Local Computer) window:
      • On the General tab apply the following configuration.
      • Startup type: “Automatic”
      • And then click “Start” and “Apply”.

BizTalk Server Administration Console cannot connect to WMI provider: Winmgmt service

  • If the service is Enable, you can simply:
    • Open a command prompt as administrator by pressing the “Windows key” to open the Start menu and type “cmd” in the Start Search box, right-click in “Command Prompt” and select from the context menu the “Run as administrator” option
    • And type the following command: net stat winmgmt

BizTalk Server Administration Console cannot connect to WMI provider: Winmgmt service running

Once the Winmgmt service is running you will be able to use the BizTalk Server Administration Console without this error/problem happening.

Author: Sandro Pereira

Sandro Pereira lives in Portugal and works as a consultant at DevScope. In the past years, he has been working on implementing Integration scenarios both on-premises and cloud for various clients, each with different scenarios from a technical point of view, size, and criticality, using Microsoft Azure, Microsoft BizTalk Server and different technologies like AS2, EDI, RosettaNet, SAP, TIBCO etc. He is a regular blogger, international speaker, and technical reviewer of several BizTalk books all focused on Integration. He is also the author of the book “BizTalk Mapping Patterns & Best Practices”. He has been awarded MVP since 2011 for his contributions to the integration community. View all posts by Sandro Pereira

Health Monitoring NLB Nodes (IIS specific)

In our previous post we’ve setup a Network Load Balancing solution for BizTalk Server 2010; this solution ensures that ‘Web Traffic’ is balanced between two dedicated BizTalk Servers.

Well one of the caveats of a software NLB solution is the fact that it’s main role is to balance network traffic to 2 or more servers and it will not check if the ‘Traffic Destination Service (endpoint)’ is available, it will only check that the NLB nodes (servers) are available.

In our case this could mean that if either the BizTalk Application Pool or the BizTalk Website (endpoint) on one or both of the BizTalk NLB nodes are malfunctioning that traffic could still be rerouted to this node; resulting in those specific BizTalk Endpoints no longer being accessible/available. And of course this is something which is not desirable in our High Availability BizTalk Server Environment.

So in order to address above mentioned ‘issue’; I’ve decided to blog about one of the possible solutions which in theory comes down to the following:

  • Build a service which monitors if the participating Application Pools and Websites in our NLB node are up and running and in case they are malfunctioning disable that particular node in our NLB Cluster

This post will only covering building the core functionality and I will leave it up to the reader to implement this logic in their own windows service or other monitoring tool.

Let’s start!

Please note; the style of this article will be quite different compared to the previous posts and will consist more of a ‘Challenge –> Solution’ approach using C# Code samples.

Setting up our Visual Studio 2010 Solution

So Start up Visual Studio 2010 and create a new ‘Class Library’ Project and name it ‘WmiMonitor’ and name the solution to be created ‘ServerMonitor’.

Include the following reference to this project: System.Management.

Add a new ‘Class item’ and name it: WmiMonitor.cs

This class will hold all functionality with regards to our WMI Functionality

Add a new ‘Class item’ and name it: WmiMonitorResults.cs

This class will contain our properties used to hold our ‘WMI Query Results

Add a new ‘Class item’ and name it: EventLogManager.cs

This class will contain functionality used for writing any exceptions which might occur to the windows Eventlog

At this point your solution should look as follows:

Completing the project

At this point we’ve set up our solution and defined the artifacts needed for our project. In the next few subchapters we will actually add the code, which completes this project.

EventlogManager

Well in all applications exceptions might occur and as our end result will be a windows service which needs to run continuously (meaning; it should not crash when an error occurs) it would be beneficial if we would have functionality which would allow us to log the exception details to the windows event log, such that we can monitor our monitor 🙂 Below I’ve listed the functionality which does this.

So open up your EventLogmanager.cs file, and replace the default contents with the code below and see the inline comments for a more detailed explanation.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Monitoring
{
    /// <summary>
    /// Static Class which contains functionality to write 'events' to the default Windows Application Log
    /// </summary>
    public static class EventLogManager
    {
        private const string DefaultLog = "Application";

        /// <summary>
        /// Write Warning to EventLog
        /// </summary>
        /// <param name="eventSource">Name of source which will be displayed in the eventlog</param>
        /// <param name="warning">Warning Text which will be the description of the eventlog entry </param>   
        public static void WriteWarning(string eventSource, string warning)
        {
            //Call method which actually writes to the eventlog
            WriteToEventlog(eventSource, warning, EventLogEntryType.Warning);
            warning = null;
        }

        /// <summary>
        /// Write Info to EventLog
        /// </summary>
        /// <param name="eventSource">Name of source which will be displayed in the eventlog</param>
        /// <param name="info">Info Text which will be the description of the eventlog entry</param>   
        public static void WriteInfo(string eventSource, string info)
        {
            //Call method which actually writes to the eventlog
            WriteToEventlog(eventSource, info, EventLogEntryType.Information);
            info = null;
        }

        /// <summary>
        /// Write Error to EventLog
        /// </summary>
        /// <param name="eventSource">Name of source which will be displayed in the eventlog</param>
        /// <param name="error">Error Text which will be the description of the eventlog entry</param>   
        public static void WriteError(string eventSource, string error)
        {
            //Call method which actually writes to the eventlog
            WriteToEventlog(eventSource, error, EventLogEntryType.Error);
            error = null;
        }

        /// <summary>
        /// private Method which actually stores data in the eventlog
        /// </summary>
        /// <param name="source">Name of source which will be displayed in the eventlog</param>
        /// <param name="message">Message which will be the description of the eventlog entry</param>
        /// <param name="entryType">Indication of the eventlog entry type</param>
        private static void WriteToEventlog(string source, string message, EventLogEntryType entryType)
        {

                //Check if the EventSource exists, if not create it and use the default log for this
                if (!EventLog.SourceExists(source))
                {
                    EventLog.CreateEventSource(source, DefaultLog);
                }

                //Write entry to eventlog, if the message exceeds the max allowed size it will be truncated
                EventLog.WriteEntry(source, TruncateEventEntry(message), entryType);            
                message = null;            
        }

        /// <summary>
        /// Truncates an eventlog entry if it exceeds the maximum available characters
        /// </summary>
        /// <param name="input">String to be checked on length</param>
        /// <returns>input string which will be truncated when exceeding 20000 characters</returns>
        private static string TruncateEventEntry(string input)
        {
            //Check if string is null or empty
            if (!String.IsNullOrEmpty(input))
            {
                //Check length
                if (input.Length > 20000)
                {
                    //return truncated string and add ... at the end indicating a truncated string
                    return input.Substring(0, 19900) + "...";
                }
                else
                {
                    //return original string
                    return input;
                }
            }
            else
            {
                //return string which mentions that there was no infomration
                return "No Information";
            }
        }
    }
}

Note: that it does not include exception handling and if an exceptions are thrown they will have to be caught in the opertation invoking this class

WmiMonitorResult

This class will contain properties which can hold the status information with regards to the monitored objects; in our case (1) Application Pools (2) Websites.

So open up your WmiMontorResult.cs file, and replace the default contents with the code below and see the inline comments for a more detailed explanation.

using System;

namespace Monitoring
{
    /// <summary>
    /// Class used to hold information with regards to the status of the monitored items
    /// </summary>
    public class WmiMonitorResults
    {
        /// <summary>
        /// Server Name
        /// </summary>
        public string ServerName { get; set; }

        /// <summary>
        /// Name of the monitoring object
        /// </summary>
        public string ItemName { get; set; }

        /// <summary>
        /// Status Code which indicates the status of an item
        /// </summary>
        public int Status { get; set; }

        /// <summary>
        /// Friendly description of the Status code
        /// </summary>
        public string FriendlyStatusName { get; set; }

    }
}

WmiMonitor

This class will include all logic required for obtaining a NLB Server Node status with regards to the application pool and websites. Besides this it will include functionality to enable or disable a NLB node if required.

Below I’ve listed the functionality which does this. So open up your WmiMonitor.cs file, and replace the default contents with the code below and see the inline comments for a more detailed explanation.

using System;
using System.Collections.Generic;
using System.Management;
using System.Linq;
using System.Text;

namespace Monitoring
{
    /// <summary>
    /// Class which includes all functionality to determine a NLB nodes status with regards to Application Pools and Websites
    /// as well as stopping and starting a NLB node. All of this is done by means of WMI events and thus requires elevated rights
    /// to be executed succesfully
    /// </summary>
    public class WmiMonitor
    {
        #region properties
        //Private properties
        private string UserName { get; set; }
        private string Password { get; set; }
        private string Domain {get;set;}
        private string RemoteComputer { get; set; }

        /// <summary>
        /// Determines if WMI requests need to be performed using Impersonation
        /// </summary>
        private bool PerformImpersonation
        {
            get
            {
                //In case UserName/password is null or empty or the Remote Computer Name equals the current servername return true else false
                return ((String.IsNullOrEmpty(UserName) || String.IsNullOrEmpty(Password) || RemoteComputer.ToUpper() == Environment.MachineName.ToUpper()) ? true : false);
            }
        }

        /// <summary>
        /// Object used to hold settings which are required to set up a WMI connection
        /// </summary>
        private ConnectionOptions WmiConnectionOption
        {
            get
            {
                //initialize
                ConnectionOptions conOption = new ConnectionOptions();

                //Set settings according to the choice of impersonation or not
                if (this.PerformImpersonation)
                {
                    conOption.Impersonation = ImpersonationLevel.Impersonate;

                    /*IF WE DONT SET THE AUTHENTICATIONLEVEL TO PACKETPRIVACY WE'LL RECEIVE THE FOLLOWING ERROR
                    * The rootWebAdministration namespace is marked with the RequiresEncryption flag. 
                    * Access to this namespace might be denied if the script or application does not have the appropriate authentication level. 
                    * Change the authentication level to Pkt_Privacy and run the script or application again. 
                    */
                    conOption.Authentication = AuthenticationLevel.PacketPrivacy;
                }
                else
                {
                    conOption.Username = UserName;
                    conOption.Password = Password;

                    /*IF WE DONT SET THE AUTHENTICATIONLEVEL TO PACKETPRIVACY WE'LL RECEIVE THE FOLLOWING ERROR
                    * The rootWebAdministration namespace is marked with the RequiresEncryption flag. 
                    * Access to this namespace might be denied if the script or application does not have the appropriate authentication level. 
                    * Change the authentication level to Pkt_Privacy and run the script or application again. 
                    */
                    conOption.Authentication = AuthenticationLevel.PacketPrivacy;

                }

                return conOption;
            }
        }

        #endregion
        #region constructors
        /// <summary>
        /// Default constructor which is used when we need to use the callers credentials when executing WMI events
        /// </summary>
        public WmiMonitor()
        {

        }

        /// <summary>
        /// Constructor used in case we want to override the used credentials to execute WMI events
        /// </summary>
        /// <param name="userName">Username</param>
        /// <param name="passWord">Password</param>
        public WmiMonitor(string userName, string passWord, string domain)
        {
            UserName = userName;
            Password = passWord;
            Domain = domain;
        }

        #endregion
        #region Public Methods
        /// <summary>
        /// Function which returns the application pool state
        /// </summary>
        /// <param name="applicationPoolNames">Name of application pool to check</param>
        /// <param name="computer">Name of Computer</param>
        public WmiMonitorResults GetApplicationPoolStatus(string applicationPoolName, string computer)
        {
            //Set RemoteComputer
            RemoteComputer = computer;

            //prefill our mwi result class, which contains the state of the application pools
            WmiMonitorResults results = new WmiMonitorResults()
            {
                ServerName = computer,
                ItemName = applicationPoolName,
                FriendlyStatusName = "Not Found",
                Status = -1
            };

            try
            {
                    //WMI Connection and Scope
                    ManagementScope WmiScope = new ManagementScope(String.Format(@"{0}rootWebAdministration", computer),WmiConnectionOption);

                    //WMI Query
                    ObjectQuery WmiQuery = new ObjectQuery(String.Format("SELECT * FROM ApplicationPool WHERE Name ='{0}'", applicationPoolName));

                    //Actual 'wmi worker'
                    ManagementObjectSearcher searcher = new ManagementObjectSearcher(WmiScope,WmiQuery);

                //Execute query and process the results which are stored as WmiMonitorResults object
                foreach (ManagementObject queryObj in searcher.Get())
                {
                    //Get State
                    int StateValue = -1;
                    if (int.TryParse(queryObj.InvokeMethod("GetState", null).ToString(), out StateValue))
                    {
                        //Store state status in return class
                        results.Status = StateValue;

                        //Determine friendly name of state and store this in the return class
                        results.FriendlyStatusName = GetFriendlyApplicationPoolState(StateValue);

                    }

                }
            }
            catch (ManagementException e)
            {
                results.Status = -2;
                results.FriendlyStatusName = e.Message;

                //log exception
                EventLogManager.WriteError("WmiMonitor", String.Format("[GetApplicationPoolStatus] {0}", e.Message));

            }
            catch (Exception gex)
            {
                results.Status = -3;
                results.FriendlyStatusName = gex.Message;

                //log exception
                EventLogManager.WriteError("WmiMonitor", String.Format("[GetApplicationPoolStatus] {0}", gex.Message));
            }
            return results;
        }

        /// <summary>
        /// Method which returns the state of the websites
        /// </summary>
        /// <param name="WebSiteName">Name of website to check</param>
        /// <param name="computer">Name of Computer</param>
        /// <returns></returns>
        public WmiMonitorResults GetWebSiteStatus(string WebSiteName, string computer)
        {
            //Set RemoteComputer
            RemoteComputer = computer;

            //prefill our mwi result class, which contains the state of the application pools
            WmiMonitorResults results = new WmiMonitorResults()
            {
                ServerName = computer,
                ItemName = WebSiteName,
                FriendlyStatusName = "Not Found",
                Status = -1
            };

            try
            {
                //WMI Connection and Scope
                ManagementScope WmiScope = new ManagementScope(String.Format(@"{0}rootWebAdministration", computer), WmiConnectionOption);

                //WMI Query
                ObjectQuery WmiQuery = new ObjectQuery(String.Format("SELECT * FROM Site WHERE Name ='{0}'", WebSiteName));

                //Actual 'wmi worker'
                ManagementObjectSearcher searcher = new ManagementObjectSearcher(WmiScope, WmiQuery);

                //Execute query and process the results which are stored as WmiMonitorResults object
                foreach (ManagementObject queryObj in searcher.Get())
                {
                    int StateValue = -1;
                    //Get State
                    if (int.TryParse(queryObj.InvokeMethod("GetState", null).ToString(), out StateValue))
                    {
                        //Store state status in return class
                        results.Status = StateValue;

                        //Determine friendly name of state and store this in the return class
                        results.FriendlyStatusName = GetFriendlyApplicationPoolState(StateValue);
                    }

                }
            }
            catch (ManagementException e)
            {
                results.Status = -2;
                results.FriendlyStatusName = e.Message;

                //log exception
                EventLogManager.WriteError("WmiMonitor", String.Format("[GetWebSiteStatus] {0}", e.Message));

            }
            catch (Exception gex)
            {
                results.Status = -3;
                results.FriendlyStatusName = gex.Message;

                //log exception
                EventLogManager.WriteError("WmiMonitor", String.Format("[GetWebSiteStatus] {0}", gex.Message));
            }
            return results;
        }

        /// <summary>
        /// Method which returns the nodes which are part of the NLB Server
        /// </summary>
        /// <param name="nlbServer">Server Name containing the NLB Feature</param>
        /// <returns>String list of nodes which are part of the NLB Server</returns>
        public List<string> GetNLBComputers(string nlbServer)
        {
            //Set RemoteComputer
            RemoteComputer = nlbServer;

            //prefill our mwi result class, which contains the state of the application pools
            List<string> returnValue = new List<string>();
            try
            {
                //WMI Connection and Scope
                ManagementScope WmiScope = new ManagementScope(String.Format(@"{0}rootMicrosoftNLB", nlbServer), WmiConnectionOption);

                //WMI Query
                ObjectQuery WmiQuery = new ObjectQuery("SELECT * FROM MicrosoftNLB_Node");

                //Actual 'wmi worker'
                ManagementObjectSearcher searcher = new ManagementObjectSearcher(WmiScope, WmiQuery);

                //Execute Query and Get NLB Nodes                
                foreach (ManagementObject queryObj in searcher.Get())
                {
                    returnValue.Add(queryObj["ComputerName"].ToString());
                }
            }
            catch (ManagementException e)
            {
                //log exception
                EventLogManager.WriteError("WmiMonitor", String.Format("[GetNLBComputers] {0}", e.Message));
                return null;
            }
            catch (Exception gex)
            {
                //log exception
                EventLogManager.WriteError("WmiMonitor", String.Format("[GetNLBComputers] {0}", gex.Message));
                return null;
            }

            return returnValue;
        }

        /// <summary>
        /// Method which actually stops or starts a NLB Node; if stateStopped paramaters is true, the node will be started and vica versa
        /// </summary>
        /// <param name="serverNode">Node to perform action on</param>
        /// <param name="stateStopped">True if current state is stopped</param>
        /// <returns>True if node was succesfully stopped/started</returns>
        public bool SetNlbNodeState (string serverNode, bool stateStopped)
        {
            //Set RemoteComputer
            RemoteComputer = serverNode;
            bool ReturnValue = false;
            try
            {
                //WMI Connection and Scope
                ManagementScope WmiScope = new ManagementScope(String.Format(@"{0}rootMicrosoftNLB", serverNode), WmiConnectionOption);

                //WMI Query
                ObjectQuery WmiQuery = new ObjectQuery(String.Format("SELECT * FROM MicrosoftNLB_Node WHERE ComputerName ='{0}'", serverNode));

                //Actual 'wmi worker'
                ManagementObjectSearcher searcher = new ManagementObjectSearcher(WmiScope, WmiQuery);

                    foreach (ManagementObject queryObj in searcher.Get())
                    {
                        int StateValue = -1;
                        int NodeStatusCode = 0;
                        string FriendeNodeStatus = string.Empty;

                        //Get NLB Node State
                        if(int.TryParse(queryObj["StatusCode"].ToString(),out NodeStatusCode))
                        {
                            //Determine friendly name of NLB Node State 
                            FriendeNodeStatus = GetFriendlyNlbNodeStatusCode(NodeStatusCode);
                        }

                        if (stateStopped)
                        {
                            //Only stop if started
                            if(FriendeNodeStatus.ToUpper() != "STOPPED")
                            {
                            if (int.TryParse(queryObj.InvokeMethod("Stop", null).ToString(), out StateValue))
                            {
                                ReturnValue = true;                               

                            }
                            }
                        }
                        else
                        {
                            //Only start if STOPPED
                            if (FriendeNodeStatus.ToUpper() == "STOPPED")
                            {
                                if (int.TryParse(queryObj.InvokeMethod("Start", null).ToString(), out StateValue))
                                {
                                    ReturnValue = true;                                   

                                }
                            }
                        }

                    }

            }

            catch (ManagementException e)
            {
                //log exception
                EventLogManager.WriteError("WmiMonitor", String.Format("[SetNlbNodeState] {0}", e.Message));

            }
            catch (Exception gex)
            {
                //log exception
                EventLogManager.WriteError("WmiMonitor", String.Format("[SetNlbNodeState] {0}", gex.Message));

            }

            return ReturnValue;
        }
        #endregion 
        #region Private Methods
        /// <summary>
        /// Method which performs a friendly lookup of possible NLB States
        /// </summary>
        /// <param name="statusCode">Original status code</param>
        /// <returns>Friendly status code description</returns>
        private string GetFriendlyNlbNodeStatusCode(int statusCode)
        {
            switch (statusCode)
            {
                case 0:
                    return "Node is remote. The StatusCode value cannot be retrieved.";
                case 1005:
                    return "STOPPED";
                case 1006:
                    return "CONVERGING";
                case 1007:
                    return "CONVERGED";
                case 1008:
                    return "CONVERGED DEFAULT HOST";
                case 1009:
                    return "DRAINING";
                case 1013:
                    return "SUSPENDED";
                default:
                    return "UNKNOWN";

            }

       }

        /// <summary>
        /// Method which performs a friendly lookup of possible ApplicationPool States
        /// </summary>
        /// <param name="stateCode">Original state code</param>
        /// <returns>Friendly state code description</returns>
        private string GetFriendlyApplicationPoolState(int stateCode)
        {
            switch(stateCode)
            {
                case 0:
                    return "Starting";
                case 1:
                       return "Started";
                case 2:
                       return "Stopping";
                case 3:
                       return "Stopped";
                case 4:
                       return "Unknown";
                default:
                    return "Undefined value";
            }

        }

        #endregion
    }
}

Closing Note

So this sums up tackling our nagging problem on how to ensure that a NLB node is disabled in case a website or application pool is malfunctioning.

In case you are interested in the source code including a sample windows service application please feel free to send me an email ([email protected]) and I’ll send it to you

Well I hope you enjoyed this read until the next time.

Kind regards

René

Host Instance Creation and Adapter Configuration Tool for BizTalk

This tool will help you design and build your BizTalk solutions by making it easier to consistently separate out your processes into multiple hosts even on your developer boxes.  It will also make sure all your developers and environments are using Hosts with the same names.  This can be a total nightmare to manage and maintain.

This tool is fed by a simple config file to set up the Hosts, install Host Instances, and assign Adapters to these new Hosts.  This tool has the ability to prompt for a user password and reset all the Adapters back to the default Host (this was used extensively when I was testing the tool).

This tool should work with BizTalk Server 2004, BizTalk Server 2006, and BizTalk Server 2006 R2.  I have not tested it running against any remote servers. 

For more information, see the full blog post at: http://www.biztalkgurus.com/biztalk_server/biztalk_blogs/b/biztalk/archive/2008/04/30/biztalk-host-creation-and-adapter-assignment-tool-available-for-download.aspx

WMI Suspended Instances for BizTalk Server 2004

The help guide gives many excellent examples of using WMI to perform a large variety of useful tasks in BizTalk 2004. 



One of the little known features is the ability to have suspended messages saved to a file at the time of suspense.  I would assume this is govern by the same rules of viewing tracked messages in HAT, that is the stream must be seekable for the message to be tracked and in this case saved (see Christof’s Blog Post).



What makes this feature so nice is it saves both the message and the context to a file.  This can be great at tracking down routing failures, convoy problems, and general correlation issues. 



I have put together a simple tool that can be run anytime you want to view the suspended messages and context.  Just deploy the sample to your C:\ drive.  The suspended messages are written to C:\SampleWMI\OutputMessages.



Download: WMI Suspended Instance Sample


Suspended Message Viewer using WMI Tool

This tool can be used to monitor BizTalk Server 2004/2006 for suspended messages. Once a suspended message is detected, the message and the message context is written to disk for easy viewing.

Get more information from the original blog post on this topic:http://www.biztalkgurus.com/biztalk_server/biztalk_blogs/b/biztalk/archive/2005/03/09/wmi-suspended-instances-for-biztalk-server-2004.aspx