PowerShell Scripting Communicator Automation API Using Native Type Library

Summary:   Learn how to automate Microsoft Lync 2010 and Microsoft Office Communicator 2007 R2 using native Microsoft Office Communicator 2007 Automation API type library in Microsoft Windows PowerShell.

Microsoft Office Communicator 2007 Automation API, supported by Microsoft Lync 2010 for backward compatibility, supports limited scripting. This support is useful in traditional web applications where a scripting language, such VBScript or JavaScript, is used throughout a web page or Microsoft Windows Script Host to enable unified communications functionality. Active scripting is mapped against native COM library, which is embedded in an active Lync instance. Microsoft Windows PowerShell can be employed to automate Lync this way. In this article, I focus on how to perform basic tasks that can be used to automate Lync 2010, Microsoft Office Communicator 2007, or Microsoft Communicator 2007 R2 using PowerShell scripts against the native Communicator 2007 Automation API type library. Code examples are used to illustrate how to invoke Communicator 2007 Automation API features in PowerShell, provided that the features are scriptable.

PowerShell also supports scripting by manipulating .NET types and members directly. By using PowerShell, you can script any .NET-based unified communications API. In addition to scripting against the native type library, you can use PowerShell to script the Communicator 2007 Automation API primary interoperable assembly and Microsoft Lync 2010 API and Microsoft Unified Communications Managed API 3.0. With PowerShell, a unified communications application developer can explore these APIs interactively and experiment with application ideas. In PowerShell Scripting Communicator Automation API Using Primary Interop Assembly, I demonstrate how to call the Communicator 2007 Automation API features against the interoperable assembly from the COM-based type library.

Lync 2010 supports backward compatibility to enable programming access through Office Communicator 2007 Automation API. The corresponding COM-based type library is included with Microsoft Lync 2010 installation. You can verify the installation of this library using OLE-COM Object Viewer (OleView.exe). This viewer is installed by default, as part of the Microsoft Windows SDK for Windows 7, in the %ProgramFiles%\Microsoft SDKs\Windows\v7.0A\Bin directory. OLE-COM Object Viewer can also be accessed through the Windows Start menu:

To start OLE-COM Object Viewer

  1. Click Start and then select All Programs.

  2. On the All Programs menu, click Microsoft Visual Studio 2010, click Microsoft Windows SDK Tools, and then click OLE-COM Object Viewer.

Note Note

You may need to run the following command to register the Interface Viewer (IViewers.DLL) if the OLE-COM Object Viewer does not display an interface:

cd C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin

regsvr32 IViewers.DLL

To automate Lync 2010 using COM-based Communicator 2007 Automation API in PowerShell, you must have Lync 2010 and PowerShell installed. To run Lync 2010, you must also be a member of a network serviced by Microsoft Lync Server 2010. On Microsoft Windows 7, PowerShell is preinstalled.

To run a PowerShell script, you must first launch a PowerShell session. You can do this in two ways: use a regular Windows command prompt or a Windows PowerShell Integrated Scripting Environment (ISE).

To use a command prompt to start PowerShell session

  • At the command prompt, type PowerShell. The PowerShell window appears.

To use Windows PowerShell ISE

  1. Click Start and then select All Programs.

  2. On the All Programs menu, click Accessories, click Windows PowerShell, and then click Windows PowerShell ISE.

I recommend that you use PowerShell ISE because it has a decent debugging capability, for a scripting engine, anyway.

Before calling the COM-based Microsoft Office Communicator 2007 Automation API Type Library for any scriptable Lync 2010 Automation feature, you must first create a Lync proxy that takes your commands on behalf of a locally running Lync instance. In Office Communicator 2007 Automation API, this proxy is an instance of the Messenger co-class.

There are two ways that you can obtain this object. One involves calling directly on the COM-based type library and the other uses the primary interoperable assembly of the type library. In this article I focus on scripting the native COM object directly. I will show how to script against the primary interoperable assembly in a future article.

To create the native Messenger object, use the PowerShell’s New-Object cmdlet:

$communicator = New-Object –ComObject "Communicator.UIAutomation”

The string value Communicator.UIAutomation after the –ComObject parameter in the New-Object cmdlet is the ProgID of the Messenger coclass that makes available by default the IMessenger, IMessenger2, IMessenger3, and IMessengerAdvanced interfaces. These and other interfaces are documented in Microsoft Office Communicator 2007 Automation API documentation that can be downloaded from MSDN or viewed online. The –ComObject parameter is required for instantiating any COM-based type instance.

You can examine the exposed members of these interfaces by using the following PowerShell command:

$communicator | Get-Member

The first few entries of the output from the previous command:

System.__ComObject

   TypeName: System.__ComObject#{da0635e8-09af-480c-88b2-aa9fa1d9db27}

Name                 MemberType            Definition                                         
----                 ----------            ----------                                         
AddContact           Method                void AddContact (int, string)                      
AutoSignin           Method                void AutoSignin ()                                 
CreateGroup          Method                IDispatch CreateGroup (string, Variant)            
FindContact          Method                void FindContact (int, string, string, Variant, ...

The UUID value appearing in the previous output, namely, the GUID in the braces after __ComObject#, identifies the IMessengerAdvanced interface. It inherits from IMessenger3, which then inherits from IMessenger2, which in turn inherits from IMessenger. The complete output contains all the public members of these interfaces.

The Get-Member cmdlet is useful for examining the members of an object and to determine their signatures.

NoteNote

For security reasons, many of the methods and properties on the IMessenger interfaces are not scriptable or not scriptable in a web browser. These restrictions apply to PowerShell scripting also. For more information about scriptable methods or properties, see the Microsoft Office Communicator 2007 Automation API documentation.

Once the Messenger object ($communicator) is instantiated correctly, you can call scriptable members in PowerShell to perform appropriate Lync Automation tasks.

Calling a Communicator 2007 Automation API object property in PowerShell resembles calling it in C#, except for the fact that the PowerShell type binder is more dynamic and the result may be assigned to a variable of unspecified type. This means that you can use the Microsoft Office Communicator 2007 Automation API documentation to determine the syntax to invoke a property in PowerShell.

For example, to obtain and display the contact list, you can use the following PowerShell code:

foreach($c in $communicator.MyContacts)
{
    $c.FriendlyName | write-host
}

Here, $communicator.MyContacts is a read-only property on the IMessenger interface that returns a collection of IMessengerContact instances. The collection is encapsulated by the IMessengerContacts interface. The foreach loop enumerates the contacts to display the contact list in the running host of PowerShell. The statement in the loop ($c.FriendlyName | write-host) reads the FriendlyName property from an enumerated IMessengerContact instance and then pipes the result to the Write-Host cmdlet. This PowerShell cmdlet writes the output to the running PowerShell host.

NoteNote

PowerShell cmdlets are case-insensitive.

Calling a Communicator 2007 Automation API instance method in PowerShell is also similar to calling it in C#, with an exception that the PowerShell type binder is more dynamic and any return value may be assigned to a variable of an unspecified type.

For example, to get a specific contact from the contact list, you can call the GetContact method on the IMessenger interface exposed on the $communicator object:

$c = $communicator.GetContact("adamb@contoso.com", $communicator.MyServiceId)
$status = $c.Status

When successfully executed, the previous GetContact method returns an IMessengerContact instance that contains presence information of the specified contact. The Status property value is of the MISTATUS enumeration type and will be discussed in more details later in this article.

It is interesting to compare the previous PowerShell statement with the corresponding C# statement. The following is a C# equivalent of the PowerShell statement:

MessengerClass communicator = …
IMessengerContact c = communicator.GetContact("adamb@contoso.com", communicator.MyServiceId)
MISTATUS status = c.Status

The similarity of the calling conventions of instance methods and properties between C# and PowerShell script implies that C# code examples in the Communicator 2007 Automation API documentation can be straightforwardly applied to PowerShell scripting.

The Status property on the IMessengerContact instance returns the availability number of the contact. In Communicator 2007 Automation API Type Library, this number is of the MISTATUS enumeration type, which can be used to infer the description of the contact’s presence status. However, such enumeration types are not supported in PowerShell scripting on COM-type library directory. This limitation also applies to JavaScript or VBScript, in which the enumeration member values are used instead of the member names. You can do the same in PowerShell when you are dealing with a value of an enumeration type, such as the Status property on the IMessengerContact interface.

The following PowerShell code shows how to determine a more informative description of the Status returned in the previous tasks in PowerShell:

$MISTATUS_UNKNOWN = 0x0
$MISTATUS_ONLINE=0x2
$MISTATUS_INVISIBLE = 0x6
$MISTATUS_BUSY = 0xA
$MISTATUS_AWAY = 0x22
if (($status -band $MISTATUS_BUSY) -eq $MISTATUS_BUSY)
{
    "status = Busy " | write-host
}
elseif (($status -band $MISTATUS_ONLINE) -eq $MISTATUS_ONLINE)
{
    "status = Online " | write-host
}

Here, the $MISTATUS_* variables map to the corresponding MISTATUS enumeration fields that can be extracted from the Office Communicator 2007 Automation API documentation. The PowerShell bitwise-AND operator (-band) and equality comparer (-eq) are used to determine “Busy” or “Online” as the descriptive status of the contact. You can apply the same trick, substituting $MISTATUS_ONLINE in the if statement with another field, to determine other Lync-supported status descriptions from a given availability number ($status).

PowerShell supports exception handling using the Trap… or Trap… Throw… primitive. This can be useful when you explore Communicator 2007 Automation API using PowerShell scripts because many objects members of the API are not scriptable. Invoking such members will result in COM exception of E_NOTIMPLEMENTED. In cases where the documentation becomes inaccessible, you can use the Trap mechanism to determine whether you have accidentally called from PowerShell a member regarded as not scriptable. The following PowerShell example shows how Trap is used to determine whether the FindContact method on the IMessenger interface can be scripted.

#Launching a wizard to find a contact will fail because the method is not scriptable.
$communicator.FindContact(0, "Adam", "Barr")

Trap [EXCEPTION]
{
    write-host ("Exception.Name " + $_.Exception.GetType().Name);
    write-host ("Message:       " + $_.Exception.Message) 
    write-host ("StackTrace:    " + $_.Exception.StackTrace) 
    continue;
}

Here, $_ is a default variable in the execution context of Trap and holds the current instance of an Exception class.

In this article, I presented a few Windows PowerShell code examples that showed basic steps for running a PowerShell script to automate Microsoft Lync 2010 using Communicator 2007 Automation API. Specifically, I explained:

  • What is required to run PowerShell against the Communicator 2007 Automation API native type library.

  • How to start a PowerShell session.

  • How to obtain a native Messenger coclass type as an entry point to using Communicator 2007 Automation API.

  • How to discover supported members of a Communicator 2007 Automation API type.

  • How to invoke Communicator 2007 Automation API instance properties.

  • How to call Communicator 2007 Automation API instance methods.

  • How to work around native enumeration types.

  • How to trap exceptions in PowerShell.

Kurt De Ding is a Senior Programming Writer, Microsoft Office Content Publishing (UA) group.

Show: