Is it possible to set call forwarding via the Lync

2019-02-20 06:59发布

问题:

I work for an IS department in a large institution. The Lync servers that handle our telephones are handled by another department, and any solution that requires cooperation from them is not viable. This rules out any solutions that require extra privileges, running from the Lync servers, SEFAUtil, etc.

My personal Lync 2013 client has some abominable GUI menu where I can forward my desk phone to another number. I know therefor that it is possible, in theory.

I have powershell code that (with a ton of SDKs installed) will login with my own personal credentials. The blog I grabbed it from allowed the script to send some arbitrary IM message (not very useful to me). It looks like this:

if (-not (Get-Module -Name Microsoft.Lync.Model)) {     
    try {       
        Import-Module -Name (Join-Path -Path ${env:ProgramFiles} -ChildPath "Microsoft Office\Office15\LyncSDK\Assemblies\Desktop\Microsoft.Lync.Model.dll")
-ErrorAction Stop   
    }
    catch {
        Write-Warning "Microsoft.Lync.Model not available, download and install the Lync 2013 SDK http://www.microsoft.com/en-us/download/details.aspx?id=36824"        break   
    }
}

$client = [Microsoft.Lync.Model.LyncClient]::GetClient()

if ($client.State -ne [Microsoft.Lync.Model.ClientState]::SignedIn) {
    $client.EndSignIn(
        $client.BeginSignIn("x@x.com", "domain\johno", "youllNeverGuess", $null, $null)) 
}

if ($Client.State -eq "SignedIn") {
    Write-Host "DEBUG: We managed to sign in!" }
}

This seems to work, in that if I supply it the wrong password, it barfs.

From within the SDK, is it possible to set callfowarding to a particular number? Microsoft's horrible documentation demonstrates how to forward an incoming call that the script caught through an event handler, meaning that it'd have to run in a polling loop... and that I couldn't just iterate through a list of accounts to forward. From the GUI client, if you set your phone to forward to a number, it sticks even if you power down the machine, so it's sending something to the server that is semi-permanent. Can Lync SDK accomplish the same?

Though Lync 2010 is deprecated, I would be happy with a solution based upon that. Powershell is preferred, but if you have code in VB or C#, again that would be ok too. I don't need the whole thing served up on a silver platter, just a few clues to work with.

回答1:

You need to publish your routing information to the Lync server. This contains your simultaneous-ring and forwarding settings, amongst others.

If you're OK with creating a .Net solution, try the following:

When you need to program against the Lync server and cannot get any elevated privileges, try using UCMA and create a UserEndpoint. Since you know your Lync server address and have login details, you can create and authenticate a UserEndpoint without cooperation from the other department.

Example (not mine): Creating UCMA Applications with a UserApplication instance.

Once you get your endpoint set up, you're basically home free. With the ability to publish presence, you can publish routing settings. For Lync, "presence" is a container which contains everything like availability, routing, contact details, custom locations, etc.

On your UserEndpoint, subscribe to LocalOwnerPresence.PresenceNotificationReceived MSDN.

After you sign in with your endpoint, this event will fire and give you your current settings. In the event argument LocalPresentityNotificationEventArgs, grab the AllCategories collection, and look for the PresenceCategoryWithMetaData with the name "routing". Create a new instance of the Routing container with this data. The routing container is the class Microsoft.Rtc.Internal.Collaboration.Routing in Microsoft.Rtc.Collaboration.dll.

private void OnLocalPresenceNotificationReceived(
    object sender, 
    LocalPresentityNotificationEventArgs e) 
{
    var container = (from c in e.AllCategories
                     where string.Equals(c.Name, "routing", StringComparison.OrdinalIgnoreCase)
                     orderby c.PublishTime descending
                     select c).FirstOrDefault();

    if (container != null)
    {
        var routing = new Microsoft.Rtc.Internal.Collaboration.Routing(container);

        // You can access the routing data here...
    }
}

If you do not receive any routing container, you can create a new instance. Take care though that publishing a new instance will override all your current routing settings instead of allowing you to update the current settings.

In the Routing class you can write to the following property:

routing.CallForwardToTargetsEnabled = true;
routing.CallForwardTo.Clear();
routing.CallForwardTo.Add("sip or tel number");
routing.UserOnlyWaitTime = TimeSpan.FromSeconds(...);

And finally, publish the new routing settings:

endpoint.LocalOwnerPresence.PublishPresenceAsync(new PresenceCategory[] { 
    routing 
});

It is also possible to publish presence by getting your current Lync instance with the GetClient() method in the Lync SDK. I'm not sure however if this can be used to publish routing settings. You could try though, I found many undocumented options while playing around with Lync. Look at the following two resources:

How to: Publish enhanced presence information and Self.BeginPublishContactInformation