EXOExchange OnlinePSPowerShell

The offboarding step everyone forgets: meeting ownership

8 July 2026  ·  9 min leestijd  ·  Kevin Oosterlaken

Every organisation has this meeting: the weekly stand-up that has run for three years, organised by someone who left last month. The series still fires, nobody can change it, and eventually someone recreates it from scratch, losing the history and forcing forty people to re-accept.

Exchange Online is finally fixing this. Message center item MC1227623 announces a new PowerShell cmdlet, Invoke-ChangeMeetingOrganizer, rolling out worldwide between late June and July 2026 (GCC High and DoD follow through August). It transfers an existing meeting or series to a new organizer, who then gets full control: recurrence, attendees, description, everything. A user-facing version in Outlook and Teams is promised for later; the admin cmdlet arrives first, enabled by default, no configuration required.

This post covers how the transfer behaves, the gotchas that are easy to miss, a wrapper script that makes it safe to run, and the one thing that will stop you cold if you try it too early.

How the transfer behaves

The one-liner is simple enough:

Invoke-ChangeMeetingOrganizer -Identity frank@contoso.com -EventId AAMkAGRlMGI0 -NewOrganizer adele@contoso.com

Identity is the mailbox of the current organizer, EventId identifies the meeting, NewOrganizer is the receiving mailbox. The cmdlet supports -WhatIf and -Confirm, which you should absolutely use given what it touches.

The interesting behaviour is in what happens around that call:

The two gotchas in the design

The previous organizer is dropped from the meeting. After the transfer, the old organizer is no longer an attendee on the transferred portion. For offboarding that is exactly right. For a role change where the person still needs to attend, the new organizer has to re-invite them manually. Easy to miss, awkward to discover live.

Identifying the right meeting has sharp edges. The cmdlet takes either -EventId or -Subject. -Subject is the convenient path: match exactly one meeting and it transfers; match several and the cmdlet refuses to guess, returning the list of candidates so you can rerun with the precise -EventId. That is genuinely helpful, but two things bite. Subjects are rarely unique across a mailbox's history, so the ambiguous case is often the norm, not the edge. And the docs are explicit that -EventId "must identify the recurring series, not an individual instance" — hand it an instance id and it fails. The subject match is also scoped tightly: it only looks at meetings on the default calendar where -Identity is the actual organizer, so a meeting that mailbox merely attends returns No calendar events were found, not a hit. So a safe transfer is less a one-liner and more: try by subject, read what comes back, and confirm before committing.

Which is exactly what the script below wraps.

A wrapper that makes the transfer safe

You could call Invoke-ChangeMeetingOrganizer -Subject ... directly. This wrapper adds the guardrails you want around something irreversible: it verifies both mailboxes before touching anything, lets you drive the transfer by subject or by an exact EventId, keeps -WhatIf working end to end, and fails loudly instead of printing a cheerful success over an error. It needs a single module, ExchangeOnlineManagement — the cmdlet finds the meeting itself, so there is no second module to install and no second source of truth to drift.

#Requires -Modules ExchangeOnlineManagement

<#
.SYNOPSIS
    Transfers meeting ownership in Exchange Online, safely.
.DESCRIPTION
    Wraps Invoke-ChangeMeetingOrganizer. Identify the meeting by -Subject (the
    cmdlet transfers it when exactly one matches, or returns the candidates so
    you can pick) or directly by -EventId. Validates both mailboxes first and
    supports -WhatIf end to end.
.EXAMPLE
    .\Transfer-MeetingOrganizer.ps1 -CurrentOrganizer [email protected] `
        -NewOrganizer [email protected] -Subject "Weekly stand-up" -WhatIf
.EXAMPLE
    .\Transfer-MeetingOrganizer.ps1 -CurrentOrganizer [email protected] `
        -NewOrganizer [email protected] -EventId AAMkAGRlMGI0
#>
[CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'BySubject')]
param(
    [Parameter(Mandatory)] [string] $CurrentOrganizer,
    [Parameter(Mandatory)] [string] $NewOrganizer,
    [Parameter(Mandatory, ParameterSetName = 'BySubject')] [string] $Subject,
    [Parameter(Mandatory, ParameterSetName = 'ByEventId')] [string] $EventId,
    [datetime] $TransferFrom = (Get-Date).Date.AddDays(1)
)

$ErrorActionPreference = "Stop"

# 1. Both mailboxes must exist before we touch anything
foreach ($upn in $CurrentOrganizer, $NewOrganizer) {
    $null = Get-EXOMailbox -Identity $upn
    Write-Host "  [ok] mailbox found: $upn"
}

# 2. Let the cmdlet identify the meeting: by EventId directly, or by Subject
#    (it transfers a single match, or returns the candidates to choose from).
$params = @{
    Identity                = $CurrentOrganizer
    NewOrganizer            = $NewOrganizer
    TransferSeriesStartDate = $TransferFrom
    Confirm                 = $false
    ErrorAction             = 'Stop'   # so "action is disabled" actually stops us
}
if ($PSCmdlet.ParameterSetName -eq 'ByEventId') {
    $params.EventId = $EventId
    $label = "EventId $EventId"
} else {
    $params.Subject = $Subject
    $label = "subject '$Subject'"
}

# 3. Transfer, honouring -WhatIf all the way down
$doel = "$label organised by $CurrentOrganizer -> $NewOrganizer, effective $($TransferFrom.ToShortDateString())"
if ($PSCmdlet.ShouldProcess($doel, "Transfer meeting organizer")) {

    $result = Invoke-ChangeMeetingOrganizer @params

    # A single-match transfer returns nothing. An ambiguous -Subject returns the
    # candidate meetings instead of acting, so surface them and stop.
    if ($result) {
        Write-Warning "Subject '$Subject' matched more than one meeting. Nothing was transferred."
        Write-Host   "Pick the right EventId below and rerun with -EventId:`n"
        $result | Format-List *
        return
    }

    Write-Host "`nTransferred: $doel"
    Write-Host "Remember:"
    Write-Host "  - $CurrentOrganizer is NO LONGER an attendee; re-invite manually if needed."
    Write-Host "  - External attendees receive a cancellation plus a new invite and must re-accept."
}

A few deliberate choices in there. The mailbox check up front fails fast on typos, before anything irreversible. Identifying the meeting is left to the cmdlet itself — -Subject for convenience, -EventId when you already know it — which is what drops the second module. Parameter sets make -Subject and -EventId mutually exclusive, so you cannot accidentally pass both. When a subject is ambiguous the cmdlet returns the candidates rather than acting; the script surfaces that list and stops, so you rerun with the exact -EventId instead of transferring the wrong series. Finally, -ErrorAction Stop on the transfer means a failure actually stops the script, rather than printing a cheerful "Transferred" over the top of an error, which is exactly the trap the next section is about.

The one that will stop you cold

Here is the thing the announcement does not tell you clearly enough: the cmdlet can be present in your module and still refuse to run. Run it before the feature has landed in your tenant and you get:

Invoke-ChangeMeetingOrganizer: ||Transfer meeting action is disabled.

That is not your session, your permissions, or your script. It is the MC1227623 rollout still in flight. The cmdlet ships with the Exchange Online module ahead of the server-side capability, so the command exists, accepts your parameters, resolves the meeting, and then the service declines at the last step.

Two things worth knowing here. First, there is no organisation-level switch to flip while you wait. Checking for one comes back empty:

Get-OrganizationConfig | Format-List *MeetingOrganizer*, *ChangeMeeting*
# (no matching properties)

No property means no toggle: this is purely gated by the rollout, not by a setting you forgot. Second, this is precisely why the script uses -ErrorAction Stop. Without it, Invoke-ChangeMeetingOrganizer writes "action is disabled" as a non-terminating error and the script sails on to print "Transferred" underneath, telling you the transfer succeeded when it did nothing. Fail loudly, or you will trust a lie.

So if you are reading this during the rollout window and hit "action is disabled": the plumbing is correct, the service simply is not ready. Try again in a few days with the exact same call.

One more trap from that same window, and this one wastes an afternoon if you let it: the disabled state does not always surface as the clean message above. The exact same call comes back sometimes as Transfer meeting action is disabled, and sometimes, with nothing changed, as a generic:

A server side error has occurred because of which the operation could not be completed. Please try again after some time. If the problem still persists, please reach out to MS support.

That message all but tells you to open a support ticket. Don't, yet. It is intermittent: during the rollout the service is simply unreliable about how it reports a feature that is not switched on, and repeating the identical call often returns the real reason instead. Do not expect -Verbose to save you here, either. It shows the HTTP round-trip, which is reassuring, but the same call under -Verbose still returns the bare "server side error" as often as not, because the wording is the server's choice, not yours. During the rollout window, read a "server side error" on an otherwise valid call as one more spelling of "not ready", not as a bug to escalate.

Make it part of offboarding, not firefighting

The real value of this cmdlet is not the one-off rescue, it is closing a structural gap. Offboarding processes are usually solid on licences, group memberships and mailbox conversion, and silent on the recurring meetings a person owns. Those only surface weeks later, when someone tries to move the stand-up and cannot.

So add one line to the offboarding checklist: transfer or cancel the recurring meetings this person organises. Transferring a series you can already name is the script above. Finding them all in the first place is a different job — the transfer cmdlet only acts on a meeting you can identify — so discover the mailbox's meetings first with Get-CalendarDiagnosticObjects, which stays inside the same Exchange module. Run it during offboarding, transfer what should live on, cancel the rest, and the three-year-old zombie series never gets the chance to exist.

Sources: MC1227623, Invoke-ChangeMeetingOrganizer on Microsoft Learn, Roadmap 554937.

← Alle posts Contact