Yesterday the new issue of BizTalk HotRod Magazine was published. Besides other nice content it contains an article on our PowerShell Provider for BizTalk.
Copying your host configuration
22 December 2009Moving your host configuration from one server to another can be daunting and time consuming task. This usually needs to be done when you hand over stuff from development to test, or from test to production. On those environments you mostly want to have the exact same host configuration as you have on your development box.
Another option is that a new development team member has just started on a fresh development box and you want him to use the same host configuration that you have. There are a lot of other scenarios where you want to copy the configuration of your hosts and host instances to another machine.
A lot of great BizTalk people have already showed how this can be done in an automated way. Some samples are:
- VBScript and WMI
- Custom tool 1
- Custom tool 2
In this post I want to show you how this can be done using PowerShell and the PowerShell provider for BizTalk. So this is actually the next post in my series on more advanced things you can do with the provider.
I use a slightly different approach compared to the existing tools. I use a PowerShell script that can be executed on the source server. This is the server that already has the host configuration set up, for example a development server. The output of running this script is actually another PowerShell script that you can run on the destination server. This output scripts contains all necessary statements to create the hosts, corresponding host instances and settings.
This is how it works:
- execute the script
- the script prompts for the name and path of the output file:
- after a short while the script is finished and a PowerShell script is created. You can run this script on the destination server or send it to an administrator who will run it on another server.
This is the created script:
#Determine BizTalk root and switch to host container.
$BizTalkRoot = (get-psdrive -PsProvider BizTalk).Root
Join-Path $BizTalkRoot 'Platform Settings\Hosts' | Set-Location
$RunningServer = $Env:ComputerName
#Create hosts
#Create host 'ReceiveHost' and set properties.
New-Item -Path 'ReceiveHost' -HostType 'InProcess' -NtGroupName 'BizTalk Application Users' -AuthTrusted:$False
Set-ItemProperty -Path 'ReceiveHost' -Name HostTracking -Value False
Set-ItemProperty -Path 'ReceiveHost' -Name Is32BitOnly -Value True
#Create host 'ProcessingHost' and set properties.
New-Item -Path 'ProcessingHost' -HostType 'InProcess' -NtGroupName 'BizTalk Application Users' -AuthTrusted:$False
Set-ItemProperty -Path 'ProcessingHost' -Name HostTracking -Value False
Set-ItemProperty -Path 'ProcessingHost' -Name Is32BitOnly -Value True
#Create host 'SendHost' and set properties.
New-Item -Path 'SendHost' -HostType 'InProcess' -NtGroupName 'BizTalk Application Users' -AuthTrusted:$False
Set-ItemProperty -Path 'SendHost' -Name HostTracking -Value False
Set-ItemProperty -Path 'SendHost' -Name Is32BitOnly -Value False
#Create host 'TrackingHost' and set properties.
New-Item -Path 'TrackingHost' -HostType 'InProcess' -NtGroupName 'BizTalk Application Users' -AuthTrusted:$False
Set-ItemProperty -Path 'TrackingHost' -Name HostTracking -Value True
Set-ItemProperty -Path 'TrackingHost' -Name Is32BitOnly -Value False
#Switch to host instances container.
Join-Path $BizTalkRoot 'Platform Settings\Host Instances' | Set-Location
#Create host instances
#Create host instance 'Microsoft BizTalk Server ReceiveHost BTS2K9-DEV' and set properties.
$Credential = $Host.UI.PromptForCredential('Host Instance user credentials', 'Please enter credentials for host instance ''ReceiveHost''', '', '')
New-Item -Path 'hostinstance' -HostName 'ReceiveHost' -RunningServer $RunningServer -Credentials $Credential
Set-ItemProperty -Path 'Microsoft BizTalk Server ReceiveHost BTS2K9-DEV' -Name IsDisabled -Value False
#Create host instance 'Microsoft BizTalk Server ProcessingHost BTS2K9-DEV' and set properties.
$Credential = $Host.UI.PromptForCredential('Host Instance user credentials', 'Please enter credentials for host instance ''ProcessingHost''', '', '')
New-Item -Path 'hostinstance' -HostName 'ProcessingHost' -RunningServer $RunningServer -Credentials $Credential
Set-ItemProperty -Path 'Microsoft BizTalk Server ProcessingHost BTS2K9-DEV' -Name IsDisabled -Value False
#Create host instance 'Microsoft BizTalk Server SendHost BTS2K9-DEV' and set properties.
$Credential = $Host.UI.PromptForCredential('Host Instance user credentials', 'Please enter credentials for host instance ''SendHost''', '', '')
New-Item -Path 'hostinstance' -HostName 'SendHost' -RunningServer $RunningServer -Credentials $Credential
Set-ItemProperty -Path 'Microsoft BizTalk Server SendHost BTS2K9-DEV' -Name IsDisabled -Value False
#Create host instance 'Microsoft BizTalk Server TrackingHost BTS2K9-DEV' and set properties.
$Credential = $Host.UI.PromptForCredential('Host Instance user credentials', 'Please enter credentials for host instance ''TrackingHost''', '', '')
New-Item -Path 'hostinstance' -HostName 'TrackingHost' -RunningServer $RunningServer -Credentials $Credential
Set-ItemProperty -Path 'Microsoft BizTalk Server TrackingHost BTS2K9-DEV' -Name IsDisabled -Value False
There are a couple of things to mention about the generated script:
- This is by no means a script applicable for all situations and environments. The purpose is just to show the output script as a result of running the source script. The source script will probably need some modification to make it apply to your environment. For example the script does not take into account multi server configurations, etc.
- The output script will prompt for credentials for each host instance it will create. There are also ways to script this from source to destination. See for example here. In most cases hosts in different environments will run under different accounts which is why I choose to show a prompt each time.
- Also in this script the windows group for the host is kept the same for the destination environment. This might not be the case in your particular situation.
After running this script on the destination server I have a exact copy of my host environment on the source server.
The source script looks like this:
$ScriptFile = Read-Host 'Enter full path of script file:'</pre>
'#Determine BizTalk root and switch to host container.' | Out-File $ScriptFile
'$BizTalkRoot = (get-psdrive -PsProvider BizTalk).Root' | Out-File $ScriptFile -Append
'Join-Path $BizTalkRoot ''Platform Settings\Hosts'' | Set-Location' | Out-File $ScriptFile -Append
'' | Out-File $ScriptFile -Append
'$RunningServer = $Env:ComputerName' | Out-File $ScriptFile -Append
$BizTalkRoot = (get-psdrive -PsProvider BizTalk).Root
Join-Path $BizTalkRoot 'Platform Settings\Hosts' | Set-Location
'#Create hosts' | Out-File $ScriptFile -Append
$HostArray = @()
Get-ChildItem -Path . | Foreach-Object {
if (!$_.IsDefault -and $_.HostType -ne 'Isolated') {
$HostArray += $_.Name
"#Create host '$($_.Name)' and set properties." | Out-File $ScriptFile -Append
"New-Item -Path '$($_.Name)' -HostType '$($_.HostType)' -NtGroupName '$($_.NtGroupName)' -AuthTrusted:`$$($_.AuthTrusted)" | Out-File $ScriptFile -Append
"Set-ItemProperty -Path '$($_.Name)' -Name HostTracking -Value $($_.HostTracking)" | Out-File $ScriptFile -Append
"Set-ItemProperty -Path '$($_.Name)' -Name Is32BitOnly -Value $($_.Is32BitOnly)" | Out-File $ScriptFile -Append
'' | Out-File $ScriptFile -Append
}
}
'#Switch to host instances container.' | Out-File $ScriptFile -Append
'Join-Path $BizTalkRoot ''Platform Settings\Host Instances'' | Set-Location' | Out-File $ScriptFile -Append
'' | Out-File $ScriptFile -Append
Join-Path $BizTalkRoot 'Platform Settings\Host Instances' | Set-Location
'#Create host instances' | Out-File $ScriptFile -Append
Get-ChildItem -Path . | Foreach-Object {
if ($HostArray -contains $_.HostName) {
"#Create host instance '$($_.Name)' and set properties." | Out-File $ScriptFile -Append
"`$Credential = `$Host.UI.PromptForCredential('Host Instance user credentials', 'Please enter credentials for host instance ''$($_.HostName)''', '', '')" | Out-File $ScriptFile -Append
"New-Item -Path 'hostinstance' -HostName '$($_.HostName)' -RunningServer `$RunningServer -Credentials `$Credential" | Out-File $ScriptFile -Append
"Set-ItemProperty -Path '$($_.Name)' -Name IsDisabled -Value $($_.IsDisabled)" | Out-File $ScriptFile -Append
'' | Out-File $ScriptFile -Append
}
}
In the script I skip the default and isolated host. As with the generated output script this is just a sample and might not apply to your specific situation. The source script should be modified to confirm to your requirements and environment.
You can download the source script from here.
BizTalk remote administration
24 November 2009Every application needs management. Ideally an application should provide two ways of management. First an administrator needs a (graphical) console to be able to do single or ad-hoc actions like changing configuration, responding to error conditions, etc. Second there should be a way for an administrator to create and run scripts. Scripts allow administrators to store a set of repetitive tasks in a container (called a script) in order to be able to easily do the same action over and over again. This is also called automation.
The best way to for any application to support management and automation is to implement such functionality on top of Windows PowerShell. Windows PowerShell contains a comprehensive API which enables the implementation of Cmdlets or a Cmdlet provider and the implementation of custom hosts.
Cmdlets or a cmdlet provider
PowerShell has uniform syntax for working with commands working and container hierarchies. This is a great advantage for administrators as they only need to learn a single way of working to manage it all. By implementing cmdlets we can “translate” this PowerShell way of working in calls to an applications native management API.
This is exactly what we have done in the provider for BizTalk. Internally we call BizTalk management APIs like ExplorerOM to perform things like starting applications, exporting MSIs, etc.
A custom host
Besides implementing custom cmdlets you can also implement a custom PowerShell host. The host can be any sort of application as long as it implements the PowerShell host interfaces. It can be a Win32 app, a web app or a text console for example.
This is exactly what Microsoft has done in the most recent versions of Exchange server (2007 & 2010). Management is done using PowerShell. The graphical management console is a PowerShell host. Exchange can be managed using this GUI or for example using scripts or commands running in the command shell console that comes out of the box with PowerShell.
The diagram below shows this architecture:
Things get even more interesting since we have PowerShell 2.0. It has a new feature called remoting which allows for remote administration and automation. Remoting uses WinRm (Microsofts implementation of the WS-Management standard). Goods news is that WinRM is firewall friendly. It only uses http(s) for communication. Now the diagram looks like this:
Is this secure? Yes it is, both PowerShell and WinRM have been designed with focus on security. Both come out of the box with security enabled. Of course you still need to pay attention especially when exposing things outside the enterprise.
Back to BizTalk
For BizTalk we have a couple of options to remotely administer a BizTalk server. We can choose between: Remote Desktop, client installation of Admin console, custom web services for management tasks, etc. Of course all have their pros and cons. With PowerShell remoting we have a new additional option.
Below I’ll show a couple of screens to see how this works.
I used two virtual machines in this demo. I installed the following software on those machines:
Virtual machine 1 (name: BTS2K9-dev):
- Windows Server 2008 R2 (I know not supported for hosting BizTalk)
- SQL Server 2008
- BizTalk Server 2009
- PowerShell 2.0
- PowerShell provider for BizTalk 1.0 (beta)
Virtual machine 2 (name: Client):
- Windows Server 2008 R2
- PowerShell 2.0
- PowerShell provider for BizTalk 1.0 (beta)
The obvious but important thing to note here is that the only thing that I have installed on virtual machine 2 that is related to BizTalk is the provider. In other words I did NOT NEED ANYTHING from the BizTalk installation CD on this machine.
The first thing I needed to was to enable remoting in PowerShell. This very simple and only requires the execution of a single command ‘Enable-PSRemoting’.
Second thing I needed to do was to add the client to the list of trusted computers on the BizTalk box. This mainly needs to be done because I just wanted to communicate over http instead of https for this demo.
On the BizTalk Box the management console is shown. Note that the default host instance is stopped:
Back to the PowerShell console on the Client to do the following:
- Create a new remote session on the BizTalk Box.
- Add the PowerShell provider snap in to the session.
- Switch to the default BizTalk drive.
- Switch the location to the host instances.
- Start the default host instance.
Finally a check on the other box to see if the host instance is running to verify this has worked (need to refresh the admin console first):
As you can see in the screen shots this is really easy to do. In my opinion it is a great new, location transparent, firewall friendly, client only way of managing BizTalk Server.
The only thing left to be done is to rebuild the BizTalk Administration Console on top of Windows PowerShell.
Cleaning your BizTalk development box with PowerShell
12 November 2009This is the first in a series of posts where I want to show some more advanced scripts and things you can do with the PowerShell provider for BizTalk.
I usually do a lot of tryouts and proof of concepts on my development box. In my urge to get things working I never spend too much time on descriptive application names. I also never clean up things after I’m done.
This will in inevitably lead to the following mess after a couple of weeks:
From time to time I feel the need to clean up this mess. I used to do this with the BizTalk Administration Console. I start on top of the list right click the application to first stop and then delete it. Then I go to the second, etc.
The problems start to arise when there are references between applications. If I delete an application that is referenced from another application I get the following warning:
I can still delete the application but the warning is annoying and takes time. The last thing I want is to lose too much time cleaning up
Things get even worse when there are assembly resources inside the application which are referred to by assembly resources in other applications. This time it is not a warning but a serious error preventing me from deleting the application.
This means I need to take this reference dependency tree into account and delete the “child” applications before their “parents”.
This all makes cleaning up my development box very annoying and time consuming which is probably why I keep postponing it in the first place.
You can nicely automate this procedure using a generic application removal script that uses the PowerShell provider for BizTalk. In the script I take advantage of the exception handling possibilities of PowerShell. I sort of do a “on error resume next”.
This is how the script works:
- - Build a list of all the applications and put them in a array variable.
- - Loop through the list and try to delete the application on top of the list.
- - When the deletion fails because of dependencies we catch, in PowerShell terms “trap”, the exception and shuffle the array a little bit so that the application that failed is moved to the bottom of the list.
- - We then continue with the application that is now on top of the list.
- - The loop will end when all the applications are removed.
This is the script:
Some details about the script:
In the fragment below we use the provider to get a list of all applications. We make sure exclude the system and default application because they cannot be deleted.
The second thing to show in detail is the error handling routine. The provider (or actually the BizTalk Management Classes library) throws an exception of type BtsException since the application is referenced and cannot be deleted. We catch this exception by using a trap statement. In the exception handler we do two things. First we make sure to set a variable in the main scope so that we know what to do with the array later. Either move the top item to the bottom or remove the top item. Second we use “continue;” to have the main routine continue with the next statement.
After running the script this is what the admin console shows:
Nice!!!!
The script can be downloaded from here
PowerShell provider for BizTalk getting started guide
10 November 2009For people interested in both PowerShell and BizTalk, I just finished a getting started guide to introduce the basics of the PowerShell provider for BizTalk (version 1.0 beta). The guide can be downloaded from here.
Posted by Randal van Splunteren 
RSS feed