关于Lync/Skype客户端无法获取Outlook忙闲信息的问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Lync/Skype客户端无法获取Outlook忙闲信息的问题相关的知识,希望对你有一定的参考价值。
故障描述
Outlook Calendar上有会议,即使Lync/Skype的客户端上EWS和MAPI状态均OK,但是Lync/Skype客户端状态不显示为In a meeting。
故障分析
Lync/Skype在从Outlook Calendar上获取到日历数据再到发布该状态需要经过两个步骤:
- 通过EWS从Outlook Calendar上检索日历数据;
- 将检索到的日历数据发布到状态信息上。
这两个步骤分别受两个参数的影响:1. WebServicePollInterval 2. CalendarStatePublicationInterval
Parameter | Required | Type | Description |
CalendarStatePublicationInterval | Optional | System.UInt32 | Specifies the amount of time, in seconds, that Skype for Business waits before retrieving calendar information from Outlook and adding this data to your presence information. For example, to set the CalendarStatePublicationInterval to 10 minutes (600 seconds) use this syntax: - CalendarStatePublicationInterval 600 |
WebServicePollInterval | Optional | System.TimeSpan | For users of Microsoft Exchange Server 2007 and later versions of the product, WebServicePollInterval specifies how often Skype for Business retrieves calendar data from Microsoft Exchange Server Web Services. WebServicePollInterval can be set to any value between 1 second and 1 hour; inclusive. To configure the Web Service poll interval, use the format hours:minutes:seconds. For example, this command sets the Web Service poll interval to 45 minutes: -WebServicePollInterval 00:45:00 Note that this setting does not apply to users whose email account is on Exchange 2003. For those users, calendar retrieval is managed using MAPIPollInterval. |
这两个值可以通过命令Get-CsClientPolicy进行查看:
注:
1.关于如何创建可以参考New-CSClientPolicy命令(New-CsClientPolicy (SkypeForBusiness) | Microsoft Learn)。
2.在测试的时候发现,使用Set-CsClientPolicy对ClientPolicy修改并应用之后,该策略会立刻执行第一次Check,之后按照所设置的时间间隔进行第二次,第三次。。。Check,因为用户创建的会议起始时间通常都是在0分或者30 分,所以为了让日历上的会议在开始之后能够很快被检索到,我们在整点应用了此策略,而WebServicePollInterval会在CalendarStatePublicationInterval之前发生,所以将前者设置为5分钟,后者设置为5分30秒。
3.ClientPolicy的配置分3个Level(User, Site, Global),所有用户默认使用Golbal策略,在使用Set-CsClientPolicy更改策略时,如果不使用-Identity参数(该参数可选),将默认修改Global策略,所以请注意使用。
技术扩展
”如何根据已有策略,克隆一个相同配置的策略?“
可以使用如下脚本来进行克隆,之后根据需要,将上文中提到的参数进行修改,以创建一个新的Lync/Skype Client Policy。
<#
.SYNOPSIS
Clones an existing Lync Server 2013/Skype for Business Server 2015 policy into a new policy with all existing settings.
.DESCRIPTION
Clones an existing Lync Server 2013/Skype for Business Server 2015 policy into a new policy with all existing settings. The new policy can then be further customized if needed.
.NOTES
Version : 1.3 - See changelog at http://www.ucunleashed.com/2302
Wish list : Better error trapping
Rights Required : CsAdministrator for some functions
Sched Task Required : No
Lync/Skype4B Version : 2013 (tested through CU4), Skype for Business Server 2015
PowerShell Version : 3.0
Author/Copyright : © Pat Richard, Office Servers and Services (Skype for Business) MVP - All Rights Reserved
Email/Blog/Twitter : pat@innervation.com https://www.ucunleashed.com @patrichard
Donations : https://www.paypal.me/PatRichard
Dedicated Post : https://www.ucunleashed.com/2300
Disclaimer : You running this script means you wont blame author(s) if this breaks your stuff. This script is
provided AS IS without warranty of any kind. Author(s) disclaim all implied warranties including,
without limitation, any implied warranties of merchantability or of fitness for a particular
purpose. The entire risk arising out of the use or performance of the sample scripts and
documentation remains with you. In no event shall author(s) be liable for any damages whatsoever
(including, without limitation, damages for loss of business profits, business interruption,
loss of business information, or other pecuniary loss) arising out of the use of or inability
to use the script or documentation. Neither this script, nor any part of it other than those
parts that are explicitly copied from others, may be republished without author(s) express written
permission.
Acknowledgements : Brian Desmond (@brdesmond) for pointing out the InnerText method: http://msdn.microsoft.com/en-us/library/system.xml.xmlelement(v=vs.100).aspx
: Using XML to copy policies: http://blogs.technet.com/b/nexthop/archive/2011/03/21/copypolicies.aspx
: Changing XML data: http://powershell.com/cs/blogs/tobias/archive/2009/02/02/xml-part-2-write-add-and-change-xml-data.aspx
Assumptions : ExecutionPolicy of AllSigned (recommended), RemoteSigned or Unrestricted (not recommended)
Limitations : Only works on Windows Server 2012. This is by design. There are no plans to support Windows Server 2008 R2.
Known issues : None yet, but Im sure youll find some!
.LINK
https://www.ucunleashed.com/2300
.EXAMPLE
.\\New-CsClonedPolicy.ps1 -PolicyType ConferencingPolicy -SourcePolicyName "global" -TargetPolicyName "New Policy"
Description
-----------
Clones the Conferencing Policy called "global" into a new user level policy called "New Policy"
.EXAMPLE
.\\New-CsClonedPolicy.ps1 -PolicyType ConferencingPolicy -SourcePolicyName "global" -TargetPolicyName "Site:Redmond"
Description
-----------
Clones the Conferencing Policy called "global" into a new site level for the Lync/Skype for Business site "Redmond".
.INPUTS
None. You cannot pipe objects to this script.
#>
#Requires -Version 3.0
#Requires -Modules Lync
[CmdletBinding(SupportsShouldProcess, SupportsPaging)]
param(
# Folder location of the exported file while cloning the policy.
[Parameter(ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[string]$ExportFolder = "$env:UserProfile\\desktop",
# Name of temp XML file used while the policy is being cloned. It is automatically deleted when finished.
[Parameter(ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[string]$ExportFile = "ExportedPolicy.xml",
# Defines the policy that will be copied.
[Parameter(ValueFromPipelineByPropertyName, Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$SourcePolicyName,
# Defines the name of the new policy. This policy cannot already exist. By default, specifying a value will create a user level policy. Specifying a name preceeded by "site:" will create a site level policy for that site.
[Parameter(ValueFromPipelineByPropertyName, Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$TargetPolicyName,
# Defines the type of policy being cloned. Valid values are "ArchivingPolicy", "ClientPolicy", "ClientVersionPolicy", "ConferencingPolicy", "ExternalAccessPolicy", "HostedVoicemailPolicy", "LocationPolicy", "MobilityPolicy", "NetworkInterSitePolicy", "PersistentChatPolicy", "PinPolicy", "PresencePolicy", "UserServicesPolicy", "VoicePolicy", "VoiceRoutingPolicy"
[Parameter(ValueFromPipelineByPropertyName, Mandatory)]
[ValidateNotNullOrEmpty()]
[ValidateSet("ArchivingPolicy", "ClientPolicy", "ClientVersionPolicy", "ConferencingPolicy", "ExternalAccessPolicy", "HostedVoicemailPolicy", "LocationPolicy", "MobilityPolicy", "NetworkInterSitePolicy", "PersistentChatPolicy", "PinPolicy", "PresencePolicy", "UserServicesPolicy", "VoicePolicy", "VoiceRoutingPolicy")]
[string]$PolicyType,
# Description for the new policy.
[Parameter(ValueFromPipelineByPropertyName)]
[string]$Description = "Cloned from the policy `$SourcePolicyName` on $(Get-Date -Format f). Created by New-CsClonedPolicy.ps1 (see https://www.ucunleashed.com/2300)",
# Defines the location for any downloaded files. Defaults to "c:\\_install". Additionally, log files generated by this script are located in a subfolder of TargetFolder called "logs". TargetFolder does not support paths with spaces, but does support non-hidden UNC paths.
[Parameter(ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[ValidatePattern((?:[a-zA-Z]\\:|\\\\\\\\[]\\w\\.+|\\w-\\\\[\\w.]+)\\\\(?:[\\w]+\\\\)*\\w[\\w.]+)]
[string] $TargetFolder = "$env:SystemDrive\\_Install"
)
[string] $ScriptVersion = "1.3"
[int] $Article = 2300
[string] $LogPath = "$TargetFolder\\logs\\$env:ComputerName" + " 0:yyyy-MM-dd hh-mmtt.log" -f (Get-Date)
[string] $LogDivider = "+------------------------------+"
#region functions
function Get-UpdateInfo
<#
.SYNOPSIS
Queries an online XML source for version information to determine if a new version of the script is available.
.DESCRIPTION
Queries an online XML source for version information to determine if a new version of the script is available.
.NOTES
Version : 1.2 - See changelog at http://www.ehloworld.com/3168 for fixes & changes introduced with each version
Wish list : Better error trapping
Rights Required : N/A
Sched Task Required : No
Lync/Skype4B Version : N/A
Author/Copyright : © Pat Richard, Office Servers and Services (Skype for Business) MVP - All Rights Reserved
Email/Blog/Twitter : pat@innervation.com https://ucunleashed.com @patrichard
Donations : https://www.paypal.me/PatRichard
Dedicated Post : http://www.ehloworld.com/3168
Disclaimer : You running this script means you wont blame author(s) if this breaks your stuff. This script is
provided AS IS without warranty of any kind. Author(s) disclaim all implied warranties including,
without limitation, any implied warranties of merchantability or of fitness for a particular
purpose. The entire risk arising out of the use or performance of the sample scripts and
documentation remains with you. In no event shall author(s) be liable for any damages whatsoever
(including, without limitation, damages for loss of business profits, business interruption,
loss of business information, or other pecuniary loss) arising out of the use of or inability
to use the script or documentation. Neither this script, nor any part of it other than those
parts that are explicitly copied from others, may be republished without author(s) express written
permission.
Acknowledgements : Reading XML files
http://stackoverflow.com/questions/18509358/how-to-read-xml-in-powershell
http://stackoverflow.com/questions/20433932/determine-xml-node-exists
Assumptions : ExecutionPolicy of AllSigned (recommended), RemoteSigned, or Unrestricted (not recommended)
Limitations :
Known issues :
.LINK
http://www.ehloworld.com/3168
.EXAMPLE
Get-UpdateInfo -Article 123
Description
-----------
Runs function to check for updates to article/script 123.
.INPUTS
None. You cannot pipe objects to this script.
#>
[CmdletBinding(SupportsShouldProcess, SupportsPaging)]
param (
[string] $article
)
[bool] $HasInternetAccess = ([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]DCB00C01-570F-4A9B-8D69-199FDBA5723B)).IsConnectedToInternet)
if ($HasInternetAccess)
[xml] $xml = (New-Object System.Net.WebClient).DownloadString("http://www.ehloworld.com/downloads/version.xml")
[string] $Ga = ($xml.catalog.article | Where-Object $_.id -eq $article).version
if (($xml.catalog.article | Where-Object $_.id -eq $article).versionInfo)
[string] $changelog = "This version includes: " + ($xml.catalog.article | Where-Object $_.id -eq $article).versionInfo
if ($Ga -gt $ScriptVersion)
Write-Log -Level Warn -Message "Outdated version. Version $Ga is latest version. Prompting user to upgrade." -NoConsole
if ((New-Popup -Message "Version $Ga is now available. $changelog `n`nWould you like to download it?" -Title "New version available!" -Buttons YesNo -Icon Question) -eq 6)
Write-Log -Message "User elected to download latest version." -Indent 1 -NoConsole
Write-Log -Message "Opening Internet Explorer and going to http://www.ehloworld.com/$article#downloads." -NoConsole -Indent 1
Start-Process "http://www.ehloworld.com/$article#downloads"
Write-Log -Level Warn -Message "Script is exiting. Please start the new version of the script once youve downloaded it." -NoLog
Exit
else
Write-Log -Level Warn -Message "User elected NOT to download latest version." -Indent 1 -NoConsole
elseif ($Ga -eq $ScriptVersion)
Write-Log -Message "Current version. Version $Ga is latest version." -NoConsole
elseif (-Not ($Ga))
# Write-Log -Level Warn -Message "Possibly regressed version. Version $Ga is latest version." -NoConsole
Write-Log -Level Warn -Message "No version info available" -NoConsole
else
Write-Log -Level Warn -Message "Unable to check online for update info." -NoConsole
# end function function Get-UpdateInfo
function Update-XMLData
[CmdletBinding(SupportsShouldProcess)]
param()
if (-not(Test-Path "$ExportFolder\\$ExportFile"))
Write-Log -Level Error -Message "Unable to export policy settings for `"$SourcePolicyName`" to $ExportFolder\\$ExportFile"
break
Write-Log -Level Info -Message "Updating XML data" -NoConsole
$xml = New-Object XML
$xml.Load("$ExportFolder\\$ExportFile")
($xml.Objs.Obj.Props.S | Where-Object $_.N -eq "Identity").InnerText = $TargetPolicyName
if ($xml.Objs.Obj.Props.S | Where-Object $_.N -eq "Name")
($xml.Objs.Obj.Props.S | Where-Object $_.N -eq "Name").InnerText = $TargetPolicyName
Write-Log -Level Info -Message "Saving updated XML data" -NoConsole
$xml.Save("$ExportFolder\\$ExportFile")
# end function Update-XMLData
function Write-Log
<#
.SYNOPSIS
Extensive function to write data to either the console screen, a log file, and/or a Windows event log.
.DESCRIPTION
Extensive function to write data to either the console screen, a log file, and/or a Windows event log. Data can be written as info, warning, error, and includes indentation, time stamps, etc.
.NOTES
Version : 2.9
Wish list : Better error trapping
Rights Required : Local administrator on server
Sched Task Required : No
Lync/Skype4B Version : N/A
Author/Copyright : © Pat Richard, Office Servers and Services (Skype for Business) MVP - All Rights Reserved
Email/Blog/Twitter : pat@innervation.com https://ucunleashed.com @patrichard
Donations : https://www.paypal.me/PatRichard
Dedicated Post :
Disclaimer : You running this script means you wont blame author(s) if this breaks your stuff. This script is
provided AS IS without warranty of any kind. Author(s) disclaim all implied warranties including,
without limitation, any implied warranties of merchantability or of fitness for a particular
purpose. The entire risk arising out of the use or performance of the sample scripts and
documentation remains with you. In no event shall author(s) be liable for any damages whatsoever
(including, without limitation, damages for loss of business profits, business interruption,
loss of business information, or other pecuniary loss) arising out of the use of or inability
to use the script or documentation. Neither this script, nor any part of it other than those
parts that are explicitly copied from others, may be republished without author(s) express written
permission.
Acknowledgements : Test for log names and sources
http://powershell.com/cs/blogs/tips/archive/2013/06/10/testing-event-log-names-and-sources.aspx
Assumptions : ExecutionPolicy of AllSigned (recommended), RemoteSigned, or Unrestricted (not recommended)
Limitations :
Known issues : None yet, but Im sure youll find some!
.LINK
.EXAMPLE
.\\
Description
-----------
.INPUTS
None. You cannot pipe objects to this script.
#>
[CmdletBinding(SupportsShouldProcess, SupportsPaging)]
param(
# The type of message to be logged. Alias is type.
[Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[ValidateSet("Error", "Warn", "Info")]
[ValidateNotNullOrEmpty()]
[string] $level = "Info",
# The message to be logged.
[Parameter(Position = 1, ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory, HelpMessage = "No message specified.")]
[ValidateNotNullOrEmpty()]
[string] $Message,
# Specifies that $message should not the sent to the log file.
[Parameter(Position = 2, ValueFromPipelineByPropertyName)]
[switch] $NoLog,
# Specifies to not display the message to the console.
[Parameter(Position = 3, ValueFromPipelineByPropertyName)]
[switch] $NoConsole,
# The number of spaces to indent the message in the log file.
[Parameter(Position = 4, ValueFromPipelineByPropertyName)]
[ValidateRange(1,30)]
[ValidateNotNullOrEmpty()]
[Int16] $Indent = 0,
# Specifies what color the text should be be displayed on the console. Ignored when switch NoConsoleOut is specified.
[Parameter(Position = 5, ValueFromPipelineByPropertyName)]
[ValidateSet("Black", "DarkMagenta", "DarkRed", "DarkBlue", "DarkGreen", "DarkCyan", "DarkYellow", "Red", "Blue", "Green", "Cyan", "Magenta", "Yellow", "DarkGray", "Gray", "White")]
[ValidateNotNullOrEmpty()]
[String] $ConsoleForeground = White,
# Existing log file is deleted when this is specified. Alias is Overwrite.
[Parameter(Position = 6, ValueFromPipelineByPropertyName)]
[Switch] $Clobber,
# The name of the system event log, e.g. Application. Note that writing to the system event log requires elevated permissions.
[Parameter(Position = 7, ValueFromPipelineByPropertyName)]
[ValidateSet("Application","System","Security","Lync Server","Microsoft Office Web Apps")]
[ValidateNotNullOrEmpty()]
[String] $EventLogName,
# The name to appear as the source attribute for the system event log entry. This is ignored unless EventLogName is specified.
[Parameter(Position = 8, ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[String] $EventSource = $($MyInvocation.ScriptName).Name,
# The ID to appear as the event ID attribute for the system event log entry. This is ignored unless EventLogName is specified.
[Parameter(Position = 9, ValueFromPipelineByPropertyName)]
[ValidateRange(1,65535)]
[ValidateNotNullOrEmpty()]
[Int32] $EventID = 1,
# The text encoding for the log file. Default is ASCII.
[Parameter(Position = 10, ValueFromPipelineByPropertyName)]
[ValidateSet("Unicode","Byte","BigEndianUnicode","UTF8","UTF7","UTF32","ASCII","Default","OEM")]
[ValidateNotNullOrEmpty()]
[String] $LogEncoding = "ASCII"
) # end of param block
try
[string]$LogFolder = Split-Path $LogPath -Parent
if (-Not(Test-Path -Path $LogFolder))New-Item $LogFolder -type Directory | Out-Null
$msg = "0 : 1 : 23" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Level.ToUpper(), (" " * $Indent), $Message
if (-Not($NoConsole))
switch ($level)
"Error" $Host.UI.WriteErrorLine("$Message")
"Warn" Write-Warning $Message
"Info" Write-Host $Message -ForegroundColor $ConsoleForeground
if (-Not($NoLog))
if ($Clobber)
$msg | Out-File -FilePath $LogPath -Encoding $LogEncoding -Force
else
$msg | Out-File -FilePath $LogPath -Encoding $LogEncoding -Append
# http://social.technet.microsoft.com/Forums/en-US/winserverpowershell/thread/e172f039-ce88-4c9f-b19a-0dd6dc568fa0/
if ($EventLogName)
if (-Not $EventSource)
[string] $EventSource = $([IO.FileInfo] $MyInvocation.ScriptName).Name
if(-Not [Diagnostics.EventLog]::SourceExists($EventSource))
[Diagnostics.EventLog]::CreateEventSource($EventSource, $EventLogName)
switch ($Level)
"Error" $EntryType = "Error"
"Warn" $EntryType = "Warning"
"Info" $EntryType = "Information"
Default $EntryType = "Information"
Write-EventLog -LogName $EventLogName -Source $EventSource -EventId 1 -EntryType $EntryType -Message $Message
$msg = ""
# end try
catch
Throw "Failed to create log entry in: $LogPath. The error was: $_."
# end catch
# end function Write-Log
#endregion functions
Write-Log -Level Info -Message "Version : $ScriptVersion" -NoConsole
Get-UpdateInfo -Article $Article
Write-Log -Level Info -Message $LogDivider -NoConsole
Write-Log -Level Info -Message "Source policy: $SourcePolicyName" -NoConsole
Write-Log -Level Info -Message "Target policy: $TargetPolicyName" -NoConsole
Write-Log -Level Info -Message "Policy type : $PolicyType" -NoConsole
Write-Log -Level Info -Message $LogDivider -NoConsole
[string] $get = "Get-Cs$PolicyType -Identity `"$SourcePolicyName`" | Export-Clixml -Path `"$ExportFolder\\$ExportFile`""
[string] $set = "Import-Clixml -Path `"$ExportFolder\\$ExportFile`" | Set-Cs$PolicyType"
if ($PolicyType -ne "UserServicesPolicy")$set += " -Description `"$Description`""
Write-Log -Level Info -Message "Exporting data" -NoConsole
Invoke-Expression $get
Update-XMLData
Write-Log -Level Info -Message "Importing updated XML data into new policy `"$TargetPolicyName`"" -NoConsole
Invoke-Expression $set
$Successful = "Get-Cs$PolicyType -Identity $TargetPolicyName"
if (Invoke-Expression $Successful -ErrorAction SilentlyContinue)
Write-Log -Level Info -Message "Target policy `"$TargetPolicyName`" successfully created" -NoConsole
else
Write-Log -Level Error -Message "Target policy `"$TargetPolicyName`" NOT created" -NoConsole
Remove-Item "$ExportFolder\\$ExportFile" -Force
”如何对用户应用/移除用户级别策略?”
关于如何创建可以参考Grant-CSClientPolicy命令(Grant-CsClientPolicy (SkypeForBusiness) | Microsoft Learn)。
Lync Skype 会议 - 生成会议 URL
【中文标题】Lync Skype 会议 - 生成会议 URL【英文标题】:Lync Skype Meeting - Generate the Meeting URL 【发布时间】:2018-01-18 16:51:17 【问题描述】:目前,该应用程序能够使用 Office 365 REST API 创建 Outlook 会议事件。因此,它通过身份验证,获取 Access_Token,然后创建新事件。
在 Microsoft Outlook 中,当我单击 Skype 会议按钮时,它会在会议正文中生成一个加入 Skype 会议 URL(示例如下),我喜欢将“加入 Skype 会议”的 URL 包含在该应用程序用于创建新事件。
Join Skype Meeting
https://meet.lync.com/OrganizationName/FirstName.LastName/L03XXXXX
IT 人员已向 Azure Active Directory 上的应用程序授予 Skype for Business 权限。
我可以为事件使用相同的 Access_Token 来为 Lync API 生成加入 Skype 会议 URL?关于如何实现这一点的任何建议?
提前致谢,
【问题讨论】:
【参考方案1】:简短的回答是否定的。
您需要意识到的第一件事是涉及两个不同的系统。
Skype For Business 用户大会 Office / Office 365 日历条目“Skype For Business 用户会议”是会议 URL 指向的内容以及“Skype”客户所知道的内容。他们对办公室日历条目一无所知。
Office“Skype 会议”日历条目具有指向“Skype For Business 用户会议”的“额外”元数据(包括 URI)。
因此,您无需创建 Office 日历条目即可创建或使用“Skype For Business 用户会议”。要创建 Skype 会议,您可以使用 UCWI API here(或者,如果您在 Web 浏览器中执行所有操作,则可以使用 WebSDK,它是 UCWA API here 的包装器)。创建 Skype 用户会议后,您将拥有会议 URI 以将人们指向。
如果您需要创建一个“Skype”会议日历条目,那么我们遇到的问题是这些日历条目的元数据没有被 Microsoft 记录在任何地方(我已经找到)。
最好的方法是手动生成“Skype”会议,然后转储添加的元数据。然后找出您需要在元数据中更改的内容,然后将元数据“添加”到您自己创建的 API 日历条目中。这是这里的工作人员所做的,并且运行良好。
我不记得元数据的确切细节,因为我已经有一段时间没有研究这个了。
【讨论】:
以上是关于关于Lync/Skype客户端无法获取Outlook忙闲信息的问题的主要内容,如果未能解决你的问题,请参考以下文章
我们可以在 Eclipse IDE 中使用 Lync/Skype SDK