Primer: Use Invoke-ChangeMeetingOrganizer to bulk change meeting organizer in Exchange Online

In a previous article, we covered how the newly introduced Invoke-ChangeMeetingOrganizer cmdlet can be used to change a meeting’s organizer in Exchange Online. While the cmdlet does handle recurring meetings, it can only update one (master) meeting at a time, making the realistic “transfer all meetings from user X” scenario not that straightforward to address. This is further complicated by the need to leverage a unique identifier for each meeting, as subject is not unique-valued and thus not always an option.

So, in this article, we will present a sample PowerShell script that can be used to bulk reassign all future meetings, organized by a given user, to another user. The script will be subject to the limitations of the Invoke-ChangeMeetingOrganizer cmdlet, as discussed in our previous article. To name a few: no support for shared or room mailboxes, no support for meetings found in non-default calendar folders, the original organizer’s mailbox must still exist, and so on. Still, the script will still be useful, as it will automate the “transfer” of all supported meetings and instances to a new organizer, all in one go.

To achieve all this we will leverage two PowerShell modules. The Invoke-ChangeMeetingOrganizer cmdlet is included in the Exchange Online module, and we can also use said module to verify the input parameters. To get the identifiers for meetings, we can leverage the Graph SDK for PowerShell and the Get-MgUserEvent cmdlet. All the required cmdlets can be run either as a user, via delegated permissions, or non-interactively, via application permissions.

Of course, we will also need sufficient permissions. For the Invoke-ChangeMeetingOrganizer cmdlet, those include:

Get-ManagementRole -Cmdlet Invoke-ChangeMeetingOrganizer -CmdletParameters NewOrganizer | ? {$_.IsRootRole}

Name            RoleType
----            --------
Mail Recipients MailRecipients
User Options    UserOptions

The roles above also include access to the Get-ExOMailbox cmdlet, which we will leverage to validate the input parameters.

On the Graph side of things, we need to be able to fetch events within the user’s default calendar. This can be achieved in two ways. The “easy” one is via Calendars.Read application permissions, but the downside here is the unrestricted access to all calendars within the tenant. This can be addressed by leveraging Exchange Online’s RBAC for applications instead. Another option is to leverage Calendars.Read.Shared delegate permissions, which can be combined with folder- or mailbox-level delegation to grant the running user access to the organizer’s events.

The script can be run in either fashion, but uses delegate permissions by default. If you prefer the fully automated approach, make sure to uncomment lines 16 and 35, and fill in the required values for the application and certificate. You can also use a different method, such as passing an access token. Also, let me know if you think a version of the script that leverages direct Graph API requests is needed.

Running the script requires two mandatory parameters, as follows:

  • Identity – used to designate the original organizer’s mailbox, aka where the meeting is “homed”. You can use any valid Exchange identifier for this parameter, such as Alias, UPN, SMTP address…
  • NewOrganizer – the SMTP address of the new organizer.

Both values must correspond to existing user mailboxes, within your own tenant. Therefore, the first thing the script does is to “resolve” the provided input values. If an issue is detected at this point, the script will exit.

After making sure we’ll have proper input, we need to obtain a list of matching meetings within the organizer’s mailbox. This can be achieved via the Get-MgUserEvent cmdlet, provided sufficient permissions are granted. Leveraging the cmdlet’s filter functionality, we can fetch the list of future events for which the user is organizer and are not cancelled. In addition, we filter out any events without attendees, as those are irrelevant to the task at hand. The list of event Ids is what we are after, but we can also fetch few other properties of interest.

The last step is to leverage the Invoke-ChangeMeetingOrganizer cmdlet to change each event’s organizer, referencing it via the retrieved Id value. As the cmdlet cannot update the join information for any online meetings, the script will warn you for any such entries. Work with the newly designated organizer to update the meeting with a proper online meeting blob.

For any recurring meetings, we use the default behavior of the cmdlet, that is to transfer the series’ ownership starting from the next occurrence. To alert you of this, another warning will be issued when a recurring meeting is detected. If you want to modify this behavior by specifying a different cutoff date (via the -TransferSeriesStartDate parameter) feel free to update the code on line 62.

As a side note, since we have no clue as to what kind of throttling applies to the Invoke-ChangeMeetingOrganizer cmdlet, I have chosen more cautious approach and forced some delay between executions. Should you believe this is unnecessary, feel free to comment out the corresponding code (line 63). Remember that the change in organizer can generate a multitude of messages to both internal and external recipients, as we discussed in our previous article, so some delay might do us good.

The script does not generate any output, apart from the aforementioned warnings and some verbose information. The main reason for the lack of output is the fact that the identifiers for any processed meeting will change, so having the old values is of no use (and the new ones are not returned by the cmdlet). As for the subject value, while it is preserved, it cannot be used to uniquely identify a meeting, as already mentioned above. In any case, adding some basic output is an easy task.

Before I forget, you can download the script from my GitHub repo. Here is also an example on how to run it:

.\Change_meeting_organizer_bulk.ps1 -Identity organizer@domain.com -NewOrganizer new@domain.com

ChangeMeetingOrganizerBulk

One last note – I’ve deliberately specified an older module versions in the Requires block of the script, as the latest ones are just few days old, and I imagine not every admin out there has updated to them. That said, there is a known issue with any of the ExO module versions older than v3.10.1 when connecting via CBA, so do make sure to update to the latest.

1 thought on “Primer: Use Invoke-ChangeMeetingOrganizer to bulk change meeting organizer in Exchange Online

Leave a Reply

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

Discover more from Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading