Introduction
Last week we covered the code that fellow Exchange MVP, Jaap Wesselius , wrote this great blog article about and we covered it’s breakdown. This week we will take the CSV file we created and use it to alter attributes in our account forest.
The CSV File
If you read the blog post from last week, or read Jaap’s post, and then performed the steps to gather the information into a CSV file, then you are in luck. In this blog post we will walk through how to take that file and use it in the Account Forest to migrate attributes from the Resource Forest as well as connect the user object in the Account Forest to the remote mailbox in Exchange Online. So what steps are needed to make this happen? Well we have an list of changes that need to be made:
- Enable the Remote Mailbox – providing a Remote Routing Address and Primary SMTP Address
- Set the ExchangeGUID attribute
- Add each email address
Preamble of the Script
By Preamble we are specifically looking at setting variables and such for the script run:
# Transcript file $CurrentPath = (Get-Item -Path ".\" -Verbose).FullName $Date = Get-Date -Format "MM.dd.yyyy-hh.mm-tt" Start-Transcript -Path "$CurrentPath\$Date-Set-UserProperties.txt" | Out-Null $ErrorLog = "$CurrentPath\$Date-ErrorLog.txt" $ChangeLog = "$CurrentPath\$Date-ChangeLog.txt"
In the above we set up three files:
Transcription: Logs all the text of the PowerShell session to a file.
Error Log: Keeps track of any error messages that may occur – for troubleshooting
Change Log: Keeps track of all successful changes – in case a change needs to be reverted.
Retrieving the CSV File
Here we use the Read-Host cmdlet to prompt the administrator for a CSV to use:
$CSVFile = Read-Host -Prompt 'Enter a CSV file to use' $CSV = Import-CSV $CSVFile
Odds and Ends
Before we get to the main script body, I like to set up a few things that are needed to make sure that we can perform all the tasks for one user in one loop of the script. The $Counter variable keeps track on the times that we process a line in the CSV file and 0 means it’s the first loop. When the $Counter variable is 0, we perform one task and if it is greater than 0, then we perform a different task. Also, because each user has multiple lines in the CSV, we need to keep track of when the mailbox changes (i.e. different line has a different user’s info) so we can begin again. In this section we set the initial $Counter to 0 and the $LastMailbox to an empty value:
# Set variables for the loop $LastMailbox = $Null $Counter = 0
Applying the Attributes
In this section we will start the processing of the CSV file with a Foreach loop and set some variables to be used on the next portion of the script
Foreach ($Line in $CSV) { $RRA = $Line.RemoteRoutingAddress $GUID = $Line.ExchangeGUID $Alias = $Line.Alias $PrimarySMTP = $Line.PrimarySMTPAddress $ADAccount = $Line.LinkedMasterAccount $Email = $Line.EmailAddresses
Next we check to see if the mailboxes have changed, which happens when the next line contains information for a different mailbox. This code will reset the $Counter variable to 0 if it is a new mailbox, otherwise the $Counter value stays the same.
# Reset Counter If ($LastMailbox -ne $Alias) { $Counter = 0 }
For this section we will make our changes, but not care if they fail, succeed or whatever. No error checking was added to this section. This was done for simplicity sake and will cover how to add logging next.
Task One
In this section, we enable the Remote Mailbox, which connects the user in the Account Forest with the Exchange Online Mailbox, then assign the Exchange GUID and finally add the email address listed in this line of the CSV.
If ($Counter -eq 0) { $UPN = (Get-User $ADAccount).UserPrincipalName Enable-RemoteMailbox -Identity $UPN -RemoteRoutingAddress $RRA -primarysmtpddress $PrimarySMTP Set-RemoteMailbox -Identity $UPN -ExchangeGUID $GUID Set-RemoteMailbox -Identity $UPN -EmailAddresses @{add=$Email} }
Task Two
In this section, if we are on a line other than the first for a mailbox, we add the email address from that line.
Else { Write-Host "Adding $Email email address to $UPN" Set-RemoteMailbox -Identity $UPN -EmailAddresses @{add=$Email} }
The loop is then closed off with this code which is done to increase the $Counter variable and set the $LastMailbox value so we can keep track of any changes between lines in the CSV file.
# Set variables for the next loop: $LastMailbox = $Alias $Counter++
At the very end of the script we also need to stop the Transcript, which is done like so:
Stop-Transcript
Adding Layers and Logging
Now, when all is right in the world, no errors will be experienced and no script troubleshooting will be needed … however, the world is not perfect and this is what we use the Try {} Catch{} coding for. Example of this is listed here:
Try { Enable-RemoteMailbox -Identity $UPN -RemoteRoutingAddress $RRA -primarysmtpddress $PrimarySMTP -ErrorAction STOP $Output = "$Date - Remote mailbox for $UPN was enabled - $RRA."| Out-File $ChangeLog -Append } Catch { $Output = "$Date - Failed to enable remote mailbox $UPN - $RRA" | Out-File $ErrorLog -Append $Output = "$Date - Error message - $_.Exception.Message" | Out-File $ErrorLog -Append }
Basically if all goes well, the success is logged to the ChangeLog file and if there is an error, the error is logged to the ErrorLog file. These can then later be reviewed for any issues or success.
Complete Script
To make it easier to understand, the entire script is listed below:
# Set variables for the loop $LastMailbox = $Null $Counter = 0 # Transcript file $CurrentPath = (Get-Item -Path ".\" -Verbose).FullName $Date = Get-Date -Format "MM.dd.yyyy-hh.mm-tt" Start-Transcript -Path "$CurrentPath\$Date-Set-UserProperties.txt" | Out-Null $ErrorLog = "$CurrentPath\$Date-ErrorLog.txt" $ChangeLog = "$CurrentPath\$Date-ChangeLog.txt" #CSV File $CSVFile = Read-Host -Prompt 'Enter a CSV file to use' $CSV = Import-CSV $CSVFile # Script main body: Foreach ($Line in $CSV) { $RRA = $Line.RemoteRoutingAddress $GUID = $Line.ExchangeGUID $Alias = $Line.Alias $PrimarySMTP = $Line.PrimarySMTPAddress $ADAccount = $Line.LinkedMasterAccount $Email = $Line.EmailAddresses # Reset Counter If ($LastMailbox -ne $Alias) { $Counter = 0 } # $Counter = 0 means the first loop for the user otherwise it's an addition loop, for email address processing. If ($Counter -eq 0) { # Get the UPN for the user, to make sure the correct object is used: $UPN = (Get-User $ADAccount).UserPrincipalName # Enable to mailbox connection between the Account domain user and the Office 365 mailbox Try { Enable-RemoteMailbox -Identity $UPN -RemoteRoutingAddress $RRA -primarysmtpddress $PrimarySMTP -ErrorAction STOP $Output = "$Date - Remote mailbox for $UPN was enabled - $RRA."| Out-File $ChangeLog -Append } Catch { $Output = "$Date - Failed to enable remote mailbox $UPN - $RRA" | Out-File $ErrorLog -Append $Output = "$Date - Error message - $_.Exception.Message" | Out-File $ErrorLog -Append } # Tag the user account with the Exchange GUID which is important for account matching Try { Set-RemoteMailbox -Identity $UPN -ExchangeGUID $GUID -ErrorAction STOP $Output = "$Date - Mailbox for $UPN was stamped with an Exchange GUID $GUID"| Out-File $ChangeLog -Append } Catch { $Output = "$Date - Failed to add Exchange GUID $GUID to mailbox $UPN" | Out-File $ErrorLog -Append $Output = "$Date - Error message - $_.Exception.Message" | Out-File $ErrorLog -Append } # Add all email addresses to the object to match what was on the resource domain Try { Set-RemoteMailbox -Identity $UPN -EmailAddresses @{add=$Email} -ErrorAction STOP $Output = "$Date - Mailbox for $UPN - added email address $Email "| Out-File $ChangeLog -Append } Catch { $Output = "$Date - Failed to add email address $Email to mailbox $UPN" | Out-File $ErrorLog -Append $Output = "$Date - Error message - $_.Exception.Message" | Out-File $ErrorLog -Append } } Else { Write-Host "Adding $Email email address to $UPN" Try { Set-RemoteMailbox -Identity $UPN -EmailAddresses @{add=$Email} -ErrorAction STOP $Output = "$Date - Mailbox for $UPN - added email address $Email "| Out-File $ChangeLog -Append } Catch { $Output = "$Date - Failed to add email address $Email to mailbox $UPN" | Out-File $ErrorLog -Append $Output = "$Date - Error message - $_.Exception.Message" | Out-File $ErrorLog -Append } } # Set variables for the next loop: $LastMailbox = $Alias $Counter++ } Stop-Transcript
Conclusion
In this blog post we covered how to use PowerShell to take attributes from Resource Forest mailboxes and apply them to user objects in the Account Forest. This script is provided as is and should be tested before putting into production.
————————————————————————————————–
See previous Quick PowerShell Posts of the Week [ HERE ]
———————————————————————————————————–
Comments? Questions?
Feel free to leave your Comments below! Learn to more efficiently utilize PowerShell to manage Exchange Server, Exchange Online, Microsoft Defender for Office or Microsoft Purview Compliance portals by picking up frequently updated eBooks: