Sign up today and save $20 on your first TRMNL e-ink display
setup guides· 10 min read

Set-CalendarProcessing for Room Mailboxes: Every Setting That Changes Booking Behaviour

A parameter-by-parameter walkthrough of Set-CalendarProcessing for room mailboxes: what each setting does, what breaks when you get it wrong, the exact PowerShell, and why DeleteSubject plus AddOrganizerToSubject is the pair that decides whether a room display is useful.

There is a specific bug report that arrives about a week after a room display goes live. It says: "the screen just says Room Alpha is busy, it does not say what the meeting is." The IT admin checks the calendar, sees the subject line right there in Outlook, and assumes the display is broken. It is not. The room mailbox stripped the subject before it ever reached the calendar, because that is what a room mailbox does by default, and no display can show data that was deleted on arrival.

That behaviour is controlled by Set-CalendarProcessing, which is also where booking windows, maximum durations, conflict handling, recurring-meeting rules and delegate approval live. Most PowerShell articles list the parameters. This one goes through the ones that actually change how a room behaves when a human tries to book it, what breaks when each is set wrong, and the exact commands. All defaults and valid ranges below come from the Microsoft Learn reference, linked at the end.

Connect, and look before you change anything

Everything here runs in Exchange Online PowerShell. Connect first:

Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com

Then read the current state of one room before touching anything:

Get-CalendarProcessing -Identity "Room Alpha" | Format-List

Better, snapshot every room to CSV so you can roll back:

Get-Mailbox -RecipientTypeDetails RoomMailbox -ResultSize Unlimited |
  Get-CalendarProcessing |
  Select-Object Identity, AutomateProcessing, AllowConflicts, BookingWindowInDays,
                MaximumDurationInMinutes, AllowRecurringMeetings, DeleteSubject,
                AddOrganizerToSubject, DeleteComments, RemovePrivateProperty,
                AllBookInPolicy, AllRequestInPolicy, ProcessExternalMeetingMessages |
  Export-Csv -Path .\room-calendarprocessing-before.csv -NoTypeInformation

One thing to know up front: these settings are editable only on resource mailboxes. Running Set-CalendarProcessing against a user mailbox will not give you room behaviour.

AutomateProcessing: the setting everything else depends on

Three values, and they are not a spectrum:

  • None: both the Calendar Attendant and the resource booking attendant are off. The mailbox does nothing with incoming requests. Bookings sit unprocessed.
  • AutoUpdate: only the Calendar Attendant runs. Meeting requests go into the calendar as tentative and stay there until a delegate approves them.
  • AutoAccept: both attendants run. The calendar is updated, then the booking assistant accepts or declines according to policy. This is what people mean by "a room that just books".

What breaks: if a room shows everything as tentative and nobody ever gets a confirmation, this is almost always AutomateProcessing sitting on AutoUpdate. It is also the reason a large number of other parameters silently do nothing: DeleteSubject, AddOrganizerToSubject, DeleteComments and the in-policy settings are only used on resource mailboxes where AutomateProcessing is AutoAccept.

Set-CalendarProcessing -Identity "Room Alpha" -AutomateProcessing AutoAccept

DeleteSubject and AddOrganizerToSubject: the pair that decides whether a display is useful

This is the combination worth understanding properly, because it is the one that determines what any room display, Lobby's or anyone else's, is able to render.

  • DeleteSubject (default $true): removes the Subject value of incoming meeting requests. The original subject is gone from the room's copy of the event.
  • AddOrganizerToSubject (default $true): replaces any existing Subject with the meeting organizer's name.

With both at their defaults, the room's calendar entry reads "Jane Doe" and nothing else. That is deliberate privacy behaviour, and for many organisations it is the right call. But it means a display can show who booked and when, and never what for. The four combinations:

  • DeleteSubject $true and AddOrganizerToSubject $true: organizer name only. This is the default.
  • DeleteSubject $false and AddOrganizerToSubject $false: the real meeting subject. This is what you want for a display.
  • DeleteSubject $false and AddOrganizerToSubject $true: organizer name again, because it replaces whatever subject survived.
  • DeleteSubject $true and AddOrganizerToSubject $false: nothing useful, an empty subject.

If you want subjects on the door, you need both set to $false:

Set-CalendarProcessing -Identity "Room Alpha" `
  -DeleteSubject $false `
  -AddOrganizerToSubject $false

The gotcha that catches everyone: that is necessary but not sufficient. Microsoft's own documentation notes that the default Calendar folder permission on a room mailbox is the AvailabilityOnly role, which does not allow viewing Subject fields at all. You need at least LimitedDetails:

Set-MailboxFolderPermission -Identity "roomalpha@contoso.com:\Calendar" `
  -User Default -AccessRights LimitedDetails

Get this wrong and you will spend an afternoon convinced your Graph integration is broken. It is not. It is being served free/busy data because that is all it has rights to read.

Say the privacy part out loud before you flip it. Turning subjects on means "1:1 Sarah performance review" and "Acquisition call, Project Falcon" are legible to anyone walking past the door. In a 40-person office that is a real risk, not a theoretical one. A reasonable middle ground is subjects on for general rooms and off for the room where sensitive conversations happen.

The guardrails: booking window and maximum duration

BookingWindowInDays

How far ahead a room can be reserved. Valid values are 0 through 1080, default 180. A value of 0 means today only.

What breaks: at the default, someone can hold your only large room every Thursday for the next six months. Dropping this to 60 or 90 removes a whole class of quiet capacity loss. Set it too low (say 14) and you will get complaints from anyone planning a quarterly offsite.

MaximumDurationInMinutes

Valid values 0 through 2147483647, default 1440 (24 hours). A value of 0 means unlimited. For recurring meetings, the value applies to each individual instance, not the series.

What breaks: the 24-hour default effectively means no cap. All-day holds sail straight through. A 240-minute (4 hour) cap declines the pathological cases while leaving normal workshops alone.

EnforceSchedulingHorizon

Controls what happens to recurring meetings that start inside the booking window but extend past it. When $true, a recurring request whose meetings extend beyond the BookingWindowInDays date is declined. When $false, the request is accepted for the occurrences that fall inside the window.

What breaks: if you set a short booking window and leave enforcement on, every open-ended weekly recurrence gets declined outright, which users experience as "the room system is broken". Setting it to $false is usually the friendlier behaviour: accept what fits, decline the rest.

Set-CalendarProcessing -Identity "Room Alpha" `
  -BookingWindowInDays 90 `
  -MaximumDurationInMinutes 240 `
  -EnforceSchedulingHorizon $false

Recurring meetings and conflicts

AllowRecurringMeetings

Default $true. Setting it to $false blocks all recurring bookings on that room. Occasionally the right answer for a single high-demand room, almost never the right answer org-wide.

AllowConflicts

Default $false. When $true, conflicting requests are accepted and a recurring series is accepted regardless of how many occurrences clash, and ConflictPercentageAllowed and MaximumConflictInstances are ignored entirely.

What breaks: setting this to $true is how you end up with two teams in the same room and a display that shows both bookings simultaneously. There is essentially no good reason to enable it for a physical room. It exists for shared resources where double-booking is meaningful.

ConflictPercentageAllowed and MaximumConflictInstances

Both apply only to new recurring requests, and only when AllowConflicts is $false. ConflictPercentageAllowed takes an integer 0 through 100, default 0. MaximumConflictInstances takes an integer 0 through 2147483647, default 0. At the defaults, a recurring series with even one conflicting occurrence is declined in full.

What breaks: the strict defaults are the reason someone books a weekly stand-up for a year and gets a hard decline because of a single clash in November. Allowing a small tolerance makes the system much less annoying:

Set-CalendarProcessing -Identity "Room Alpha" `
  -AllowConflicts $false `
  -ConflictPercentageAllowed 20 `
  -MaximumConflictInstances 5

The declined occurrences still get declined individually. The series survives.

Who is allowed to book

AllBookInPolicy

Default $true: in-policy requests from all users are approved automatically. Set it to $false and in-policy requests need approval from a delegate. That is the switch that turns an open room into a gated one.

BookInPolicy

The named list of users or groups whose in-policy requests are auto-approved. Only meaningful once AllBookInPolicy is $false. Important limitation: query-based groups such as dynamic distribution groups are not supported, and Microsoft explicitly warns against nested groups in resource mailbox settings. Use a flat, non-nested mail-enabled security group.

AllRequestInPolicy

Whether all users may submit in-policy requests at all. Those requests require delegate approval when AllBookInPolicy is $false.

ForwardRequestsToDelegates

Default $true. Forwards incoming requests to the delegates configured on the resource mailbox.

What breaks: the classic failure is a gated room whose only delegate left the company. Requests are forwarded into a mailbox nobody reads, and users see requests hang in tentative forever. If you gate a room, put at least two people on ResourceDelegates and check them at offboarding.

Set-CalendarProcessing -Identity "Boardroom" `
  -AllBookInPolicy $false `
  -BookInPolicy "leadership-team@contoso.com" `
  -ResourceDelegates "ops@contoso.com","facilities@contoso.com" `
  -ForwardRequestsToDelegates $true

Related: TentativePendingApproval (default $true) decides whether requests awaiting a delegate show as tentative or as free on the calendar. Leave it on, otherwise the room reads as available while a request is pending and your display will happily tell people to walk in.

External requests: ProcessExternalMeetingMessages

Default $false, which means meeting requests originating outside your Exchange organisation are rejected.

What breaks: the symptom is an external partner, contractor or a colleague at an acquired company sending an invite that includes your room, and the room silently declining. Set it to $true only when you genuinely need it, and understand what you are opting into: anyone in the world who knows the room's SMTP address can now put a booking on your wall.

Body text, privacy flags and the response message

  • DeleteComments (default $true): removes the message body of incoming meeting requests. Set to $false if you want a display or an integration to surface details like "on the 3rd floor" or a dial-in.
  • RemovePrivateProperty (default $true): clears the private flag on incoming meetings, so a meeting marked private by the organizer stops being private in the room's copy. If you rely on private meetings staying hidden, set this to $false.
  • RemoveOldMeetingMessages (default $true): the Calendar Attendant deletes outdated and redundant updates and responses. Leave it on.
  • AddAdditionalResponse (default $false) and AdditionalResponse: adds custom text to the acceptance or decline email. This is the cheapest way to make your booking policy visible at the moment someone books.
Set-CalendarProcessing -Identity "Room Alpha" `
  -AddAdditionalResponse $true `
  -AdditionalResponse "Max 4 hours. If nobody arrives within 10 minutes the room is free for anyone."

Applying a baseline across every room

Once you have decided the baseline, apply it in one pass. Test on one room first, and keep the CSV snapshot from earlier.

$rooms = Get-Mailbox -RecipientTypeDetails RoomMailbox -ResultSize Unlimited

foreach ($room in $rooms) {
    Write-Host "Configuring $($room.DisplayName)"
    Set-CalendarProcessing -Identity $room.Identity `
        -AutomateProcessing AutoAccept `
        -AllowConflicts $false `
        -BookingWindowInDays 90 `
        -MaximumDurationInMinutes 240 `
        -EnforceSchedulingHorizon $false `
        -AllowRecurringMeetings $true `
        -ConflictPercentageAllowed 20 `
        -MaximumConflictInstances 5 `
        -DeleteSubject $false `
        -AddOrganizerToSubject $false `
        -DeleteComments $false `
        -RemovePrivateProperty $false `
        -ProcessExternalMeetingMessages $false `
        -AllBookInPolicy $true `
        -TentativePendingApproval $true

    Set-MailboxFolderPermission -Identity "$($room.PrimarySmtpAddress):\Calendar" `
        -User Default -AccessRights LimitedDetails -ErrorAction SilentlyContinue
}

Then verify:

Get-Mailbox -RecipientTypeDetails RoomMailbox -ResultSize Unlimited |
  Get-CalendarProcessing |
  Format-Table Identity, AutomateProcessing, BookingWindowInDays,
               MaximumDurationInMinutes, DeleteSubject, AddOrganizerToSubject

What Set-CalendarProcessing cannot do

Worth stating plainly, because a lot of the questions people bring to this cmdlet are not answerable by it.

  • It cannot detect no-shows. There is no occupancy signal here. Auto-release on no-show comes from Teams panels or Places reservation policies, not from calendar processing.
  • It cannot enforce room capacity. A room mailbox with ResourceCapacity 4 will happily accept a meeting with 20 attendees. Capacity is metadata for Room Finder, not a rule.
  • It cannot expire recurring series. Nothing in this cmdlet cleans up the weekly meeting that outlived its project. That stays a human review.
  • It does not change what Graph can return to your display beyond what got stored. Calendar folder permissions decide read access; calendar processing decides what was written in the first place.

The buy side of this decision

Getting these parameters right is the hard, valuable half of a room display project, and it is entirely yours regardless of what you put on the wall. Once the mailboxes behave, the remaining work is rendering: a Graph subscription, a token refresh loop, something to draw a schedule, and a device that stays awake. Plenty of teams build that. The part that wears people down is not the first room, it is keeping five of them alive through OAuth expiry, firmware updates and the screen that quietly froze on a Thursday.

Lobby is the buy side. It reads Microsoft 365 room resources (and Google Workspace) in real time and renders them in three ways from the same dashboard: a physical e-ink panel on TRMNL 7.5" open hardware, a virtual display that is just a URL in any browser tab, or a room overview board for reception.

The hardware is bought direct from the TRMNL shop and we take no markup on it. Volume pricing applies: USD 139 per device for 1 to 9, USD 119 each from 10 to 20, USD 109 from 21 to 50, and down to USD 99 at 151 or more. Same list price in the EU and the USA, before tax, duties and shipping. Buy once and own it. It mounts magnetically, runs up to 12 months on a charge, and is readable from 5m.

On the software side, Free is free forever for up to three active displays with 15-minute e-ink updates and no credit card. It is not a trial. Unlimited is USD 30 per month billed yearly, which is USD 360 a year, or USD 50 per month if you pay month to month, for unlimited rooms and displays. Pro Unlimited is USD 60 per month billed yearly, USD 720 a year, or USD 100 per month month to month, and adds 5-minute e-ink updates, custom templates, your own logo with Lobby branding removed, room feedback with free QR stickers, a Slack /book command, priority support, full EU hosting for TRMNL devices, battery saver mode and smart updates. Yearly billing saves 40 percent and there is no annual contract lock-in. Setup is under 10 minutes, self-serve.

What it does not do: no desk booking, no visitor management, no room automation or AV control, no enterprise SSO or SCIM at scale, no MDM on the TRMNL hardware, no occupancy sensors, and no on-premises Exchange unless you are in hybrid. If you need managed devices under Intune, this is the wrong shape of product. Lobby is made by Vikba ApS in Denmark and is not affiliated with Microsoft or Google.

TL;DR

  • AutomateProcessing AutoAccept is the prerequisite. Most other parameters are ignored on AutoUpdate or None.
  • DeleteSubject $false plus AddOrganizerToSubject $false is what puts a real meeting subject on a display. Both must be $false, and the calendar folder permission must be at least LimitedDetails, because the default AvailabilityOnly role cannot read Subject at all.
  • Defaults worth changing: BookingWindowInDays (180 is generous), MaximumDurationInMinutes (1440 is effectively no cap), and ConflictPercentageAllowed plus MaximumConflictInstances (both 0, which declines a whole recurring series over one clash).
  • Leave AllowConflicts $false for physical rooms. Leave TentativePendingApproval $true on gated rooms or your display will show free while approval is pending.
  • ProcessExternalMeetingMessages $true lets anyone outside your tenant book the room. Only enable it deliberately.
  • This cmdlet cannot detect no-shows, enforce capacity, or expire recurring meetings. Those need panels, policy or people.

Related reading

Sources

Try Lobby — free forever up to 3 displays

Room booking that just works.

Get started →