Santosh Benjamin's Weblog

Adventures with AppFabric, BizTalk & Clouds

Archive for the ‘Powershell’ Category

Creating Hosts with Powershell

with 9 comments


[UPDATE]: The issue I had has now been solved. Please refer to the text below for the original issues as well as the solution

Context: Basically I was trying to write the powershell equivalent of the MSDN Article : Creating a Host using WMI

For the C# version of the sample here is the powershell equivalent
$putOptions = new-Object System.Management.PutOptions
$putOptions.Type = [System.Management.PutType]::CreateOnly;

[System.Management.ManagementClass]$objHostSettingClass = New-Object
System.Management.ManagementClass(“root\MicrosoftBizTalkServer”,”MSBTS_HostSetting”,$null)
[System.Management.ManagementObject]$objHostSetting = New-Object
System.Management.ManagementObject
$objHostSetting = $objHostSettingClass.CreateInstance()
$objHostSetting[“Name”] = $hostName
$objHostSetting[“HostType”] = $hostType
$objHostSetting[“NTGroupName”] = $NTGroupName
$objHostSetting[“AuthTrusted”] =$authTrusted
[System.Management.ManagementObject]($objHostSetting).Put(([System.Management.PutOptions]$putOptions));

This gives me the error
Exception calling “Put” with “1” argument(s): “You cannot call a method on a
null-valued expression.”

If i try the VBscript version (PS equivalent) as shown below
 $objLocator = New-Object -ComObject “WbemScripting.SWbemLocator”
$objService = $objLocator.ConnectServer(“.”,”root/MicrosoftBizTalkServer”)
$objHostSetting = $objService.Get(“MSBTS_HostSetting”)
$objHS = $objHostSetting.SpawnInstance_
$objHS.HostName = $hostName
$objHS.HostType = $hostType
$objHS.NTGroupName = $NTGroupName
$objHS.AuthTrusted = $authTrusted
$objHS.Put(2)

Then i get an error saying : the property is read only (name, hosttype etc)

changing the assignment to the following

$objHS.Properties_.Item(“Name”).value = $hostName

does not work  either, saying

You cannot call a method on a null-valued expression.

SOLUTION

In the original post, I had said that I was going to try to solve the problem through Reflection and indeed that was the only way i could get it to work.

 

In the code (for the C#/PS equivalent) shown above , it appears that the line [$objHostSetting.Put($options)] is the offender. Although $objHostSetting gets initialised correctly and all properties get set, the Put method cannot be called on it. At the time of invocation it seems that PS thinks its null.

 

It was a very painful process (for a PS newbie) and the reflection equivalent isn’t an exact translation of the C# either. The Invoke() method requires an object[] in C# but in PS you just pass the actual object and it will work

 

PS Script 

function bts-host-create([string]$hostName, [int]$hostType, [string]$NTGroupName, [bool]$authTrusted)

{

       $putOptions = new-Object System.Management.PutOptions

       $putOptions.Type = [System.Management.PutType]::CreateOnly;

      

       [System.Management.ManagementClass]$objHostSettingClass = New-Object System.Management.ManagementClass(“root\MicrosoftBizTalkServer”,”MSBTS_HostSetting”,$null)

       [System.Management.ManagementObject]$objHostSetting = New-Object System.Management.ManagementObject

       $objHostSetting = $objHostSettingClass.CreateInstance()

      

      

       $objHostSetting[“Name”] = $hostName

       $objHostSetting[“HostType”] = $hostType

       $objHostSetting[“NTGroupName”] = $NTGroupName

       $objHostSetting[“AuthTrusted”] =$authTrusted

      

       [Type[]] $targetTypes = New-Object System.Type[] 1

       $targetTypes[0] = $putOptions.GetType()

 

       $sysMgmtAssemblyName = “System.Management”

       $sysMgmtAssembly = [System.Reflection.Assembly]::LoadWithPartialName($sysMgmtAssemblyName)

       $objHostSettingType = $sysMgmtAssembly.GetType(“System.Management.ManagementObject”)

      

       [Reflection.MethodInfo] $methodInfo = $objHostSettingType.GetMethod(“Put”,$targetTypes)

       $methodInfo.Invoke($objHostSetting,$putOptions)

      

       Write-Host “Successfully created host named:  $hostName”

      

 

}

Here’s the C# code

public static void CreateHostThroughReflection(string HostName, int HostType, string NTGroupName, bool AuthTrusted)

        {

            try

            {

                PutOptions options = new PutOptions();

                options.Type = PutType.CreateOnly;

 

                //create a ManagementClass object and spawn a ManagementObject instance

                ManagementClass objHostSettingClass = new ManagementClass(“root\\MicrosoftBizTalkServer”, “MSBTS_HostSetting”, null);

                ManagementObject objHostSetting = objHostSettingClass.CreateInstance();

 

                //set the properties for the Managementobject

                objHostSetting[“Name”] = HostName;

                objHostSetting[“HostType”] = HostType;

                objHostSetting[“NTGroupName”] = NTGroupName;

                objHostSetting[“AuthTrusted”] = AuthTrusted;

 

                Type[] targetTypes = new Type[1];

                targetTypes[0]= typeof(PutOptions);

 

                object[] parameters = new object[1];

                parameters[0] = options;

               

                Type objType = objHostSetting.GetType();

                MethodInfo mi = objType.GetMethod(“Put”,targetTypes);

                mi.Invoke(objHostSetting, parameters);

 

                //create the Managementobject

                //objHostSetting.Put(options);

                System.Console.WriteLine(“Host – ” + HostName + ” – has been created successfully”);

            }

            catch (ManagementException mex)

            {

                Console.WriteLine(“Management Exception ” + mex.Message);

            }

            catch (Exception excep)

            {

                System.Console.WriteLine(“CreateHost – ” + HostName + ” – failed: ” + excep.Message);

            }

        }

Notice that the “Invoke” is different in the PS and the C#. Also notice how convoluted the PS is when trying to do a simple object.GetType() , but i guess PS wasnt meant for this sort of thing anyway, so we cant complain.

Hope this helps someone. Do let me know if it does. Use the code for whatever you want but i dont provide support  🙂

Written by santoshbenjamin

October 8, 2008 at 6:14 PM

Powershell : Calling BTSTask.exe

with one comment


I set out to write a bunch of PS functions to manage Biztalk to keep in a little script library that i could then call from external scripts etc (I found and came up with some other good stuff that i’ll share shortly but this is something i had to write about immediately).

One of the tasks was to export bindings for an application. This is something that i found incredibly hard to do from within a function. It works alright when just called interactively, just like any normal command prompt, but invoking the process within a function had me lose a lot of hair (and theres very little spare anyway 😦 ).

Anyhow, i’ll spare you the gory details. After mucking around with System.Process, trying to capture the output window , invoking cmd etc, the solution was drop dead simple.

A snippet of the function is as follows

function bts-application-exportbindings ([string]$bindingFile, [string]$appName)

{

$taskParams = ” ExportBindings /Destination:$bindingfile /ApplicationName:$appName ”

$p = [diagnostics.process]::start(“BTSTask.exe”, $taskParams)

}

Thats all. But my goodness, it had me really frustrated for a while. C’est la vie!! Hope it helps some of you…

Written by santoshbenjamin

September 30, 2008 at 7:20 PM

Posted in BizTalk, Powershell

Tagged with ,

Powershell and Arrays as named parameters

with 5 comments


While theres a ton of stuff on the usage of Powershell as an interactive scripting system there is not as much from a general programming perspective of a developer , at least not much that i could find today.

For example, while there is a flood of posts showing how you can manipulate the “args” system variable and how you can pass in an array on the command line by simply putting in several arguments with spaces, i was looking for a way to pass parameters into a function where 1 of the several parameters happened to be an array and then i needed to parse that array. After much trial and error, i found a solution. Here it is for any powershell newbies to benefit.

My main script file has a function like this  (very trivialised example)

function showfriends([string] $mainPerson, [string[]] $friends)
{
 Write-Host “Main person is “,$mainPerso
 Write-Host ‘friends count is : ‘ ,$friends.Count
 foreach($friend in $friends)
 {
  Write-Host $mainPerson “has a friend named:” ,$friend
  }

}

Now to call it i use the following line

showfriends -mainPerson:Smith  -friends:@(‘Jon’, ‘Joshua’)

which will then print

Smith has a friend namd Jon

Smith has a friend named Joshua

The reason i got stuck intiially was that i was trying to use foreach-object and PS insisted on prompting me to enter the objects. Another thing that got me stuck was that on a site with tutorials , the illustration of some syntax had showed the usage of [array]  which did not work for me.

Written by santoshbenjamin

September 30, 2008 at 7:07 PM

Posted in General, Powershell

Tagged with