將 Exchange 2003 信箱轉換為擁有郵件功能的使用者

完成分段移轉後,請將信箱轉換為擁有郵件功能的使用者,讓信箱能夠自動連線到雲端信箱。

為何將信箱轉換為擁有郵件功能的使用者?

如果您已完成 Exchange 階段移轉,將貴組織的 Exchange 2003 內部部署信箱移轉到 Office 365,而且您想要使用 Active Directory 從您的內部部署組織管理雲端式使用者,則應將內部部署信箱轉換為擁有郵件功能的使用者 (MEU)。

本文包含可從雲端式信箱收集資訊的 Windows PowerShell 指令碼,以及可執行以將 Exchange 2003 信箱轉換為 MEU 的 Visual Basic (VB) 指令碼。當您執行此指令碼時,會將雲端式信箱的 Proxy 位址複製到位於 Active Directory 內的 MEU。此外,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 Bsic 指令碼會將內部部署 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 位址

    • 雲端信箱的其他 Proxy 位址

    • LegacyExchangeDN

  • 會將收集的屬性儲存到一個名為 Cloud.csv 的 CSV 檔案。

Exchange2003MBtoMEU.vbs

這是您在內部部署 Exchange 2003 組織中執行的 VB 指令碼,可將信箱轉換為 MEU。它會使用 ExportO365UserInfo 指令碼輸出的 Cloud.csv 檔案。

當您執行 Exchange2003MBtoMEU.vbs 指令碼時,它會針對輸入 CSV 檔案中列出的每個信箱執行下列操作:

  • 會從輸入 CSV 檔案及從內部部署信箱收集資訊。

  • 從內部部署和雲端信箱建立 Proxy 位址清單,以新增到 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 支援專員連絡以深入了解您的意見。

×