Microsoft Bookings の予約ページは「公開」状態でも、公開範囲が「組織内のみ」か「誰でも」かで挙動が大きく変わります。isPublished と publicUrl だけでは差が見えないときに、Graph API/PowerShell で公開範囲を判別する方法を解説します。
よくある悩み:Bookings の公開範囲を変えたのに API のレスポンス上で差が見えない
Microsoft Bookings(Shared Bookings)の運用では、同じテナント内に複数の Bookings メールボックス(例:Mailbox1 / Mailbox2)を用意し、部署や拠点ごとに予約ページを分けることがよくあります。ところが予約ページの設定を次のように変えていても、Microsoft Graph で bookingBusiness を取得しただけでは「どちらの公開範囲なのか」を見落としがちです。
| Bookings メールボックス | 予約ページの公開範囲(UI) | 現場で起きること |
|---|---|---|
| Mailbox1 | 組織内のユーザーのみ(Available to people in your organization) | 社内ユーザーは予約できるが、社外ユーザーはサインイン要求になり予約できない |
| Mailbox2 | 誰でも(Available to anyone) | 社外ユーザーも URL から予約できる(運用によっては OTP など追加条件あり) |
特に「Graph API で取得したら両方 isPublished = true で publicUrl も返ってくる。差が分からない」という状態は、公開(Publish)と公開範囲(アクセス制御)が別概念であることが原因です。
まず整理:isPublished と publicUrl は「公開」状態の指標であって「公開範囲」ではない
bookingBusiness には isPublished と publicUrl があり、Publish/Unpublish のアクションで値が切り替わります。Microsoft のリファレンスでも、Publish は isPublished を true にし、publicUrl に予約ページの URL を設定する動きとして説明されています。
ここがポイントで、isPublished=true かつ publicUrl が存在することは「予約ページが公開されている(URL が発行されている)」ことの確認には使えます。しかし、それだけでは「誰でもアクセスできる公開」なのか、「組織内のみ(サインイン必須)」なのかは判断できません。
| プロパティ | 意味 | このプロパティだけで分かること | 分からないこと |
|---|---|---|---|
| isPublished | 予約ページが公開されているかどうか | 公開/非公開(URLが有効か) | 公開範囲(組織内のみ/誰でも) |
| publicUrl | 予約ページの URL(公開後に設定) | URLの存在確認 | URLにアクセスできる対象(匿名可か、サインイン必須か) |
結論:公開範囲は bookingPageSettings.accessControl を見る
公開範囲の判定に使えるのが bookingPageSettings の accessControl です。これは「公開済み予約ページへのアクセス制御」を表すプロパティで、unrestricted(制限なし)と restrictedToOrganization(組織に制限)が定義されています。
| accessControl の値 | Bookings UI の意味 | 想定される挙動 | 監査時のラベル例 |
|---|---|---|---|
unrestricted | 誰でも(Available to anyone) | 匿名ユーザーでも予約ページを開ける(テナント設定や OTP により追加条件が付く場合あり) | 誰でも |
restrictedToOrganization | 組織内のユーザーのみ(Available to people in your organization) | サインイン要求になり、組織内アカウント以外は予約しにくい | 組織内のみ |
unknownFutureValue | 将来の拡張用 | 現行の UI と一致しない可能性があるため要確認 | 不明(要確認) |
ちなみに、2022 年頃の Q&A では「組織内のみ」の切り替えは Graph では未サポート、と回答されていました。 その後、bookingBusiness に bookingPageSettings が追加され、公開ページ設定を取得できるようになった経緯があります。
Graph API で公開範囲を取得する手順
前提として、Microsoft Graph の Microsoft Bookings API は Shared Bookings のみが対象で、個人用(Personal Bookings)には適用されません。
ステップ1:Bookings ビジネス(メールボックス)一覧を取得する
まずはテナント内の Bookings ビジネスを一覧取得します。ここで注意点として、一覧取得はパフォーマンスの都合で id と displayName しか返さない仕様です(ほかのプロパティは別途 GET が必要)。さらに結果が 500 件に制限され、ページングもサポートされません。
GET https://graph.microsoft.com/v1.0/solutions/bookingBusinesses
ステップ2:個別に bookingBusiness を取得して bookingPageSettings を確認する
続いて、対象の Bookings メールボックス(bookingBusiness の id)を指定して詳細を取得します。ポイントは bookingPageSettings を取得対象に入れることです。
GET https://graph.microsoft.com/v1.0/solutions/bookingBusinesses/[email protected]?$select=id,displayName,isPublished,publicUrl,bookingPageSettings
レスポンスのイメージは次のとおりです(見やすさのため一部省略)。
{
"id": "[email protected]",
"displayName": "Mailbox1",
"isPublished": true,
"publicUrl": "https://outlook.office.com/bookings/....",
"bookingPageSettings": {
"accessControl": "restrictedToOrganization",
"enforceOneTimePassword": false,
"isSearchEngineIndexabilityDisabled": true
}
}
この bookingPageSettings.accessControl を見れば、Mailbox1 / Mailbox2 の公開範囲を機械的に判定できます。isPublished と publicUrl は「公開されているか」を見るための値、accessControl は「誰がアクセスできるか」を見るための値、と役割を分けて理解すると混乱しません。
PowerShell で公開範囲を判別する方法(Microsoft Graph PowerShell)
手元の運用で一番ラクなのは、Microsoft Graph PowerShell SDK(Microsoft.Graph.Bookings)を使って監査用の一覧を作る方法です。Get-MgBookingBusiness は最小権限の例として Bookings.Read.All などが示されています。
サンプル:Mailbox1 / Mailbox2 を判定して一覧表示する
Import-Module Microsoft.Graph
Import-Module Microsoft.Graph.Bookings
# 監査用途なら読み取り権限で開始(環境に応じて Bookings.Manage.All などに調整)
Connect-MgGraph -Scopes "Bookings.Read.All"
$targetIds = @(
"[[email protected]](mailto:[email protected])",
"[[email protected]](mailto:[email protected])"
)
function Convert-AccessControlLabel {
param([string]$AccessControl)
switch ($AccessControl) {
"restrictedToOrganization" { return "組織内のみ" }
"unrestricted" { return "誰でも" }
default { return "不明" }
}
}
$result = foreach ($id in $targetIds) {
$b = Get-MgBookingBusiness -BookingBusinessId $id -Property "id","displayName","isPublished","publicUrl","bookingPageSettings"
$ac = $null
if ($b.BookingPageSettings) { $ac = $b.BookingPageSettings.AccessControl }
[pscustomobject]@{
Id = $b.Id
DisplayName = $b.DisplayName
IsPublished = $b.IsPublished
AccessControl = $ac
ScopeLabel = (Convert-AccessControlLabel -AccessControl $ac)
PublicUrl = $b.PublicUrl
}
}
$result | Format-Table -AutoSize
この結果を CSV にエクスポートして台帳化すると、「公開範囲が意図せず変わっていた」事故をかなり減らせます。
サンプル:テナント内の Bookings ビジネスを横断監査して CSV 出力する
対象が増えると手入力がつらいので、テナント内一覧を回して詳細を取る形が実用的です。前述のとおり一覧は id/displayName のみなので、詳細は id ごとに取得します。
# 1) まず一覧(id/displayName)
$bizList = Get-MgBookingBusiness -All
# 2) 詳細を取り直して accessControl を抜く
$audit = foreach ($biz in $bizList) {
$detail = Get-MgBookingBusiness -BookingBusinessId $biz.Id -Property "id","displayName","isPublished","publicUrl","bookingPageSettings"
$ac = $null
if ($detail.BookingPageSettings) { $ac = $detail.BookingPageSettings.AccessControl }
[pscustomobject]@{
Id = $detail.Id
DisplayName = $detail.DisplayName
IsPublished = $detail.IsPublished
Access = $ac
ScopeLabel = (Convert-AccessControlLabel -AccessControl $ac)
PublicUrl = $detail.PublicUrl
}
}
# 3) 証跡として保存
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$audit | Export-Csv -NoTypeInformation -Encoding UTF8 -Path ".\\BookingsAccessAudit-$timestamp.csv"
「誰でも公開」なのに社外が予約できない?判定を狂わせる要因
accessControl で公開範囲を判別できても、実際のアクセス可否はテナント側の統制や追加オプションで変わることがあります。ここを押さえておくと「設定は合っているのに動かない」系トラブルの切り分けが速くなります。
組織全体の設定で “外部からの共有 Bookings をブロック” している
Microsoft 365 管理センターの Shared Bookings の粒度設定には「組織外からの共有 Bookings をブロック(認証済みの組織内ユーザーのみに制限)」といった項目があります。テナント側でここが有効だと、各 Bookings ビジネスを unrestricted にしても社外アクセスが想定どおりにならないことがあります。
ワンタイムパスコード(OTP)など、追加の本人確認を要求している
bookingPageSettings には enforceOneTimePassword など、予約作成時の追加条件に関する設定が含まれます。unrestricted は「匿名アクセス可能」に近い意味ですが、「完全な無条件」ではないことがあります。
条件付きアクセスや外部コラボレーション設定の影響
組織のセキュリティ要件によっては、サインインが発生する経路で条件付きアクセス(MFA 必須など)がかかったり、ゲストの扱いが制限されることがあります。公開範囲の判定(accessControl)と、認証ポリシーによる制限は層が違うため、切り分けは「公開範囲 → テナント設定 → 認証ポリシー」の順で進めると迷子になりにくいです。
監査・運用のおすすめパターン
「API で取れる=すべて自動化できる」と考えると、権限や仕様差分で運用が破綻しやすい領域です。現実的には、次のように役割分担すると安定します。
| やりたいこと | おすすめ手段 | 理由 |
|---|---|---|
| 現在の公開範囲を定期的に点検したい | Graph / PowerShell で accessControl を取得して台帳化 | API で機械的に比較でき、設定ドリフトに強い |
| 外部公開の可否を “実際の挙動” で確認したい | 匿名ブラウザで publicUrl にアクセスしてサインイン要求をチェック | テナント側ブロックや認証ポリシーを含めた外形監視になる |
| 設定を統一したい(誰でも or 組織内のみ) | まず UI で標準化 → その後に監査スクリプトで逸脱検知 | 「更新 API の仕様差」や権限差を吸収しやすい |
補足:設定を更新したい場合の注意点(API/PowerShell)
「判別できたなら、ついでに統一も自動化したい」と考える方も多いですが、更新系は読み取りより罠が増えます。たとえば Graph の Update bookingBusiness は更新可能プロパティが明示されており、メールアドレスや表示名は PATCH では更新できない旨も注意されています。
一方で PowerShell の Update-MgBookingBusiness には -BookingPageSettings パラメータがあり、構造上は accessControl を渡せます。
ただし「ドキュメント上の更新対象に含まれていない/環境によって 403 や反映遅延が出る」といった報告もあるため、いきなり本番一括変更に振り切るのではなく、まずは UI で標準化し、API は監査と逸脱検知に使う運用が安全です。
まとめ:見るべきは isPublished ではなく accessControl
isPublishedとpublicUrlは「予約ページが公開されているか」を示す指標で、公開範囲までは分からない- 公開範囲は
bookingPageSettings.accessControl(unrestricted/restrictedToOrganization)で判別できる - 実際の社外アクセス可否は、テナントの Shared Bookings 統制や OTP、認証ポリシーでも変わる
- 運用は「UIで標準化 → APIで監査(台帳化・逸脱検知)」にすると事故が減る

コメント