How to Bulk Transfer Meeting Ownership Between Mailboxes

Wrapping Code Around the Invoke-ChangeMeetingOrganizer Cmdlet to Fix One of Its Problems

As reported previously, the Invoke-ChangeMeetingOrganizer cmdlet has two big problems. First, although an administrator might be able to transfer ownership for a meeting based on the meeting subject, Graph event identifiers are needed when events with duplicate subjects exist within a calendar. There’s no easy way for an administrator to retrieve event identifiers without resorting to a Graph query.

Graph queries are also needed when administrators must transfer ownership for multiple events. For example, if someone is leaving a company, it’s likely that multiple events exist in their calendar that should be transferred to new owners.

The second issue is that Invoke-ChangeMeetingOrganizer does nothing to transfer the online portion of Teams meetings. The cmdlet can transfer the calendar event, but Microsoft says that manual intervention is necessary to update the Teams portion of the meeting to make sure that the new owner controls meeting recordings, transcripts, and other artifacts. It’s disappointing that Microsoft ignores the Teams element of online meetings, but it’s possible to close the gap with PowerShell. I’ll explain how in a future article.

Bulk Transfer of Meetings from One Owner to Another

This article covers how to create a script to transfer all future meetings from one user mailbox to the ownership of another user mailbox. As you’ll recall, meetings involving shared or group mailboxes cannot be transferred.

We probably all have our own ideas about how to create such a script. In this post, Vasil Michev explains how he solved the problem. My script is similar in some respects, but different in others. It’s nice to have the choice of template scripts to choose from when you come to integrate the transfer of meetings into employee exit processes.

Explaining the Bulk Transfer Script

My script, which you can download from the Microsoft 365 for IT Pros GitHub repository, uses the Exchange Online management module and the Microsoft Graph PowerShell SDK. I use a registered Entra ID app for authentication because access is required to user calendar data. The same app can be used to authenticate with Exchange Online and the Graph.

Make sure to use version 3.10.1 of the Exchange Online management module because it contains an important update for certificate-based authentication. Using Exchange Online cmdlets with app-only authentication has specific requirements for app permissions and roles. The app must have consent to use the Calendar.Read and User.ReadBasic.All application permissions. Calendar.Read allows access to all calendars across the tenant, so consider using RBAC for Applications to limit the scope of the app.

After permissions and authentication are taken care of, we can run some code. The script:

  • Has three parameters: source mailbox, target mailbox, and date to transfer meetings from. The date must be in the future. The script validates that the source and target mailboxes are user mailboxes that can participate in the transfer process.
  • Checks the calendar of the source mailbox to find events to transfer. These are events that take place after the transfer date. The command used is:
[array]$Events = Get-MgUserDefaultCalendarEvent -UserId $SourceMailboxId -All -Filter "start/datetime gt '$($StartDate.ToString('yyyy-MM-ddTHH:mm:ss'))' and IsCancelled eq false" -ErrorAction Stop
  • Events in a user calendar can be organized (owned) by the user or another user. The script filters out non-owned meetings because only owned meetings can be transferred.
  • Events can be meetings, recurring events, and personal events (like a doctor’s appointment). The Invoke-ChangeMeetingOrganizer cmdlet transfers meetings and recurring events with slightly different commands. For example, to transfer a recurring event, the script runs:
Invoke-ChangeMeetingOrganizer -Identity $SourceMailboxId -EventId $CalendarEvent.Id -NewOrganizer $TargetMailboxId -TransferSeriesStartDate $StartDate
  • The script also checks meetings to determine if they are online Teams meetings. This information is noted in the output file.
  • Basic throttling is included by pausing processing by a second after each successful transfer. The chosen interval is an educated guess rather than the result of careful experimentation.

Figure 1 shows an example of the script in action.

Running the script to transfer meeting ownership in bulk.

Invoke-ChangeMeetingOrganizer.
Figure 1: Running the script to transfer meeting ownership in bulk

I’ve tested the script to transfer ownership for up to 50 meetings, including a mixture of standard, recurring, and Teams events. The idea is to demonstrate how to automate the transfer of all meetings from a user mailbox to another, not to create a complete solution. It might be preferable to find events and create a CSV file that can be edited to add the target mailbox for each meeting and then process the CSV file to make the transfers. It would be easy to change the code to take this route.

Automation Through Scripting Enhances the Meeting Transfer Cmdlet

The script demonstrates how to use the Invoke-ChangeMeetingOrganizer cmdlet to transfer all the owned meetings found after a selected date from one user mailbox to another. It deals with a need arising when people who organize meetings leave a company. By itself, the cmdlet is effective at transferring a single meeting. Surrounded by some PowerShell automation, its capabilities become a lot more interesting.


Need help to write and manage PowerShell scripts for Microsoft 365, including Azure Automation runbooks? Get a copy of the Automating Microsoft 365 with PowerShell eBook, available standalone or as part of the Microsoft 365 for IT Pros eBook bundle.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.