将 Exchange 2003 邮箱转换为启用邮件的用户

完成暂存迁移后,将邮箱转换为启用邮件的用户,以便邮箱自动连接云邮箱。

为什么要将邮箱转换为启用邮件的用户?

如果将组织的 Exchange 2003 本地邮箱迁移到 Office 365 的暂存 Exchange 迁移已完成,并且想要利用 Active Directory 从本地组织管理基于云的用户,应将本地邮箱转换为启用邮件的用户 (MEU)。

本文包含 Windows PowerShell 脚本,该脚本收集了来自基于云的邮箱的信息,还包含 Visual Basic (VB) 脚本,可运行该脚本将 Exchange 2003 邮箱转换为 MEU。运行此脚本时,来自基于云的邮箱的代理地址会复制到 MEU,MEU 驻留在 Active Directory 中。此外,MEU 的属性启用 Microsoft Online Services 目录同步工具 (DirSync),以匹配 MEU 及其相应的云邮箱

针对迁移批处理,建议将本地邮箱转换为 MEU。暂存 Exchange 迁移批处理完成、确定已成功迁移批处理中的所有邮箱,且邮箱项初始同步到云完成后,将迁移批处理中的邮箱转换为 MEU。

从云邮箱收集数据的 PowerShell 脚本

可以使用以下脚本收集基于云的邮箱信息,并将 Exchange 2007 邮箱转换为 MEU。

以下脚本收集云邮箱的信息,并将其保存为 CSV 文件。先运行该脚本。

将以下脚本复制到 .txt 文件,然后保存该文件,并将其另存为 ExportO365UserInfo.ps1。

Param($migrationCSVFileName = "migration.csv")
function O365Logon
{
#Check for current open O365 sessions and allow the admin to either use the existing session or create a new one
$session = Get-PSSession | ?{$_.ConfigurationName -eq 'Microsoft.Exchange'}
if($session -ne $null)
{
$a = Read-Host "An open session to Office 365 already exists. Do you want to use this session? Enter y to use the open session, anything else to close and open a fresh session."
if($a.ToLower() -eq 'y')
{
Write-Host "Using existing Office 365 Powershell Session." -ForeGroundColor Green
return
}
$session | Remove-PSSession
}
Write-Host "Please enter your Office 365 credentials" -ForeGroundColor Green
$cred = Get-Credential
$s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $cred -Authentication Basic -AllowRedirection
$importresults = Import-PSSession $s
}

function Main
{

#Verify the migration CSV file exists
if(!(Test-Path $migrationCSVFileName))
{
Write-Host "File $migrationCSVFileName does not exist." -ForegroundColor Red
Exit
}

#Import user list from migration.csv file
$MigrationCSV = Import-Csv $migrationCSVFileName

#Get mailbox list based on email addresses from CSV file
$MailBoxList = $MigrationCSV | %{$_.EmailAddress} | Get-Mailbox
$Users = @()

#Get LegacyDN, Tenant, and On-Premise Email addresses for the users
foreach($user in $MailBoxList)
{
$UserInfo = New-Object System.Object

$CloudEmailAddress = $user.EmailAddresses | ?{($_ -match 'onmicrosoft') -and ($_ -cmatch 'smtp:')}
if ($CloudEmailAddress.Count -gt 1)
{
$CloudEmailAddress = $CloudEmailAddress[0].ToString().ToLower().Replace('smtp:', '')
Write-Host "$user returned more than one cloud email address. Using $CloudEmailAddress" -ForegroundColor Yellow
}
else
{
$CloudEmailAddress = $CloudEmailAddress.ToString().ToLower().Replace('smtp:', '')
}

$UserInfo | Add-Member -Type NoteProperty -Name LegacyExchangeDN -Value $user.LegacyExchangeDN
$UserInfo | Add-Member -Type NoteProperty -Name CloudEmailAddress -Value $CloudEmailAddress
$UserInfo | Add-Member -Type NoteProperty -Name OnPremiseEmailAddress -Value $user.PrimarySMTPAddress.ToString()

$Users += $UserInfo
}

#Check for existing csv file and overwrite if needed
if(Test-Path ".\cloud.csv")
{
$delete = Read-Host "The file cloud.csv already exists in the current directory. Do you want to delete it? Enter y to delete, anything else to exit this script."
if($delete.ToString().ToLower() -eq 'y')
{
Write-Host "Deleting existing cloud.csv file" -ForeGroundColor Red
Remove-Item ".\cloud.csv"
}
else
{
Write-Host "Will NOT delete current cloud.csv file. Exiting script." -ForeGroundColor Green
Exit
}
}
$Users | Export-CSV -Path ".\cloud.csv" -notype
(Get-Content ".\cloud.csv") | %{$_ -replace '"', ''} | Set-Content ".\cloud.csv" -Encoding Unicode
Write-Host "CSV File Successfully Exported to cloud.csv" -ForeGroundColor Green

}

O365Logon
Main

以下 Visual Basic 脚本将本地 Exchange 2003 邮箱转换为 MEU。运行脚本收集云邮箱中的信息后,请运行该脚本。

将以下脚本复制到 .txt 文件,然后将该文件另存为 Exchange2003MBtoMEU.vbs。

'Globals/Constants
Const ADS_PROPERTY_APPEND = 3

Dim UserDN
Dim remoteSMTPAddress
Dim remoteLegacyDN
Dim domainController
Dim csvMode
csvMode = FALSE
Dim csvFileName
Dim lastADLookupFailed


Class UserInfo
public OnPremiseEmailAddress
public CloudEmailAddress
public CloudLegacyDN
public LegacyDN
public ProxyAddresses
public Mail
public MailboxGUID
public DistinguishedName

Public Sub Class_Initialize()
Set ProxyAddresses = CreateObject("Scripting.Dictionary")
End Sub
End Class

'Command Line Parameters
If WScript.Arguments.Count = 0 Then
'No parameters passed
WScript.Echo("No parameters were passed.")
ShowHelp()
ElseIf StrComp(WScript.Arguments(0), "-c", vbTextCompare) = 0 And WScript.Arguments.Count = 2 Then
WScript.Echo("Missing DC Name.")
ShowHelp()
ElseIf StrComp(WScript.Arguments(0), "-c", vbTextCompare) = 0 Then
'CSV Mode
csvFileName = WScript.Arguments(1)
domainController = WScript.Arguments(2)
csvMode = TRUE
WScript.Echo("CSV mode detected. Filename: " & WScript.Arguments(1) & vbCrLf)
ElseIf wscript.Arguments.Count <> 4 Then
'Invalid Arguments
WScript.Echo WScript.Arguments.Count
Call ShowHelp()
Else
'Manual Mode
UserDN = wscript.Arguments(0)
remoteSMTPAddress = wscript.Arguments(1)
remoteLegacyDN = wscript.Arguments(2)
domainController = wscript.Arguments(3)
End If

Main()

'Main entry point
Sub Main

'Check for CSV Mode
If csvMode = TRUE Then
UserInfoArray = GetUserInfoFromCSVFile()
Else
WScript.Echo "Manual Mode Detected" & vbCrLf
Set info = New UserInfo
info.CloudEmailAddress = remoteSMTPAddress
info.DistinguishedName = UserDN
info.CloudLegacyDN = remoteLegacyDN
ProcessSingleUser(info)
End If

End Sub

'Process a single user (manual mode)
Sub ProcessSingleUser(ByRef UserInfo)

userADSIPath = "LDAP://" & domainController & "/" & UserInfo.DistinguishedName
WScript.Echo "Processing user " & userADSIPath
Set MyUser = GetObject(userADSIPath)
proxyCounter = 1
For Each address in MyUser.Get("proxyAddresses")
UserInfo.ProxyAddresses.Add proxyCounter, address
proxyCounter = proxyCounter + 1
Next
UserInfo.OnPremiseEmailAddress = GetPrimarySMTPAddress(UserInfo.ProxyAddresses)
UserInfo.Mail = MyUser.Get("mail")
UserInfo.MailboxGUID = MyUser.Get("msExchMailboxGUID")
UserInfo.LegacyDN = MyUser.Get("legacyExchangeDN")
ProcessMailbox(UserInfo)

End Sub

'Populate user info from CSV data
Function GetUserInfoFromCSVFile()

CSVInfo = ReadCSVFile()
For i = 0 To (UBound(CSVInfo)-1)
lastADLookupFailed = false
Set info = New UserInfo
info.CloudLegacyDN = Split(CSVInfo(i+1), ",")(0)
info.CloudEmailAddress = Split(CSVInfo(i+1), ",")(1)
info.OnPremiseEmailAddress = Split(CSVInfo(i+1), ",")(2)
WScript.Echo "Processing user " & info.OnPremiseEmailAddress
WScript.Echo "Calling LookupADInformationFromSMTPAddress"
LookupADInformationFromSMTPAddress(info)
If lastADLookupFailed = false Then
WScript.Echo "Calling ProcessMailbox"
ProcessMailbox(info)
End If
set info = nothing
Next

End Function

'Populate user info from AD
Sub LookupADInformationFromSMTPAddress(ByRef info)

'Lookup the rest of the info in AD using the SMTP address
Set objRootDSE = GetObject("LDAP://RootDSE")
strDomain = objRootDSE.Get("DefaultNamingContext")
Set objRootDSE = nothing
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand = CreateObject("ADODB.Command")
BaseDN = "<LDAP://" & domainController & "/" & strDomain & ">"
adFilter = "(&(proxyAddresses=SMTP:" & info.OnPremiseEmailAddress & "))"
Attributes = "distinguishedName,msExchMailboxGUID,mail,proxyAddresses,legacyExchangeDN"
Query = BaseDN & ";" & adFilter & ";" & Attributes & ";subtree"
objCommand.CommandText = Query
Set objCommand.ActiveConnection = objConnection
On Error Resume Next
Set objRecordSet = objCommand.Execute

'Handle any errors that result from the query
If Err.Number <> 0 Then
WScript.Echo "Error encountered on query " & Query & ". Skipping user."
lastADLookupFailed = true
return
End If

'Handle zero or ambiguous search results
If objRecordSet.RecordCount = 0 Then
WScript.Echo "No users found for address " & info.OnPremiseEmailAddress
lastADLookupFailed = true
return
ElseIf objRecordSet.RecordCount > 1 Then
WScript.Echo "Ambiguous search results for email address " & info.OnPremiseEmailAddress
lastADLookupFailed = true
return
ElseIf Not objRecordSet.EOF Then
info.LegacyDN = objRecordSet.Fields("legacyExchangeDN").Value
info.Mail = objRecordSet.Fields("mail").Value
info.MailboxGUID = objRecordSet.Fields("msExchMailboxGUID").Value
proxyCounter = 1
For Each address in objRecordSet.Fields("proxyAddresses").Value
info.ProxyAddresses.Add proxyCounter, address
proxyCounter = proxyCounter + 1
Next
info.DistinguishedName = objRecordSet.Fields("distinguishedName").Value
objRecordSet.MoveNext
End If

objConnection = nothing
objCommand = nothing
objRecordSet = nothing
On Error Goto 0

End Sub

'Populate data from the CSV file
Function ReadCSVFile()

'Open file
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFS.OpenTextFile(csvFileName, 1, false, -1)

'Loop through each line, putting each line of the CSV file into an array to be returned to the caller
counter = 0
Dim CSVArray()
Do While NOT objTextFile.AtEndOfStream
ReDim Preserve CSVArray(counter)
CSVArray(counter) = objTextFile.ReadLine
counter = counter + 1
Loop

'Close and return
objTextFile.Close
Set objTextFile = nothing
Set objFS = nothing
ReadCSVFile = CSVArray

End Function

'Process the migration
Sub ProcessMailbox(User)

'Get user properties
userADSIPath = "LDAP://" & domainController & "/" & User.DistinguishedName
Set MyUser = GetObject(userADSIPath)

'Add x.500 address to list of existing proxies
existingLegDnFound = FALSE
newLegDnFound = FALSE

'Loop through each address in User.ProxyAddresses
For i = 1 To User.ProxyAddresses.Count
If StrComp(address, "x500:" & User.LegacyDN, vbTextCompare) = 0 Then
WScript.Echo "x500 proxy " & User.LegacyDN & " already exists"
existingLegDNFound = true
End If
If StrComp(address, "x500:" & User.CloudLegacyDN, vbTextCompare) = 0 Then
WScript.Echo "x500 proxy " & User.CloudLegacyDN & " already exists"
newLegDnFound = true
End If
Next

'Add existing leg DN to proxy list
If existingLegDnFound = FALSE Then
WScript.Echo "Adding existing legacy DN " & User.LegacyDN & " to proxy addresses"
User.ProxyAddresses.Add (User.ProxyAddresses.Count+1),("x500:" & User.LegacyDN)
End If

'Add new leg DN to proxy list
If newLegDnFound = FALSE Then
'Add new leg DN to proxy addresses
WScript.Echo "Adding new legacy DN " & User.CloudLegacyDN & " to existing proxy addresses"
User.ProxyAddresses.Add (User.ProxyAddresses.Count+1),("x500:" & User.CloudLegacyDN)
End If

'Dump out new list of addresses
WScript.Echo "Original proxy addresses updated count: " & User.ProxyAddresses.Count
For i = 1 to User.ProxyAddresses.Count
WScript.Echo " proxyAddress " & i & ": " & User.ProxyAddresses(i)
Next

'Delete the Mailbox
WScript.Echo "Opening " & userADSIPath & " as CDOEXM::IMailboxStore object"
Set Mailbox = MyUser
Wscript.Echo "Deleting Mailbox"
On Error Resume Next
Mailbox.DeleteMailbox

'Handle any errors deleting the mailbox
If Err.Number <> 0 Then
WScript.Echo "Error " & Err.number & ". Skipping User." & vbCrLf & "Description: " & Err.Description & vbCrLf
Exit Sub
End If
On Error Goto 0

'Save and continue
WScript.Echo "Saving Changes"
MyUser.SetInfo
WScript.Echo "Refeshing ADSI Cache"
MyUser.GetInfo
Set Mailbox = nothing

'Mail Enable the User
WScript.Echo "Opening " & userADSIPath & " as CDOEXM::IMailRecipient"
Set MailUser = MyUser
WScript.Echo "Mail Enabling user using targetAddress " & User.CloudEmailAddress
MailUser.MailEnable User.CloudEmailAddress
WScript.Echo "Disabling Recipient Update Service for user"
MyUser.PutEx ADS_PROPERTY_APPEND, "msExchPoliciesExcluded", Array("{26491CFC-9E50-4857-861B-0CB8DF22B5D7}")
WScript.Echo "Saving Changes"
MyUser.SetInfo
WScript.Echo "Refreshing ADSI Cache"
MyUser.GetInfo

'Add Legacy DN back on to the user
WScript.Echo "Writing legacyExchangeDN as " & User.LegacyDN
MyUser.Put "legacyExchangeDN", User.LegacyDN

'Add old proxies list back on to the MEU
WScript.Echo "Writing proxyAddresses back to the user"
For j=1 To User.ProxyAddresses.Count
MyUser.PutEx ADS_PROPERTY_APPEND, "proxyAddresses", Array(User.ProxyAddresses(j))
MyUser.SetInfo
MyUser.GetInfo
Next

'Add mail attribute back on to the MEU
WScript.Echo "Writing mail attribute as " & User.Mail
MyUser.Put "mail", User.Mail

'Add msExchMailboxGUID back on to the MEU
WScript.Echo "Converting mailbox GUID to writable format"
Dim mbxGUIDByteArray
Call ConvertHexStringToByteArray(OctetToHexString(User.MailboxGUID), mbxGUIDByteArray)
WScript.Echo "Writing property msExchMailboxGUID to user object with value " & OctetToHexString(User.MailboxGUID)
MyUser.Put "msExchMailboxGUID", mbxGUIDByteArray

WScript.Echo "Saving Changes"
MyUser.SetInfo
WScript.Echo "Migration Complete!" & vbCrLf

End Sub

'Returns the primary SMTP address of a user
Function GetPrimarySMTPAddress(Addresses)
For Each address in Addresses
If Left(address, 4) = "SMTP" Then GetPrimarySMTPAddress = address
Next
End Function

'Converts Hex string to byte array for writing to AD
Sub ConvertHexStringToByteArray(ByVal strHexString, ByRef pByteArray)

Set FSO = CreateObject("Scripting.FileSystemObject")
Set Stream = CreateObject("ADODB.Stream")

Temp = FSO.GetTempName()
Set TS = FSO.CreateTextFile(Temp)

For i = 1 To (Len (strHexString) -1) Step 2
TS.Write Chr("&h" & Mid (strHexString, i, 2))
Next

TS.Close

Stream.Type = 1
Stream.Open
Stream.LoadFromFile Temp

pByteArray = Stream.Read

Stream.Close
FSO.DeleteFile Temp

Set Stream = nothing
Set FSO = Nothing

End Sub

'Converts raw bytes from AD GUID to readable string
Function OctetToHexString (arrbytOctet)

OctetToHexStr = ""
For k = 1 To Lenb (arrbytOctet)
OctetToHexString = OctetToHexString & Right("0" & Hex(Ascb(Midb(arrbytOctet, k, 1))), 2)
Next

End Function

Sub ShowHelp()

WScript.Echo("This script runs in two modes, CSV Mode and Manual Mode." & vbCrLf & "CSV Mode allows you to specify a CSV file from which to pull user names." & vbCrLf& "Manual mode allows you to run the script against a single user.")
WSCript.Echo("Both modes require you to specify the name of a DC to use in the local domain." & vbCrLf & "To run the script in CSV Mode, use the following syntax:")
WScript.Echo(" cscript Exchange2003MBtoMEU.vbs -c x:\csv\csvfilename.csv dc.domain.com")
WScript.Echo("To run the script in Manual Mode, you must specify the users AD Distinguished Name, Remote SMTP Address, Remote Legacy Exchange DN, and Domain Controller Name.")
WSCript.Echo(" cscript Exchange2003MBtoMEU.vbs " & chr(34) & "CN=UserName,CN=Users,DC=domain,DC=com" & chr(34) & " " & chr(34) & "user@cloudaddress.com" & chr(34) & " " & chr(34) & "/o=Cloud Org/ou=Cloud Site/ou=Recipients/cn=CloudUser" &
chr(34) & " dc.domain.com")
WScript.Quit

End Sub

脚本有什么作用?

ExportO365UserInfo.ps1

这是在基于云的组织中运行的 Windows PowerShell 脚本,用于收集在暂存 Exchange 迁移过程中迁移的云邮箱信息。它使用 CSV 文件来设定用户批的范围。建议使用与迁移用户批相同的迁移 CSV 文件

运行 ExportO365UserInfo 脚本时:

  • 对于输入 CSV 文件中列出的用户,会从云邮箱收集下列属性:

    • 主 SMTP 地址

    • 相应本地邮箱的主 SMTP 地址

    • 云邮箱的其他代理地址

    • LegacyExchangeDN

  • 收集的属性被保存到名为 Cloud.csv 的 CSV 文件。

Exchange2003MBtoMEU.vbs

这是在本地 Exchange 2003 组织中运行的 VB 脚本,以将邮箱转换为 MEU。它使用由 ExportO365UserInfo 脚本输出的 Cloud.csv 文件。

运行 Exchange2003MBtoMEU.vbs 脚本时,它将为输入 CSV 文件中列出的每个邮箱执行以下操作:

  • 从输入 CSV 文件和本地邮箱收集信息。

  • 从本地和云邮箱创建代理地址列表,以添加到 MEU。

  • 删除本地邮箱。

  • 创建 MEU 并填充下列属性:

    • legacyExchangeDN -来自本地邮箱的值。

    • mail - 云邮箱的主 SMTP。

    • msExchMailboxGuid -来自本地邮箱的值。

    • proxyAddresses -来自本地邮箱和云邮箱的值。

    • targetAddress -从本地邮箱读取;该值是云邮箱的主 SMTP。

      重要: 若要启用从 Office 365 到 Exchange 2003 的分离,需要将 MEU 上的 msExchMailboxGuid 值替换为基于云的邮箱中的 Guid。若要获取云组织中邮箱的 Guid 并将其保存到 CSV 文件,请运行以下 PowerShell 命令:

      Get-Mailbox | Select PrimarySmtpAddress, Guid | Export-csv -Path .\guid.csv

      此命令将所有云邮箱的主 SMTP 地址和 Guid 提取到 guid.csv 文件中,然后将该文件保存到当前目录。

可以在手动模式下运行 Exchange2003MBtoMEU.vbs 脚本一次转换一个邮箱,而不是使用输入 CSV 文件成批转换邮箱。若要执行此操作,需要提供以下输入参数:

  • 本地邮箱的可分辨名称 (DN)。

  • 云邮箱的主 SMTP 地址。

  • 云邮箱的 Exchange 旧版 DN。

  • Exchange 2003 组织中的域控制器名称。

将本地邮箱转换为 MEU 的步骤

  1. 在云组织中运行 ExportO365UserInfo。将迁移批处理的 CSV 文件作为输入文件使用。该脚本将创建名为 Cloud.csv 的 CSV 文件。

    .\ExportO365UserInfo.ps1 <CSV input file>

    例如:

    .\ExportO365UserInfo.ps1 .\MigrationBatch1.csv

    此示例假定脚本和输入 CSV 文件位于同一目录中。

  2. 将 Exchange2003MBtoMEU.vbs 和 Cloud.csv 复制到本地组织的同一目录中。

  3. 在本地组织中运行以下命令:

    cscript Exchange2003MBtoMEU.vbs –c .\Cloud.csv <FQDN of on-premises domain controller>

    例如:

    cscript Exchange2003MBtoMEU.vbs –c .\Cloud.csv DC1.contoso.com

    若要在手动模式下运行该脚本,请输入以下命令。在每个值之间使用空格。

    cscript Exchange2003MBtoMEU.vbs “<DN of on-premises mailbox>” “
    <Primary SMTP of cloud mailbox>” “<ExchangeLegacyDN of cloud mailbox>”
    <FQDN of on-premises domain controller>

    例如:

    cscript Exchange2003MBtoMEU.vbs “CN=Ann Beebe,
    CN=Users,DC=contoso,DC=com”
    “annb@contoso.onmicrosoft.com” “/o=First Organization/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=d808d014cec5411ea6de1f70cc116e7b-annb” DC1.contoso.com
  4. 验证是否已创建新的 MEU。在 Active Directory 用户和计算机中,请执行下列操作:

    1. 单击“操作”>“查找”。

    2. 单击“Exchange 选项卡”。

    3. 选择“仅显示 Exchange 收件人”,然后选择“具有外部电子邮件地址的用户”。

    4. 单击“立即查找”。

    搜索结果”下列出已转换为 MEU 的邮箱。

  5. 使用 Active Directory 用户和计算机、ADSI 编辑器或 Ldp.exe 验证以下 MEU 属性是否填充了正确的信息。

    • legacyExchangeDN

    • mail

    • msExchMailboxGuid*

    • proxyAddresses

    • targetAddress

    * 如上文所述,Exchange2003MBtoMEU.vbs 脚本保留来自本地邮箱的 msExchMailboxGuid 值。若要启用从 Office 365 到 Exchange 2003 的分离,需要将 MEU 上的 msExchMailboxGuid 属性值替换为基于云的邮箱中的 Guid。

扩展你的技能
了解培训
抢先获得新功能
加入 Office 预览体验计划

此信息是否有帮助?

谢谢您的反馈!

谢谢你的反馈! 可能需要转接到 Office 支持专员。

×