Friday, 1 March 2013

Administratively Configuring Lync Call Forwarding

The Lync Server 2010 Resource Kit includes a tool called SEFAUtil (the Secondary Extension Feature Activation utility).  There have been a few good guides written for getting the tool to work (there are quite a few steps required), and once it's working correctly you can use it to modify call forwarding settings of Lync-enabled accounts.

You can download the Lync Server 2010 Resource Kit from here:
http://www.microsoft.com/en-us/download/details.aspx?id=21165

And to get started with SEFAUtil I recommend taking a look at these blog posts:
http://blogs.technet.com/b/jenstr/archive/2010/12/07/how-to-get-sefautil-running.aspx
http://blogs.technet.com/b/meacoex/archive/2011/04/23/configure-simultaneous-ring-delegate-ringing-and-call-forwarding-settings-on-behalf-of-a-lync-server-2010-user.aspx

Through some trial and error I found that to delegate the ability to use SEFAUtil you need to grant these permissions:
  • Membership in the "RtcUniversalUserAdmins" Active Directory security group
  • Membership in the "RTC Local Read-only Administrators" local security group on the machine where SEFAUtil is being run
Assuming at this point you (and your delegates) can use SEFAUtil at the command prompt, you may find this script useful.

The script provides a wrapper around SEFAUtil in order to make configuring and disabling call forwarding simpler - you just need to pass in a username and a destination.

To use the script in your environment you must at least change the $LyncServer and $SipDomain defaults in the script, or pass in your own values as parameters. You'll also need the Lync Management Shell module available.

The script supports several options:
  • Forward to manager
  • Forward to a phone number
  • Forward to a SIP address
  • Disable forwarding

# Script to enable or disable call forwarding 

# Parameters for the script
[CmdletBinding(DefaultParametersetName="Common")]
param(
 [Parameter(Mandatory=$true)][string]  $Username = $Null,
 [Parameter(Mandatory=$false)][string] $Destination = $Null,
 [Parameter(Mandatory=$false)][switch] $ForwardToManager = $False,
 [Parameter(Mandatory=$false)][switch] $Disable = $False,
 [Parameter(Mandatory=$false)][string] $SEFAUtilPath = "C:\Program Files\Microsoft Lync Server 2010\ResKit\SEFAUtil.exe",
 [Parameter(Mandatory=$false)][string] $LyncServer = "lyncpool.example.com",
 [Parameter(Mandatory=$false)][string] $SipDomain = "example.com"
 )

# Function to get the current forwarding destination
Function Get-ForwardDest () {
 [CmdletBinding()]
 Param
 (
  [Parameter(Mandatory=$true)][System.Object]$LyncUser
 )
 Process
 {
  $Destination = $Null
  $ForwardDetails = SEFAUtil /Server:$LyncServer $($LyncUser.SipAddress.ToLower().Replace("sip:",""))
  ($ForwardDetails | Out-String).Split("`n") | % {
   If ($_ -like "Forward immediate to*") {
    $Destination = $_.Split()[3]
    If ($Destination -like "*user=phone") {
     # Destination is a number
     $Destination = $Destination.Split("@")[0].Split(":")[1]
    } Else {
     # Destination is a SIP address
     $Destination = $_.Split(":")[2]
    }
   }
  }
  Return $Destination
 }
}

# Function to retrieve manager from AD
Function Get-Manager () {
 [CmdletBinding()]
 Param
 (
  [Parameter(Mandatory=$true)][System.Object]$LyncUser
 )
 Process
 {
  $Searcher = New-Object System.DirectoryServices.DirectorySearcher
  $Filter = "(&(objectCategory=User)(samAccountName=$($LyncUser.SamAccountName)))"
  $Searcher.Filter = $Filter 
  $Searcher.SearchScope = "Subtree"
  $Result = $Searcher.FindOne()
  $Manager = $Result.properties.manager
  
  Return $Manager
 }
}

# Import the Lync PowerShell module
If (-not (Get-Module Lync)) {
 Write-Verbose "Importing Lync PowerShell module"
 If (-not (Import-Module Lync -ErrorAction SilentlyContinue)) {
  Write-Error "Unable to import Lync PowerShell module"
  Break
 }
}

# Set an alias to SEFAUtil
If (Test-Path $SEFAUtilPath) {
 Write-Verbose "Using $SEFAUtilPath"
 Set-Alias SEFAUtil $SEFAUtilPath
} Else {
 Write-Error "SEFAUtil.exe not found at $SEFAUtilPath"
 Break
}

# Get the Lync user object for the supplied username
Write-Verbose "Getting Lync user object"
$LyncUser = Get-CSUser "$Username" -erroraction SilentlyContinue

If (-not $LyncUser) {
 Write-Warning "$Username is not enabled for Lync"
 Write-Host 
 break
}

If ($LyncUser.Count) {
 Write-Warning "Username `"$Username`" matches multiple Lync-enabled accounts. Please specify a unique username."
 Write-Host 
 Break
}

# Output the Lync user object
Write-Host $LyncUser

# Get the current forwarding destination
$ForwardDest = Get-ForwardDest $LyncUser

# Output the current forwarding, if set
If ($ForwardDest) {
 Write-Host "Immediate call forwarding is currently enabled to $ForwardDest"
} Else {
 Write-Host "Immediate call forwarding is not enabled"
}

# Forward to the manager if ForwardToManager is set and we're not disabling
If ($ForwardToManager.IsPresent -and -not $Disable.IsPresent) {
 Write-Host
 Write-Host "Enabling immediate forward to manager..."
 Write-Host
 
 $Manager = Get-Manager $LyncUser
 If (-not $Manager) {
  Write-Error "No manager defined for $LyncUser"
  Write-Host
  Break
 }
 
 $LyncManager = Get-CsUser $Manager.ToString()
 
 If (-not $LyncManager) {
  Write-Error "Manager is not Lync-enabled"
  Write-Host
  Break
 }
 
 $ServerArg = "/Server:$LyncServer"
 $SipUriArg = $($LyncUser.SipAddress.ToLower().Replace("sip:",""))
 $FwdDestArg = "/setfwddestination:$($LyncManager.SipAddress.ToLower())"
 $EnableFwdArg = "/enablefwdimmediate"
 
 Write-Verbose "`"$SEFAUtilPath`" $ServerArg $SipUriArg $FwdDestArg $EnableFwdArg"
 & SEFAUtil $ServerArg, $SipUriArg, $FwdDestArg, $EnableFwdArg

}

# Forward to the destination if one is specified and we're not disabling
If ($Destination -and -not $Disable.IsPresent) {
 Write-Host
 Write-Host "Enabling immediate forward..."
 Write-Host
 If ($Destination -notlike "*@*") {
  # Destination is a number, reformat it as a Uri
  $destination = $destination + "@$SipDomain;user=phone"
 }
 $ServerArg = "/Server:$LyncServer"
 $SipUriArg = $($LyncUser.SipAddress.ToLower().Replace("sip:",""))
 $FwdDestArg = "/setfwddestination:$destination"
 $EnableFwdArg = "/enablefwdimmediate"
 
 Write-Verbose "`"$SEFAUtilPath`" $ServerArg $SipUriArg $FwdDestArg $EnableFwdArg"
 & SEFAUtil $ServerArg, $SipUriArg, $FwdDestArg, $EnableFwdArg
}

# Disable forwarding
If ($Disable.IsPresent -and $ForwardDest) {
 Write-Host
 Write-Host "Disabling immediate forward..."
 Write-Host
 $ServerArg = "/Server:$LyncServer"
 $SipUriArg = $($LyncUser.SipAddress.ToLower().Replace("sip:",""))
 $DisableFwdArg = "/disablefwdimmediate"

 Write-Verbose "`"$SEFAUtilPath`" $ServerArg $SipUriArg $DisableFwdArg"
 & SEFAUtil $ServerArg, $SipUriArg, $DisableFwdArg 
}

Write-Host
Download Script

Usage examples:
 
Forward to manager
PS C:\AdminScripts\Lync> .\Forward-LyncPhone.ps1 benlye -ForwardToManager
CN=benlye,OU=Users,DC=example,DC=com
Immediate call forwarding is not enabled
Enabling immediate forward to manager...
User Aor: sip:ben.lye@example.com
Display Name: Ben Lye
UM Enabled: False
Simulring enabled: False
Forward immediate to: sip:David.Jones@example.com
 
Forward to a SIP address
PS C:\AdminScripts\Lync> .\Forward-LyncPhone.ps1 benlye -Destination sip:Joe.Smith@example.com
CN=benlye,OU=Users,DC=example,DC=com
Immediate call forwarding is not enabled
Enabling immediate forward...
User Aor: sip:ben.lye@example.com
Display Name: Ben Lye
UM Enabled: False
Simulring enabled: False
Forward immediate to: sip:Joe.Smith@example.com
 
Forward to a number
PS C:\AdminScripts\Lync> .\Forward-LyncPhone.ps1 benlye -Destination +441234567890
CN=benlye,OU=Users,DC=example,DC=com
Immediate call forwarding is not enabled
Enabling immediate forward...
User Aor: sip:ben.lye@example.com
Display Name: Ben Lye
UM Enabled: False
Simulring enabled: False
Forward immediate to: sip:+441234567890@example.com;user=phone
 
Disable Forwarding
PS C:\AdminScripts\Lync> .\Forward-LyncPhone.ps1 benlye -Disable
CN=benlye,OU=Users,DC=example,DC=com
Immediate call forwarding is currently enabled to +441234567890
Disabling immediate forward...
User Aor: sip:ben.lye@example.com
Display Name: Ben Lye
UM Enabled: False
Simulring enabled: False
CallForwarding Enabled: false

- Ben

7 comments:

  1. Hi Ben,
    first of all thanks for your great script. I noticed that the script is not run under PowerShell V3. Background is the query in line 90. V3 gives the value 1 back and earlier versions nothing. I only added:
    If ($LyncUser.Count -gt 1) {...}
    therefore it works under PSv3 for me

    Alex

    ReplyDelete
  2. hey, is there a way to redirect a phone number directly to a different phone number, without having to create a Lync user account?

    Greetings from Deutschalnd

    ReplyDelete
  3. Thanks for this. Was able to use your wrapper to get SEFAUtil to run a batch of users from a .CSV with a few modifications, but this saved me 90% of the work.

    ReplyDelete
  4. @Zarc did you ever find the answer to this question

    ReplyDelete
  5. @Zarc did you ever find the answer to this question

    ReplyDelete
  6. Notwithstanding, all such types of gear are accessible in your neighborhood on the off chance that you need to get it online then you can without much of a stretch purchase utilizing web based shopping locales. 0800 business lines

    ReplyDelete
  7. With such a tight work routine, you now and again wish you could be able to answer calls and help clients all an opportunity to continue with your assignments wherever you are.cost of 0800 numbers

    ReplyDelete