Time for an Update
A Microsoft 365 Tenant-to-Tenant migration can be a daunting task. As more apps and features become available, the list of things to keep track of when planning a migration grows. I strongly believe that the key to any project – particularly migration projects – lies in strong preparation and planning.
Some time ago, I published a PowerShell script to help admins prepare for Microsoft 365 Tenant to Tenant Migrations. The script gathers key data from a Microsoft 365 tenant to generate an Excel report containing key data for consideration during the migration planning process. The feedback on this script was very positive and many people had their own suggestions of items that should be included.
The feedback provided through GitHub or within the article comments has highlighted some areas to include in the assessment script. Taking this on board, I have now published Version 2 of the Tenant-to-Tenant Migration Assessment on GitHub.
What’s New?
While the fundamentals of the script haven’t changed, there are some key improvements and additions to be aware of:
- A new Power BI template that can be used to summarize core areas.
- The entire script has been updated to use the Microsoft Graph PowerShell SDK, allowing for better performance and scalability.
- Addition of the following optional areas in the output:
- SharePoint Document Libraries
- SharePoint Lists
- Planner Plans
- Addition of the user’s directory sync status in the output.
Prepare the Environment
Preparing and running the script is like the process for Version 1 of the Tenant Assessment. The files for the assessment are available from GitHub here. To prepare to run the script, download all files to the folder C:\TenantAssessment on a local machine. The following files are used:
- Perform-TenantAssessment.ps1 – This PowerShell script runs the assessment and generates the output file.
- Prepare-TenantAssessment.ps1 – This PowerShell script creates the app registration in the Entra tenant and generates a self-signed certificate for authentication.
- TenantAssessment-Report.pbit – This Power BI template imports data from the output file and visualizes key data.
- TenantAssessment-Template.xlsx – This is the Excel template used to create the output file.
To prepare the tenant and generate the authentication certificate, run the script Prepare-TenantAssessment.ps1, as shown in Figure 1.
The script performs the following tasks to prepare the environment for the assessment:
- Authenticates to the Microsoft Graph using the PowerShell SDK (prompting the user for credentials).
- Creates a new app registration with the permissions shown in Figure 2 below.
- Adds the app service principal to the “Global Reader” and “Exchange Administrator” roles. If the roles are not activated yet, the script will activate them.
- Generate a new self-signed certificate and store it in the user’s certificate store on the workstation
- Upload the certificate to the app registration for use when authenticating.
- Outputs the Tenant ID, Client ID, and Certificate Thumbprint to the screen.
- Opens the application consent page in a browser to allow consent for the application permissions (as per Figure 2). Alternatively, the permissions can be consented from the app registration page of the Entra admin center. This consent must be granted by a Global Administrator account.
It’s important to understand that this app requires a high level of permissions, a level that attackers would love to gain to enumerate data in the tenant. The app registration should be treated as a highly privileged account and protected with Conditional Access and/or deleted after you have run the assessment. The high level of permissions is required to gather the data butit it shouldn’t be left in place and unprotected.
Running the Assessment Script
As with the previous version of the script, version 2 requires the “TenantID”, “ClientID” and “CertificateThumbprint” parameters. These values are displayed as the output of the preparation script shown above in Figure 1. There are also several optional parameters which will gather additional information:
- IncludeGroupMembership – This parameter includes a report of the members of each group.
- IncludeMailboxPermissions – This parameter includes a report of all mailbox permission assignments.
- IncludeDocumentLibraries – This parameter includes a report of all Document Libraries in the SharePoint environment.*
- IncludeLists – This parameter includes a report of all lists in the SharePoint environment (Excluding Document Libraries).
- IncludePlans – This parameter includes a report of all Planner plans in the tenant.
*Note, for non-English tenants, the filters in the code need to be updated to reflect the name of the “Documents” library in your tenant
The script uses only these PowerShell modules:
- Microsoft.Graph to perform the data gathering
- ImportExcel to create the output file
- ExchangeOnlineManagement to connect to Exchange Online to get information that is not exposed via the Graph API
The example command shown in Figure 3 runs the script with all optional parameters enabled and the Client ID, Tenant ID, and Certificate Thumbprint passed as variables as shown in Figure 3:
.\Perform-TenantAssessment.ps1 -clientId $clientid -tenantId $tenantID -certificateThumbprint $Thumbprint -IncludePlans -IncludeGroupMembership -IncludeMailboxPermissions -IncludeDocumentLibraries -IncludeLists
Note: Adding all optional parameters can increase the time required to run the script significantly, particularly in larger environments. Progress is displayed throughout to allow the administrator to know what’s happening.
When the script finishes, it generates a report in the folder C:\TenantAssessment named TenantAssessment.xlsx. Many of the tabs in the report are similar to the output from Version 1 of the assessment, so I won’t repeat them here. The new tabs generated by using the optional parameters are:
- Mailbox Permissions: This tab lists each assigned mailbox permission in Exchange Online.
- Group Membership: This tab lists every group membership present in Microsoft Entra ID.
- Document Libraries: This tab lists every Document Library present in SharePoint Online.
- Lists: This tab lists every SharePoint list (excluding Document Libraries) present in SharePoint Online.
- Planner Plans: This tab lists every Planner plan present in Microsoft 365 Groups.
Using the Power BI Template
With the output file generated, opening the Power BI Template “TenantAssessment-Report.pbit” will connect to the output file (located in C:\TenantAssessment) and import the data. After a few seconds, the report will load and present four pages: “User Overview”, “Exchange Overview”, “SharePoint Overview” and “Teams Overview”.
User Overview Page
The User Overview page in the Power BI report displays high-level statistics about the user accounts in the tenant. From this page, it’s easy to see data sizes for each component of a user account and see how they relate to each other as seen in Figure 4.
Each report page also contains two buttons on the left to filter results to only items which have the “migrate” column in the report set to “TRUE”. By default, all items have migrate set to “TRUE” but as you work through the migration plan, any objects not being migrated can be set to “FALSE” and they will be excluded from this view by clicking the “Show Migrating” button.
Exchange Overview
The Exchange Overview page (Figure 5) shows the details of the Exchange-related objects in the assessment such as counts and sizes of each mailbox type. The sliders at the top of the page allow for quickly identifying mailboxes of each type by size, for example, locating particularly large mailboxes that may take more time to synchronize data.
SharePoint Overview
The SharePoint Overview page (Figure 6) shows the data sizes within SharePoint (not including SharePoint sites linked to Teams), and the associated site types and activity. It also provides details on the 10 largest OneDrive and SharePoint sites and the most active sites. This information is useful when targeting priority areas for the business during a migration.
Teams Overview
Finally, the Teams Overview page (Figure 7) shows the details of Teams data sizes, counts of private and shared channels, and lists the largest Teams, Teams with most private channels and Teams with most Shared channels. Private and Shared channels require extra consideration during a migration, so this information supports planning for migration and estimating timeframes of data transfers.
Summary
When I created the initial tenant assessment script, I included what was (at the time) the most important aspects of a tenant-to-tenant migration for Microsoft 365. Extending the assessment out to these additional areas will help when it comes to planning migrations and the Power BI template allows for a summarized view of the key areas that impact migration planning.
One consistent piece of feedback I received in the previous version was that this information isn’t just useful in a migration context. Sometimes admins just need to get a view of what is in their tenant and the information provided can absolutely help in that scenario too.
As with the previous version, the feedback from the community is key to determining what version 3 might look like. I encourage people to share what they have found useful and maybe even add and share some features of their own through GitHub. Having a solid assessment is the first step to success in a migration project, and hopefully, this tool will help people to prepare and minimize late nights and weekends trying to get everything working in the new environment.
This constantly gets stuck on Task 9 downloading App info.
Hi,
Trying to run .\Prepare-TenanatAssessment.ps1 and getting following error; any pointers why it must be happening?
Thank you!
*************************************
PS C:\TenantAssessment> .\Prepare-TenantAssessment.ps1
Provisioning Entra App Registration for Tenant Migration Assessment Tool
get-mgcontext : The term ‘get-mgcontext’ is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At C:\TenantAssessment\Prepare-TenantAssessment.ps1:73 char:12
+ $Context = get-mgcontext
+ ~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (get-mgcontext:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Error connecting to Microsoft Graph:
The term ‘Connect-MgGraph’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling o
f the name, or if a path was included, verify that the path is correct and try again.
Try again…
Error connecting to Microsoft Graph:
The term ‘Connect-MgGraph’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling o
f the name, or if a path was included, verify that the path is correct and try again.
Try again…
Error connecting to Microsoft Graph:
The term ‘Connect-MgGraph’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling o
f the name, or if a path was included, verify that the path is correct and try again.
Try again…
Error connecting to Microsoft Graph:
The term ‘Connect-MgGraph’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling o
f the name, or if a path was included, verify that the path is correct and try again.
Try again…
*****************************
If Connect-MgGraph isn’t recognized as a cmdlet, you haven’t installed the Microsoft Graph PowerShell SDK on your PC.
Hi Sean,
Greate content, and solid code repo. Noted there is very little in here related to Power Platform. MSFT Docs indicate the presence of a TenantToTenant-MigratePowerAppEnvironment cmdlet, but docs are sparse. Can you shed any light on it?
Hi Sean,
I tried your scripts on a large tenant (10k users, 7k Teams, …) I’ve got some errors during the execution :
| An error occurred while sending the request.
InvalidOperation: C:\temp\temp\Perform-TenantAssessment.ps1:231
Line |
231 | $teamgroup | Add-Member -MemberType NoteProperty -Name “URL” -Val …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot index into a null array.
| Invalid request Status: 400 (BadRequest) ErrorCode: invalidRequest Date: 2024-08-09T09:33:03 Headers: Cache-Control : max-age=0, private Vary : Accept-Encoding
| Strict-Transport-Security : max-age=31536000 request-id : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxclient-request-id : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
| x-ms-ags-diagnostic : {“ServerInfo”:{“DataCenter”:”Italy North”,”Slice”:”E”,”Ring”:”3″,”ScaleUnit”:”000″,”RoleInstance”:”MI1PEPF0000031C”}} Date : Fri, 09 Aug 2024
| 09:33:02 GMT
InvalidOperation: C:\temp\temp\Perform-TenantAssessment.ps1:231
Line |
231 | $teamgroup | Add-Member -MemberType NoteProperty -Name “URL” -Val …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot index into a null array.
InvalidOperation: C:\temp\temp\Perform-TenantAssessment.ps1:885
Line |
885 | $user.OneDriveSizeGB = (((($OneDrive | ? { $_.’Owner Prin …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Method invocation failed because [System.Object[]] does not contain a method named ‘op_Division’.
But after 7 hours, the script has finished.
When I tried to open the Excel file, I’ve got an error: “We found a problem with some content in TenantAssessment.xlsx … After the repair, I’ve been able to consult the results. But when I tried to open the PowerBi Report, I’ve got a new error concerning the DisplayName in Teams table because it contains duplicate values.
Thanks for your great job, and thanks for your help.
Thierry
I’ve been trying to run against my MS CDX demo tenants.
I’ve found the powerbi report will not load unless I create a shared mailbox and a resource – the table lacks headers when there is no data, and this causes an error. I suspect this would rarely be a problem with a real tenant.
More importantly, I am not getting any data from the fields below, even though it exists.
targetobjectID
targetUPN
TargetMail
MailboxItemCount
MailboxSizeGB
OneDriveSizeGB
OneDriveFileCount
Admin is assigned to the App.
PowerShell 7.7.4
Version Name
2.0.2.182 AzureAD
3.5.1 ExchangeOnlineManagement
2.21.1 Microsoft.Graph
7.8.9 ImportExcel
sure how to check MSAL.PS version
Hey Mark,
I expect the data not showing is because names are concealed in reports, could you check you are allowing names to be shown in reports in the tenant? On the shared mailboxes, that is a bug which I will resolve soon. Without shared mailboxes that page does show up blank.
Thanks, that did the trick!
Scripts works well, great work and thanks Sean! Note that it only worked when i ran it with PS V7 (Exchange Online connection error when tested on PS version 5). Also the Assessment outputs to C:\TenantAssessment rather than C:\Temp\TenantAssessment.
Thanks, that did the trick!
Getting below when running assessment in PSv5. Tried running the Connect-ExchangeOnline and get below –
Error connecting to Exchange Online…Exiting…
Press Enter to continue…:
PS C:\temp\Assessment> Connect-ExchangeOnline -Certificate $Certificate -AppID $clientid -Organization ($orgdetails.verifieddomains | ? { $_.isinitial -eq “true” }).name -ShowBanner:$false
Function Get-DeviceComplianceSummaryReport cannot be created because function capacity 4096 has been exceeded for this scope.
At C:\Program Files\WindowsPowerShell\Modules\ExchangeOnlineManagement\3.5.1\netFramework\ExchangeOnlineManagement.psm1:766 char:21
+ throw $_.Exception;
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (Get-DeviceComplianceSummaryReport:String) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : FunctionOverflow
Found that using PSv7 works to avoid the above error but now getting below –
InvalidOperation: C:\TEMP\Assessment\Perform-TenantAssessment.ps1:885
Line |
885 | $user.OneDriveSizeGB = (((($OneDrive | ? { $_.’Owner Prin …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Method invocation failed because [System.Object[]] does not contain a method named ‘op_Division’.
PS C:\TEMP\Assessment>
H,
What version of the Exchange Online Management module are you using?
Hi Sean
Thanks for the followup.
3.5.1 ExchangeOnlineManagement PSGallery
When using PS v7.4.2, I am not getting the “ExchangeOnline exiting” error which I was getting with PS v5.1, but now the script stops at below error as mentioned in my last post.
Line |
885 | $user.OneDriveSizeGB = (((($OneDrive | ? { $_.’Owner Prin …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Method invocation failed because [System.Object[]] does not contain a method named ‘op_Division’.
Regards
Ok, I have seen this before when a null value is returned for a user in the OneDrive report exported. I will add logic to suppress this error but the export should still work fine?
Hi
Script fails with “Error connecting to Exchange Online…Exiting…” The same issue also happens with older v1 script.
Getting Error connecting to Exchange Online…Exiting… even though I have the most up to date version of Exchange Online Management PowerShell module (version 3.5.1)
The best thing to do in this case is to open the code and try to connect using the same logic interactivity to see where it’s failing.
the script is running great, but the SharePoint Site URL is staying empty for me
I believe that’s due to a bug in the usage reports API that has existed since September 2023 where the site URL is not returned. See https://office365itpros.com/2024/02/19/sharepoint-usage-data-issue/
Awesome Script to assess migration items. I have done many T2T migration projects and this helps simplify the assessment process immensely! Thanks for the script!
You’re welcome! Glad it’s helped!
It’s really nice to have the PowerBI reporting template. Appreciate it!
Can i know that Tenant ID and Client ID requires of Source or Destination environment?
This is a really great tool! Thx a lot for your commitment to the community!
The only caveat is, and this is just a personal opinio, you used the powershell SDK instead of the invoke powershell cmd let. I got fed up with those modules becoming deprecated every few years, and lots of customers don’t want to install such things (for bad reasons I admit). Rest API is so easy for people like us, and way more reliable, that the PS SDK is just an obstacle to scalability.
I guess the issue is which development environment should someone use: SDK or Graph API? My response is that professional developers should use the Graph APIs and tenant administrators should use the SDK (because it’s easier). I don’t think the SDK is an obstacle to scalability. There are some features (like JSON batching) that can’t be done with the SDK cmdlets, but generally, the cmdlets are as fast as Graph API requests because they are Graph API requests…
The original version used direct Graph API calls without the SDK but I feel that the SDK is a much easier way for tenant admins of all skill levels to understand the code and adapt / learn from it. The audience for this tool is not limited to people with knowledge of the API (while I recommend all tenant admins familiarise themselves with it).
I’m getting the same error. I’ve both updated and reinstalled the ExchangeOnlineManagement module version 3.4.0, still will not connect to Exchange Online.
It seems to be an issue with the connection to exchange online
Error connecting to Exchange online …. Exiting ….
The most likely issue is that you don’t have the latest version of the Exchange Online Management PowerShell module.
Hi there
I’m busy investigate this for my company and something else to possibly add to the list is the Devops portal (Dev.azure.com), as I believe this is tied to the tenant.