My latest BizTalk administration powershell scripting mission has been to save suspended messages and terminate all suspended service instances. WMI exposes both message instances and service instances and corresponding methods.
The following script is in two steps. First all suspended messages are saved to file and then all suspended service instances are terminated. This script is used as part of a deployment process when the BizTalk cluster is not taking any messages. If the server is actively processing messages, a message could get suspended between the two steps and not get saved but the owning service instance could be terminated.
I have been thinking that one could use the serviceinstanceid to connect directly to the service instance from the message instance and terminate it then thereby avoiding the possibility of deleting a service instance without its corresponding message being saved. However, routing failure reports cannot be saved, (attempting to save them causes an exception) so the routing failure messages and service instances would still need to be cleaned up.
The simplest form of this script looks like this(note that blog software wraps the code):
Invoke-wmiMethod returns information that is not particularly meaningful in this context so it gets piped out to $null to minimize clutter.
The second filter specifies all resumable and non-resumable service instances and is used to select the service instances. Again the results are piped directly to Invoke-wmiMethod which will invoke the Terminate method. The terminate method has no parameters.
For further reference: here is the MSDN documentatation for the Service Instance Status codes http://msdn.microsoft.com/en-us/library/ee268242(v=bts.10).aspx and for Message Instance Service Class http://msdn.microsoft.com/en-US/library/ee253972(v=bts.10).aspx
In the dev and test environments we don't normally want to save the suspended messages so I extended the script to accept parameters for flexibility. I also had some exceptions during development so I added a function to handle each message with a try/catch. The exception information will be printed but does not stop the processing. This would allow for eventually finetuning the catches if I wanted to account for specific errors.
The longer version of the script looks like this(again beware of line wrapping):
I also call the SaveToFile method directly on the message object instead of using invoke-wmiMethod. In case you are new to powershell, the % operator used before the call to Save-Message is an alias for for-each.

The following script is in two steps. First all suspended messages are saved to file and then all suspended service instances are terminated. This script is used as part of a deployment process when the BizTalk cluster is not taking any messages. If the server is actively processing messages, a message could get suspended between the two steps and not get saved but the owning service instance could be terminated.
I have been thinking that one could use the serviceinstanceid to connect directly to the service instance from the message instance and terminate it then thereby avoiding the possibility of deleting a service instance without its corresponding message being saved. However, routing failure reports cannot be saved, (attempting to save them causes an exception) so the routing failure messages and service instances would still need to be cleaned up.
The simplest form of this script looks like this(note that blog software wraps the code):
$nameSpace ="root\MicrosoftBizTalkServer" $path = "c:\messagedump" $filter="(ServiceClass=1 OR ServiceClass=4) AND (ServiceInstanceStatus=4 OR ServiceInstanceStatus=32)" get-wmiobject MSBTS_MessageInstance -namespace $nameSpace -filter $filter | invoke-wmiMethod -name SaveToFile -arg $path > $null $filter="(ServiceStatus=4 OR ServiceStatus=32)" get-wmiobject MSBTS_ServiceInstance -namespace $nameSpace -filter $filter | invoke-wmiMethod -name Terminate > $nullThe first filter specifies orchestration or messaging service classes that are suspended(resumable) or suspended(not resumable). All message instance meeting this criteria get returned by the call to get-wmiobject and are piped directly into invoke-wmiMethod. The SaveToFile method exposed by WMI has a path parameter specifying where messages should be written.
Invoke-wmiMethod returns information that is not particularly meaningful in this context so it gets piped out to $null to minimize clutter.
The second filter specifies all resumable and non-resumable service instances and is used to select the service instances. Again the results are piped directly to Invoke-wmiMethod which will invoke the Terminate method. The terminate method has no parameters.
For further reference: here is the MSDN documentatation for the Service Instance Status codes http://msdn.microsoft.com/en-us/library/ee268242(v=bts.10).aspx and for Message Instance Service Class http://msdn.microsoft.com/en-US/library/ee253972(v=bts.10).aspx
In the dev and test environments we don't normally want to save the suspended messages so I extended the script to accept parameters for flexibility. I also had some exceptions during development so I added a function to handle each message with a try/catch. The exception information will be printed but does not stop the processing. This would allow for eventually finetuning the catches if I wanted to account for specific errors.
The longer version of the script looks like this(again beware of line wrapping):
# define parameters: $path is where messages will be saved # $save - a switch to trigger saving of suspended messages # $purge - a switch to trigger purging suspended service instances param([string] $path, [switch] $save, [switch] $purge) $nameSpace ="root\MicrosoftBizTalkServer" function Save-Message ($messageInstance) { try { $messageInstance.SaveToFile($path) > $null } catch { $messageInstance.MessageInstanceId $_.Exception.GetType().FullName $_.Exception } } If ($save) { if (! $path) { $path = ".\messages"; } if (! (Test-Path $path)) { mkdir $path } $filter="(ServiceClass=1 OR ServiceClass=4) AND (ServiceInstanceStatus=4 OR ServiceInstanceStatus=32)" get-wmiobject MSBTS_MessageInstance -namespace $nameSpace -filter $filter | %{Save-Message($_)} } if ($purge) { $filter="(ServiceStatus=4 OR ServiceStatus=32)" get-wmiobject MSBTS_ServiceInstance -namespace $nameSpace -filter $filter | invoke-wmiMethod -name Terminate > $null }The main changes here are that the path becomes a parameter to the script. If the path is not specified then a default path is used. If the path doesn't exist it will be created. I also added a save and a purge switch to allow complete flexibility around saving and terminating.
I also call the SaveToFile method directly on the message object instead of using invoke-wmiMethod. In case you are new to powershell, the % operator used before the call to Save-Message is an alias for for-each.
No comments:
Post a Comment