故障描述
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 : [email protected] 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 won't 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 I'm sure you'll 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 : [email protected] https://ucunleashed.com @patrichard
Donations : https://www.paypal.me/PatRichard
Dedicated Post : http://www.ehloworld.com/3168
Disclaimer : You running this script means you won't 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 you've 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 : [email protected] https://ucunleashed.com @patrichard
Donations : https://www.paypal.me/PatRichard
Dedicated Post :
Disclaimer : You running this script means you won't 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 I'm sure you'll 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} : {2}{3}" -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)。
标签:Outlook,Log,Level,Lync,Write,Skype,policy,Message,com From: https://blog.51cto.com/u_10996149/6127826