Microsoft Entra Connect:暂存服务器和灾难恢复
当服务器处于暂存模式时,可以在激活服务器之前更改配置并预览更改。 它还允许运行完全导入和完全同步,以便在生产环境中应用所有更改之前验证这些更改是否符合预期。
过渡模式
暂存模式可以用于许多方案,包括:
- 高可用性。
- 测试和部署新的配置更改。
- 引入新的服务器并解除旧服务器。
可以在安装过程中选择将服务器置于暂存模式。 此操作可以激活服务器进行导入和同步,但不会运行任何导出。 处于暂存模式的服务器不会运行密码同步或密码写回,即使在安装期间选择了这些功能。 如果禁用暂存模式,服务器将开始导出,启用密码同步,并启用密码写回。
注意
假设拥有已启用密码哈希同步功能的 Microsoft Entra Connect。 如果启用暂存模式,则服务器停止同步本地 AD 的密码更改。 如果禁用暂存模式,则服务器从上次离开的位置恢复同步密码更改。 如果服务器长时间处于暂存模式,则服务器可能需要一段时间才能同步该时间段内发生的所有密码更改。
仍然可以使用 Synchronization Service Manager 强制导出。
处于暂存模式的服务器继续从 Active Directory 和 Microsoft Entra ID 接收更改,并且在发生故障时可以快速接管另一台服务器的职责。 如果对主要服务器进行配置更改,则需要负责对处于暂存模式的服务器进行相同的更改。
对于熟悉旧式同步技术的人员而言,暂存模式是不同的,因为服务器有自身的 SQL 数据库。 此体系结构允许将暂存模式服务器放置在不同的数据中心。
验证服务器的配置
若要应用此方法,请遵循以下步骤:
准备
- 安装 Microsoft Entra Connect,选择“暂存模式”,并取消选择安装向导中最后一页上的“启动同步”。 此模式允许手动运行同步引擎。
- 注销/登录并从“开始”菜单选择“同步服务”。
配置
如果对主服务器进行了自定义更改并希望比较配置和临时服务器,则使用 Microsoft Entra Connect 配置文档管理器。
导入和同步
- 选择“连接器”,并选择第一个 Active Directory 域服务类型的连接器。 单击“运行”,然后依次选择“完全导入”和“确定”。 针对此类型的所有连接器执行这些步骤。
- 选择类型为“Microsoft Entra ID (Microsoft)”的连接器。 单击“运行”,然后依次选择“完全导入”和“确定”。
- 确保“连接器”选项卡仍处于选中状态。 针对每个 Active Directory 域服务类型的连接器,单击“运行”,然后依次选择“增量同步”和“确定”。
- 选择类型为“Microsoft Entra ID (Microsoft)”的连接器。 单击“运行”,然后依次选择“增量同步”和“确定”。
现在,已将导出更改暂存到 Microsoft Entra ID 和本地 AD(如果使用的是 Exchange 混合部署)。 后续步骤可让你在实际开始导出到目录之前,检查将要更改的内容。
验证
- 启动 cmd 提示符并转到
%ProgramFiles%\Microsoft Azure AD Sync\bin
- 运行:
csexport "Name of Connector" %temp%\export.xml /f:x
连接器名称可以在同步服务中找到。 它的名称类似于 Microsoft Entra ID 的“contoso.com - Microsoft Entra ID”。 - 运行:
CSExportAnalyzer %temp%\export.xml > %temp%\export.csv
%temp% 中已有名为 export.csv 的文件,可在 Microsoft Excel 中检查。 此文件包含要导出的所有更改。 - 对数据或配置进行必要的更改并再次执行这些步骤(导入、同步和身份验证),直到要导出的更改都按预期进行。
了解 export.csv 文件
大部分的文件都简单易懂。 请理解内容中的的一些缩写:
- OMODT – 对象修改类型。 指示对象级别的操作是添加、更新还是删除。
- AMODT – 属性修改类型。 指示属性级别的操作是添加、更新还是删除。
检索通用标识符
export.csv 文件包含所有待导出的更改。 每行都对应于连接器空间中某个对象的更改,该对象由 DN 属性标识。 DN 属性是分配给连接器空间中对象的唯一标识符。 当 export.csv 中存在较多待分析的行/更改时,仅凭 DN 属性可能难以判断哪些对象发生了更改。 要简化分析更改的进程,请使用 csanalyzer.ps1
PowerShell 脚本。 该脚本可检索对象的通用标识符(如 displayName 和 userPrincipalName 等)。 使用脚本:
- 将 PowerShell 脚本从 CSAnalyzer 部分复制到名为
csanalyzer.ps1
的文件。 - 打开 PowerShell 窗口并浏览到已在其中创建 PowerShell 脚本的文件夹。
- 运行:
.\csanalyzer.ps1 -xmltoimport %temp%\export.xml
。 - 现在已有名为 processedusers1.csv 的文件,可在 Microsoft Excel 中检查。 请注意,该文件提供从 DN 属性到通用标识符(如 displayName 和 userPrincipalName 等)的映射。 当前尚不包括即将要导出的实际属性更改。
切换活动服务器
可以在主动-被动高可用性设置中设置 Microsoft Entra Connect,主动服务器主动将对同步 AD 对象的更改推送到 Microsoft Entra ID,而被动服务器在需要接管时暂存这些更改。
注意
无法在主动-主动设置中设置 Microsoft Entra Connect。 必须采用主动-被动设置。 请确保只有 1 个 Microsoft Entra Connect 服务器主动同步更改。
有关在暂存模式下设置 Microsoft Entra Connect 同步服务器的详细信息,请参阅暂存模式
出于多种原因,你可能需要执行同步服务器的故障转移,例如升级 Microsoft Entra Connect 版本,或接收同步服务的运行状况服务未收到最新信息的警报。 在这些事件中,可以按照以下步骤尝试对同步服务器进行故障转移。
重要
如果不满足以下条件,将暂存服务器切换到活动模式可能会对同步产生严重影响。 作为预防措施,请在执行此操作之前,始终运行初始同步周期并验证挂起的导出。
先决条件
- 一个当前处于主动模式的 Microsoft Entra Connect 同步服务器
- 一台处于暂存模式下的 Microsoft Entra Connect Sync 服务器
- 暂存服务器已启用同步计划程序,并且最近已与 Microsoft Entra ID 同步
- 如果同步规则或同步范围内发生任何更新,请运行初始同步周期
- 确认 Microsoft Entra Connect 同步服务器已配置为防止意外删除
- 验证挂起的导出,并确认没有重大更新,并且此类更新符合预期
- 通过在 Microsoft Entra Connect Health 门户中检查服务器来确定是否更新了 Microsoft Entra Connect Health 代理
- 将当前活动服务器切换到暂存模式,然后将暂存服务器切换到活动模式
将当前主动同步服务器更改为暂存模式
我们需要确保在整个过程中的任何给定时间都只有一个同步服务器在同步更改。 如果当前主动同步服务器可访问,可以执行以下步骤将其更改为暂存模式。 如果无法访问,请确保服务器或 VM 不会通过关闭服务器或将其与出站连接隔离来意外地重新获得访问权限。
- 对于当前主动 Microsoft Entra Connect 服务器,请打开 Microsoft Entra Connect 向导并单击“配置暂存模式”,然后单击“下一步”:
- 需要使用混合标识管理员凭据登录 Microsoft Entra ID:
- 勾选暂存模式框,然后单击“下一步”:
- Microsoft Entra Connect 服务器将检查已安装的组件,然后在配置更改完成时提示是否要启动同步过程:
由于服务器处于暂存模式,因此不会将更改写入 Microsoft Entra ID,但会在其连接器空间保留对 AD 的任何更改,以便写入这些更改。 建议在暂存模式下将服务器的同步进程保持打开状态,因此如果它变为主动状态,就可很快接管并且不必进行大型同步来赶上范围内 Active Directory/Microsoft Entra 对象的当前状态。
选择启动同步进程并单击“配置”后,Microsoft Entra Connect 服务器将配置为“暂存模式”。 完成此操作后,将显示屏幕,提示确认已启用“暂存模式”。 可以单击“退出”完成。
你可以通过打开 Windows PowerShell、加载“ADSync”模块并使用以下命令验证 ADSync 计划程序配置来确认服务器已成功处于暂存模式:
Import-Module ADSync
Get-ADSyncScheduler
根据结果,验证“StagingModeEnabled”设置的值。 如果服务器已成功切换到分段模式,则此设置的值应为 True,如下例所示:
将当前暂存同步服务器更改为主动模式
此时,所有的 Microsoft Entra Connect 同步服务器都应处于暂存模式而不是导出更改。 现在可以将暂存同步服务器更改为主动模式并主动同步更改。
- 现在移动到最初处于暂存模式的 Microsoft Entra Connect 服务器并打开 Microsoft Entra Connect 向导。
单击“配置暂存模式”然后单击“下一步”:
向导底部的消息指示此服务器处于暂存模式。
- 登录到 Microsoft Entra ID,然后转到“暂存模式”屏幕。
取消勾选“暂存模式”框,然后单击“下一步”。
根据此页上的警告,请务必确保没有其他 Microsoft Entra Connect 服务器正在主动同步。
任何时候都应该只有一个主动 Microsoft Entra Connect 同步服务器。
- 出现启动同步进程的提示时,请勾选此框并单击“配置”:
- 该过程完成后,你应该会看到下面的确认屏幕,可以在其中单击“退出”以完成:
- 可以通过打开同步服务控制台并检查导出作业是否正在运行,来确认此进程是否在正常工作:
灾难恢复
实现设计的一部分是规划发生灾难失去同步服务器时如何应对。 有不同的模型可用,要使用哪一种模型取决于许多因素,包括:
- 停机期间无法对 Microsoft Entra ID 中的对象进行更改的容限度如何?
- 如果使用密码同步,用户是否接受他们在本地更改时必须在 Microsoft Entra ID 中使用旧密码?
- 是否对实时操作具有依赖性,例如密码写回?
根据这些问题的回答和组织的策略,实施下列其中一个策略:
- 根据需要重建。
- 具有备用的待机服务器(称为暂存模式)。
- 使用虚拟机
如果不使用内置的 SQL Express 数据库,则还应查看“SQL 高可用性”部分。
根据需要重建
必要时规划服务器重建为可行的策略。 通常,在几个小时内即可完成安装同步引擎以及执行初始导入和同步。 如果没有可用的备用服务器,则可以暂时使用域控制器托管同步引擎。
同步引擎服务器不存储有关对象的任何状态,因此可以根据 Active Directory 和 Microsoft Entra ID 中的数据重建数据库。 sourceAnchor 属性可用于联接来自本地和云的对象。 如果重新生成包含本地与云中现有对象的服务器,同步引擎的重新安装符合这些项目。 需要记录和保存的内容是对服务器进行的配置更改,例如筛选和同步规则。 在开始同步之前,必须重新应用这些自定义配置。
具有备用的待机服务器 - 暂存模式
如果环境更复杂,我们建议使用一个或多个待机服务器。 可以在安装过程中启用服务器的暂存模式。
有关详细信息,请参阅暂存模式。
使用虚拟机
常用的受支持方法是在虚拟机中运行同步引擎。 如果主机有问题,可将包含同步引擎服务器的映像迁移到另一个服务器。
SQL 高可用性
如果未使用 Microsoft Entra Connect 随附的 SQL Server Express,还应考虑 SQL Server 的高可用性。 支持的高可用性解决方案包括 SQL 群集和 AOA(Always On 可用性组)。 不支持的解决方案包括镜像。
Microsoft Entra Connect 版本 1.1.524.0 中添加了对 SQL AOA 的支持。 安装 Microsoft Entra Connect 之前,必须启用 SQL AOA。 在安装期间,Microsoft Entra Connect 会检测是否已为提供的 SQL 实例启用 SQL AOA。 如果启用了 SQL AOA,Microsoft Entra Connect 进一步指出如果 SQL AOA 配置为使用同步复制或异步复制。 当设置可用性组侦听器时,必须将 RegisterAllProvidersIP 属性设置为 0。 Microsoft Entra Connect 当前使用 SQL Native Client 连接到 SQL,并且 SQL Native Client 不支持使用 MultiSubNetFailover 属性。
附录 CSAnalyzer
有关如何使用此脚本的信息,请参阅验证部分。
Param(
[Parameter(Mandatory=$true, HelpMessage="Must be a file generated using csexport 'Name of Connector' export.xml /f:x)")]
[string]$xmltoimport="%temp%\exportedStage1a.xml",
[Parameter(Mandatory=$false, HelpMessage="Maximum number of users per output file")][int]$batchsize=1000,
[Parameter(Mandatory=$false, HelpMessage="Show console output")][bool]$showOutput=$false
)
#LINQ isn't loaded automatically, so force it
[Reflection.Assembly]::Load("System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") | Out-Null
[int]$count=1
[int]$outputfilecount=1
[array]$objOutputUsers=@()
#XML must be generated using "csexport "Name of Connector" export.xml /f:x"
write-host "Importing XML" -ForegroundColor Yellow
#XmlReader.Create won't properly resolve the file location,
#so expand and then resolve it
$resolvedXMLtoimport=Resolve-Path -Path ([Environment]::ExpandEnvironmentVariables($xmltoimport))
#use an XmlReader to deal with even large files
$result=$reader = [System.Xml.XmlReader]::Create($resolvedXMLtoimport)
$result=$reader.ReadToDescendant('cs-object')
if($result)
{
do
{
#create the object placeholder
#adding them up here means we can enforce consistency
$objOutputUser=New-Object psobject
Add-Member -InputObject $objOutputUser -MemberType NoteProperty -Name ID -Value ""
Add-Member -InputObject $objOutputUser -MemberType NoteProperty -Name Type -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name DN -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name operation -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name UPN -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name displayName -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name sourceAnchor -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name alias -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name primarySMTP -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name onPremisesSamAccountName -Value ""
Add-Member -inputobject $objOutputUser -MemberType NoteProperty -Name mail -Value ""
$user = [System.Xml.Linq.XElement]::ReadFrom($reader)
if ($showOutput) {Write-Host Found an exported object... -ForegroundColor Green}
#object id
$outID=$user.Attribute('id').Value
if ($showOutput) {Write-Host ID: $outID}
$objOutputUser.ID=$outID
#object type
$outType=$user.Attribute('object-type').Value
if ($showOutput) {Write-Host Type: $outType}
$objOutputUser.Type=$outType
#dn
$outDN= $user.Element('unapplied-export').Element('delta').Attribute('dn').Value
if ($showOutput) {Write-Host DN: $outDN}
$objOutputUser.DN=$outDN
#operation
$outOperation= $user.Element('unapplied-export').Element('delta').Attribute('operation').Value
if ($showOutput) {Write-Host Operation: $outOperation}
$objOutputUser.operation=$outOperation
#now that we have the basics, go get the details
foreach ($attr in $user.Element('unapplied-export-hologram').Element('entry').Elements("attr"))
{
$attrvalue=$attr.Attribute('name').Value
$internalvalue= $attr.Element('value').Value
switch ($attrvalue)
{
"userPrincipalName"
{
if ($showOutput) {Write-Host UPN: $internalvalue}
$objOutputUser.UPN=$internalvalue
}
"displayName"
{
if ($showOutput) {Write-Host displayName: $internalvalue}
$objOutputUser.displayName=$internalvalue
}
"sourceAnchor"
{
if ($showOutput) {Write-Host sourceAnchor: $internalvalue}
$objOutputUser.sourceAnchor=$internalvalue
}
"alias"
{
if ($showOutput) {Write-Host alias: $internalvalue}
$objOutputUser.alias=$internalvalue
}
"proxyAddresses"
{
if ($showOutput) {Write-Host primarySMTP: ($internalvalue -replace "SMTP:","")}
$objOutputUser.primarySMTP=$internalvalue -replace "SMTP:",""
}
}
}
$objOutputUsers += $objOutputUser
Write-Progress -activity "Processing ${xmltoimport} in batches of ${batchsize}" -status "Batch ${outputfilecount}: " -percentComplete (($objOutputUsers.Count / $batchsize) * 100)
#every so often, dump the processed users in case we blow up somewhere
if ($count % $batchsize -eq 0)
{
Write-Host Hit the maximum users processed without completion... -ForegroundColor Yellow
#export the collection of users as a CSV
Write-Host Writing processedusers${outputfilecount}.csv -ForegroundColor Yellow
$objOutputUsers | Export-Csv -path processedusers${outputfilecount}.csv -NoTypeInformation
#increment the output file counter
$outputfilecount+=1
#reset the collection and the user counter
$objOutputUsers = $null
$count=0
}
$count+=1
#need to bail out of the loop if no more users to process
if ($reader.NodeType -eq [System.Xml.XmlNodeType]::EndElement)
{
break
}
} while ($reader.Read)
#need to write out any users that didn't get picked up in a batch of 1000
#export the collection of users as CSV
Write-Host Writing processedusers${outputfilecount}.csv -ForegroundColor Yellow
$objOutputUsers | Export-Csv -path processedusers${outputfilecount}.csv -NoTypeInformation
}
else
{
Write-Host "Imported XML file is empty. No work to do." -ForegroundColor Red
}
后续步骤
概述主题