Select Page

Lync 2013 – Oauth On-Premises (Lync Server 2013 and Exchange 2013)

What is this?

Since Lync Server 2013, there is a new prerequisite on the Lync Servers for Exchange 2013 interconnection: This will allow you to use :

  • Unified Contact Store (UCS)
  • Exchange OWA IM and presence Integration

Windows Identity Foundation

  “It’s a new extension to the Microsoft .NET Framework that makes it easy for developers to enable advanced identity capabilities in the .NET Framework applications.” This feature has been created to support server to server authentication. It is used by asp.net and Windows Communication Foundation applications. (In our situation, by Lync server 2013 and Exchange Server 2013)   In order to configure Oauth, you must do two things:

  • Assign a certificate to Lync Server’s
  • Set Exchange as a partner application.

Please note : “It should also be pointed out that you do not need to use server-to-server authentication: server-to-server authentication is not required in order to deploy Lync Server 2013. If Lync Server 2013 does not need to communicate with other servers (such as Exchange 2013) then server-to-server authentication is not needed.” Source   Also note that “your Lync Server 2013 default certificate can also be used as the OAuthTokenIssuer certificate” Source


Installation

There is two ways to install the WIF : Windows Server 2008 R2    Install with the Windows Identity Foundation (KB974405) installer.   Windows Server 2012    Server Manager Go to Add Roles and Features Wizard, select Features. Select Windows Identity Foundation 3.5 from the list. Click Next, then click Install.   Powershell

Add-WindowsFeature Windows-Identity-Foundation

Once WIF has been installed you can run Deployment Wizard and Assign the Lync default certificate to Oauth certificate.


Sources

Description of Windows Identity Foundation (http://support.microsoft.com/kb/974405/en-us) Microsoft TechNet – Lync Server 2013 (http://technet.microsoft.com/en-us/library/gg398616.aspx)

Lync – Get-MCsPool

When you look for a simple way to get all Lync Server topology, you probably will do a Get-CsPool command. But here, you don’t see the sites and the output is not coming in a easily readable way.

The script below will let you Show all information at once.

Get-MCsPool will show you your infrastructure in an easy way :

Get-MCsPool

 

Communication Server versions tested
Office Communication Server 2007
Microsoft Lync Server 2010 OK
Microsoft Lync Server 2013 OK

 

function Get-MCsPool{

	foreach ($site in Get-Cssite){ 
		Write-Host "Site : " $site.Displayname "( " -NoNewline -ForegroundColor Green
		if ($site.Description -notlike ""){
			Write-Host $site.Description")" -foregroundcolor Green
		}else{
			Write-Host "No description" -foregroundcolor DarkRed -NoNewline
			Write-Host " )" -foregroundcolor Green
		}
		$pools = $site | select -ExpandProperty pools
		foreach ($pool in $pools){
			$boolDiscovered = $false
			[array]$ServerType = ""
		
			Write-Host "Pool : " $pool -ForegroundColor Cyan -NoNewline
			$services = Get-CsPool $pool | select -ExpandProperty services #Get all services from the current pool
			
			If ($Site.ParentSite -ne $Null){ #SBA
				if ($services.count -ge 2){
					$ServerType += "Survivable Branch Appliance"
					$boolDiscovered = $true
				}else{
					$ServerType += " PSTN Gateway "
					$boolDiscovered = $true
				}
			}else{ #NO SBA
			
				$PoolComputersCount = (get-cspool $pool | select -ExpandProperty computers ).count #Get the computer numbers in a pool
	 			if ($PoolComputersCount -ge 2){ #POOL SERVERS (If there is 2 or more computers
					$findOut = $services -match '.*Registrar:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "Enterprise Edition Pool"
						$boolDiscovered = $true
					}
					$findOut = $services -match '.*PersistentChatService:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "Persistent Chat Pool"
        				$boolDiscovered = $true
					}
					$findOut = $services -match '.*TrustedApplicationPool:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "Trusted Application Pool"
        				$boolDiscovered = $true
					}
					$findOut = $services -match '.*EdgeServer:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "EDGE Pool"
        				$boolDiscovered = $true
					}
			
				}else{ #STANDALONE SERVERS (Only one computer)
	    			$findOut = $services -match '.*Registrar:([a-zA-Z]).*'
        			if ($findOut) {
						$Registrar = $findOut -replace "Registrar:",""
						$ServerType += "Standard Edition Pool"
						$boolDiscovered = $true
        			}
					$findOut = $services -match '.*PstnGateway:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "PSTN Gateway"
        				$boolDiscovered = $true
					}
					$findOut = $services -match '.*EdgeServer:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "EDGE Server"
        				$boolDiscovered = $true
					}
					$findOut = $services -match '.*MonitoringServer:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "Monitoring Server"
        				$boolDiscovered = $true
					}
					$findOut = $services -match '.*ArchivingServer:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "Archiving Server"
        				$boolDiscovered = $true
					}
					$findOut = $services -match '.*WacServer:([a-zA-Z]).*'  #Lync 2013
        			if ($findOut) {
						$ServerType += "Office Web Apps Server"
        				$boolDiscovered = $true
					}else{
						$findOut = $services -match '.*WacService:([a-zA-Z]).*' #Lync 2010
						if ($findOut) {
							$ServerType += "Office Web Apps Server"
        					$boolDiscovered = $true
						}
					}
					$findOut = $services -match '.*TrustedApplicationPool:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "Trusted Application Server"
        				$boolDiscovered = $true
					}
					$findOut = $services -match '.*FileStore:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "File Server"
        				$boolDiscovered = $true
					}
					$findOut = $services -match '.*ApplicationDatabase:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "SQL Server"
        				$boolDiscovered = $true
					}
					$findOut = $services -match '.*PersistentChatServer:([a-zA-Z]).*'
        			if ($findOut) {
						$ServerType += "Persistent Chat Server"
        				$boolDiscovered = $true
					}
				}#End pool or no pool
			
			}#end sba or no sba		
			
			if (!$boolDiscovered){ #If the variable is false, it means the service is unknown
				Write-Host " (N/A)" -ForegroundColor Gray -NoNewline
			}else{#If the variable is true, it means the service was discovered
				foreach ($type in $ServerType){
					if ($type -notlike ""){
						if (($type -like "*Edition*") -or ($type -like "Survivable*")){ #For the main pools, Write in Yellow
							Write-Host " ["$type" ]" -ForegroundColor Yellow -NoNewline
						}else{
							Write-Host " ["$type" ]" -ForegroundColor DarkCyan -NoNewline #For the normal service types, write in darkcyan
						}
					}
				}
			}
			Write-Host "" #Add a return after each line
		}#Close Pools foreach
	}#Close Site foreach
}#Close Get-MCsPool function

Lync 2013 – Activate Unified Contact Store

 

This post will explain the Unified Contact Store on Microsoft Lync 2013 and Exchange 2013 deployments.

 


What is this?

This is a feature who will share the contacts between all the Microsoft Office products. In fact, it will store all contact information in Exchange 2013 and make it available for :

  • Lync Client 2013
  • Exchange 2013
  • Outlook 2013
  • Outlook Web Access 2013

This makes the contacts available globally in the organization.

 


Prerequisites

You must be running Microsoft Lync Server 2013 and Exchange 2013.

  • Users must use Lync 2013 to initiate the migration of contacts from Lync Server 2013 to Exchange 2013.
  • User mailboxes must be migrated to Exchange 2013.
  • You must have server-to-server authentication (Oauth) configured between Lync Server 2013 and Exchange 2013.
  • Lync 2010 Client and older versions will not be able to work with UCS (they can only read contacts).

I will explain the process of creating an Oauth partnership with Exchange 2013 in my next post.


Activation

Ensure you get all the prerequisites before activating.

In order to test it, create a User Policy that you will assign to you before enabling everyone :

New-CsUserServicesPolicy -Identity "UserSvcPolicy-UCSEnabled" -UcsAllowed $True
Grant-CsUserServicesPolicy -Identity "JohnDoeAdmin" -PolicyName "UserSvcPolicy-UCSEnabled"

After you see everything is working fine, you can activate UCS for all users, you only need to change the Global User Service Policy using PowerShell:

Set-CsUserServicesPolicy -Identity global -UcsAllowed $True

 


 

Check

On outlook 2013, got to Contacts and verify you have the Lync Contacts folder as in the picture :

 

UCS Outlook

On Lync Client, check the Lync Configuration Information page (Pres Ctrl and right click the Lync icon, then go to Configuration Information).

It may be an entry named Contact List Provider. It may have changed to UCS instead of Lync Server.

 

UCS Lync Configuration Info

Change Voice Policy of Lync 2013 Response Group Workflow, Dialin, or any other service

There is two ways to change the Voice Policy with Lync 2013.

  • CmdLets
  • Active Directory (advanced)

First of all, we will se how to get the Voice Policy from an Application Endpoint (Workflow, Dialin etc…) :

Get-CsApplicationEndpoint -Identity "*WorkflowName*" | Select VoicePolicy
Get-CsApplicationEndpoint -Identity "*WorkflowName*" | FL *

So if you want to change the voice Policy of a Workflow with powershell, here is the cmdlet :

Get-CsApplicationEndpoint -Identity "*WorkflowName*" | GrantCsVoicePolicy -PolicyName "VPolicy-US-International"

Now we are going to be more “serious” by going to make changes in the Active Directory for the workflow itself.

First, depending on your environment, the RTC services folder can be found in different paths:

  • [Configuration]/Services/RTC Services/Application Contacts
  • [Domain Naming Context]/Services/Microsoft/RTC Services/Application Contacts

Once you’re in the path, search for the Active Directory Contact object that is your workflow, and modifies the attribute of msRTCSIP-UserPolicies.

It may have some entries like “0=123,1=6,7=2,…”

The “7=” is the voice Policy pointer. So to assign the correct voice Policy number to the Contact, Show the anchors of the voice policies in powershell and add it to the contact.

Powershell Voice Policy Anchor :

Get-CsVoicePolicy | select Anchor

This is working for all the policies.

Karl

Disable Close button in Powershell Window

I did some powershell scripting these days.

Disabled Window running script

Disabled Window running script

Someone asked me if it would be possible to avoid the user to close the powershell window while a script is running (logon or any other). After a few searches in the MSDN world, I was able to handle the window and send some parameters to it.

For this, I ask the user32.dll Library to disable the powershell window and to disable the button (close menu). To remove any undesired button, I set the Windows style to Toolbox.

I know the fact of disabling window will avoid any user input and click on any button, but as they asked me to disable the button, I dit it this way. So use the rest as know-how… 🙂

Knowing what I need to code, I will use some user32.dll methods :

  • GetSytemMenu
  • EnableMenuItem
  • SetWindowLongPtr
  • EnableWindow

Hope that this script can be useful to some admins!

Karl

Windows versions tested
Windows 2000
Windows XP
Windows 7 OK
Windows 8
Windows 8.1 Standard OK (Disabled window only)

 

Here is the script :

#Calling user32.dll methods for Windows and Menus
$MethodsCall = '
[DllImport("user32.dll")] public static extern long GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")] public static extern bool EnableMenuItem(long hMenuItem, long wIDEnableItem, long wEnable);
[DllImport("user32.dll")] public static extern long SetWindowLongPtr(long hWnd, long nIndex, long dwNewLong);
[DllImport("user32.dll")] public static extern bool EnableWindow(long hWnd, int bEnable);
'

#Create a new namespace for the Methods to be able to call them
Add-Type -MemberDefinition $MethodsCall -name NativeMethods -namespace Win32

#WM_SYSCOMMAND Message
$MF_GRAYED = 0x00000001L    #Indicates that the menu item is disabled and grayed so that it cannot be selected.
$MF_BYCOMMAND = 0x0               #Gives the identifier of the menu item. If neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified, the MF_BYCOMMAND flag is the default flag.            
$MF_DISABLED = 0x00000002L #Indicates that the menu item is disabled, but not grayed, so it cannot be selected.
$MF_ENABLED = 0x00000000L #Indicates that the menu item is enabled and restored from a grayed state so that it can be selected.
#... http://msdn.microsoft.com/en-us/library/windows/desktop/ms647636(v=vs.85).aspx

$SC_CLOSE = 0xF060
$SC_CONTEXTHELP = 0xF180
$SC_MAXIMIZE = 0xF030 
$SC_MINIMIZE = 0xF020 
$SC_TASKLIST = 0xF130
$SC_MOUSEMENU = 0xF090
$SC_KEYMENU = 0xF100
#... http://msdn.microsoft.com/en-us/library/windows/desktop/ms646360(v=vs.85).aspx

$GWL_EXSTYLE = -20
$GWL_STYLE = -16
#... http://msdn.microsoft.com/en-us/library/windows/desktop/ms644898(v=vs.85).aspx

#WM_SETICON Message  -  http://msdn.microsoft.com/en-us/library/ms632643%28VS.85%29.aspx
$WM_SETICON = 0x0080;
$ICON_SMALL = 0;
$ICON_BIG = 1;

#Extended Window Styles
$WS_EX_DLGMODALFRAME = 0x00000001L
$WS_EX_NOACTIVATE = 0x08000000L
$WS_EX_TOOLWINDOW = 0x00000080L
$WS_EX_STATICEDGE = 0x00020000L
$WS_EX_WINDOWEDGE = 0x00000100L
$WS_EX_TRANSPARENT = 0x00000020L
$WS_EX_CLIENTEDGE = 0x00000200L
$WS_EX_LAYERED = 0x00080000
$WS_EX_TOPMOST = 0x00000008L
#... http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx

#Get window handle of Powershell process (Ensure there is only one Powershell window opened)
$PSWindow = (Get-Process Powershell) | where {$_.MainWindowTitle -like "*Powershell*"}
$hwnd = $PSWindow.MainWindowHandle

#Get System menu of windows handled
$hMenu = [Win32.NativeMethods]::GetSystemMenu($hwnd, 0)

#Window Style : TOOLWINDOW
[Win32.NativeMethods]::SetWindowLongPtr($hwnd, $GWL_EXSTYLE, $WS_EX_TOOLWINDOW) | Out-Null

#Disable X Button and window itself
[Win32.NativeMethods]::EnableMenuItem($hMenu, $SC_CLOSE, $MF_DISABLED) | Out-Null
[Win32.NativeMethods]::EnableWindow($hwnd, 0) | Out-Null

Write-Host "Disabled!" -ForegroundColor Red 
sleep 5

#Enable X Button
[Win32.NativeMethods]::EnableMenuItem($hMenu, $SC_CLOSE, $MF_ENABLED) | Out-Null
[Win32.NativeMethods]::EnableWindow($hwnd, 1) | Out-Null

Write-Host "Enabled!" -ForegroundColor Green
sleep 2