mcpField
E
ensure-pipelines-host

ensure-pipelines-host

github.com/microsoftクラウド・DevOps1.1k154 回インストール今日更新
リポジトリ

ensure-pipelines-host について

ensure-pipelines-host は Power Platform Pipelines に必要なホストを検出・設定するスキルです。Power Platform のデプロイ環境を管理する人向けに、Power Apps の解決順序に沿って既存ホストを探し、プロビジョニングやバインドには確認を求めます。

主な機能

  1. 01解決順序に沿った Pipelines ホスト検出
  2. 02Platform Host と Custom Host の識別
  3. 03既存ホストの再利用
  4. 04確認を伴うホスト設定経路
  5. 05チェック結果のキャッシュと稼働確認

活用シーン

  1. 01ソース環境に紐づくホストの特定
  2. 02ホストがない場合の設定方法の選択
  3. 03キャッシュ済みホストへのアクセス確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/microsoft/power-platform-skills --skill ensure-pipelines-host

インストール後、Claude Code で/ensure-pipelines-hostを入力して読み込まれたか確認します。

同梱ファイルscripts/validate-ensure-host.js

詳細

プラグインの確認:node "${PLUGIN_ROOT}/scripts/check-version.js" を実行します。メッセージが出力された場合は、続行する前にユーザーに表示してください。

ensure-pipelines-host

対象範囲: ソース環境にホストが関連付けられていない場合、このスキルは再利用できる既存のホスト(Custom または PE)を検出します。NoHost 状態の場合は、次の 3 つのプロビジョニング方法を提示します。新しい Platform Host(推奨。冪等で、所要時間は約 3~5 分)、新しい Custom Host(管理者のみ。所要時間は約 5~10 分)、または PPAC での手動プロビジョニング(代替手段)です。エンドポイント名、テンプレート名、BAP オーディエンスなどの実装の詳細は、以下の Phase 4.0/4.A/4.C に記載しています。ユーザー向けの説明では、結果に焦点を当てます。

Power Platform Pipelines にはホスト環境が必要です。これは Power Platform Pipelines マネージドソリューションがインストールされた Dataverse 環境で、パイプライン、ステージ、実行履歴、成果物が保存されます。既存の setup-pipeline および deploy-pipeline スキルは、ホストがすでに構成されていることを前提としています。このスキルは、その不足を補います。

判定根拠(信頼できる情報源)

この計画は、優先順位順に次の 3 つの主要な情報源に基づいています。

  1. useGetOrCreatePlatformEnvironment.v4.ts(Microsoft 内部のクライアントソース。power-platform-ux/packages/powerapps-appdeployment-ux/src/hooks/v4/)。Platform Environment のプロビジョニングに関する正確な HTTP 契約(エンドポイント、本文、ヘッダー、ポーリング)を定義しています。
  2. ProjectHostProvider.tsx(同じリポジトリの src/components/ProjectHostProvider/)。ソース環境に対するプロジェクトホストとなる環境を特定するために、Power Apps UI が使用する正確な解決順序を定義しています。このスキルも UI と一致するよう、同じ順序を踏襲します。
  3. eng.ms の createcustompipelineshost(Microsoft 内部)。Pipelines アプリが事前インストールされた D365_ProjectHost 組織テンプレートを、標準の環境作成 API を通じて呼び出せる Custom Host の高速な作成方法について説明しています。

公開されている Microsoft Learn(learn.microsoft.com/power-platform/alm/{platform-host-pipelines, custom-host-pipelines, set-a-default-pipelines-host})には、同じフローがユーザー向けに説明されています。ユーザーにもなじみのある動作の根拠として、こちらを参照しています。PipelinesDeployScenario.har と Pipelines.har の HAR ファイルでは、読み取り側の呼び出しが確認できます。

テナントで取り得る 3 種類のホスト形態

形態作成方法保存場所組織テンプレート
Platform Host (PE)getOrCreate BAP 呼び出しによる自動プロビジョニング(または make.powerapps.com の Pipelines ページに初めて移動した際の副次的な処理)。環境ピッカーには表示されません。テナントごとに 1 つです。テナントのホーム地理的リージョンにある、Microsoft 管理の Dataverse 環境D365_1stPartyAdminApps
Custom Host管理者が PPAC の Deployments → New custom host から作成するか、D365_ProjectHost テンプレートを指定した標準の環境作成 API で作成するか、既存の Dataverse 環境に Power Platform Pipelines アプリをインストールして作成します。テナント内の通常の Dataverse 環境D365_ProjectHost(または既存の環境にアプリをインストール)
ソース環境にホストが関連付けられていないテナントがこの環境から Pipelines を使用したことがありません。——

現在の discover-pipelines-host.js は、テナントレベルの DefaultCustomPipelinesHostEnvForTenant 設定のみを確認します。これは数あるシグナルのうちの 1 つです。このスキルでは、完全な解決順序を実装します。

解決順序(ProjectHostProvider.tsx を踏襲)

これは判断の基盤となる決定木です。Power Apps UI が実行する処理です。このスキルも UI と一致するよう、同じ順序を再現します。

┌─────────────────────────────────────────────────────────────────────┐
│ 1. GetOrgDbOrgSetting('ProjectHostEnvironmentId') on source env     │
└──────────────────────────┬──────────────────────────────────────────┘
                           │
            ┌──────────────┴───────────────┐
            │ value present                │ value empty
            ▼                              ▼
┌───────────────────────┐         ┌────────────────────────────┐
│ 2. Resolve env via    │         │ 5a. Tenant-wide search:    │
│    BAP GET            │         │   list envs + per-env      │
│    /environments/{id} │         │   /deploymentpipelines     │
└───────┬───────────────┘         │   probe.                   │
        │                         │                            │
   environmentSku?                │   - 1 Custom Host found →  │
        │                         │     AvailableUnboundCustom │
   ┌────┴────────────┐            │     (3.C-pre)              │
   │ Platform        │            │   - >1 Custom Hosts →      │
   │                 │            │     MultipleUnboundCustom  │
   │                 │            │     (3.C-pre')             │
   │                 │            │   - PE only →              │
   │                 │            │     PlatformHostExists-    │
   │                 │            │     Unbound (3.C-pre'')    │
   │                 │            │   - none → NoHost (3.C)    │
   │                 │            │                            │
   │                 │            │ 5b. Decision tree paths    │
   │                 │            │   for create-new (3.C):    │
   │                 │            │   - Platform getOrCreate   │
   │                 │            │     (fast-path, no admin)  │
   │                 │            │   - Custom D365_ProjectHost│
   │                 │            │     (fast-path, admin)     │
   │                 │            │   - Manual app install     │
   │                 │            │   - Manual PPAC create     │
   │                 │            └────────────────────────────┘
   ▼                 │
┌──────────────┐     │
│ 3. Check     │     │ environmentSku ≠ Platform (Custom Host)
│  Default-    │     ▼
│  Custom-     │   ┌──────────────────────────────┐
│  Pipelines-  │   │ 4. Use the Custom Host       │
│  HostEnv-    │   │    directly. Skip default-   │
│  ForTenant   │   │    custom check.             │
└──────┬───────┘   └──────────────────────────────┘
       │
   ┌───┴────────────────────────┐
   │ admin set a custom default │
   │                            │
   ▼                            ▼
┌─────────────────┐  ┌─────────────────────────┐
│ default ==      │  │ default !=              │
│ org setting?    │  │ org setting             │
│                 │  │                         │
│ → use default   │  │ → CannotRedirect ERROR  │
│   custom        │  │   (user locked to PE    │
└─────────────────┘  │   but admin overrode    │
                     │   at tenant scope)      │
                     └─────────────────────────┘

   if no admin default → use PE

出典:ProjectHostProvider.tsx の 100~213 行(orgSetting の取得 → defaultCustomPipelinesHost の取得 → finalProjectHostEnvironmentId の解決)。

このスキルで行わないこと

以下は意図的な非目標です(それぞれ、厳しい制約または影響範囲が大きく破壊的な操作に基づいています。下記の 設計上の制約 を参照してください)。

  • 何も黙ってプロビジョニングしません。 環境を作成する操作や、ソース環境をホストにバインドする操作では、テナント名とテナント ID を確認のために表示したうえで、ユーザーの明示的な確認が必要です。PE はテナントごとに単一で、管理者でも削除できないため、Phase 4.0 の実行前確認ゲートが、誤ったテナントへのプロビジョニングに対する主な緩和策です。getOrCreate エンドポイントは冪等です。PE がすでに存在するテナントで呼び出すと、重複を作成せずに既存の PE を返します。
  • Force Link は呼び出しません。 環境を別のホストに再バインドするためには使用しません。Force Link は破壊的な操作です(以前のホストにある既存のパイプラインに、メーカーがアクセスできなくなります)。別個の確認ゲートで保護されており、ユーザーが明示的に「rebind」と言った場合にのみ実行できます。
  • テナントレベルの DefaultCustomPipelinesHostEnvForTenant 設定は変更しません。 この設定は実質的に元に戻せない操作です(以前の既定値にある既存のパイプラインにアクセスできなくなります。learn.microsoft.com/power-platform/alm/set-a-default-pipelines-host を参照してください)。対象範囲外です。
  • 環境は削除しません。
  • ProjectHostEnvironmentId は直接書き込みません。 バインドは、文書化された Pipelines フローを通じて、ホストに deploymentenvironment レコードを作成することで確立します。組織設定に直接書き込むと、検証を回避することになります。

認証戦略:PAC を優先し、BAP にフォールバック(--source auto)

読み取り側の検出(Phase 2 の解決順序、環境一覧、環境 ID による検索)は、既定で --source auto を使用します。

  1. BAP トークンが指定されている場合は、まず BAP の環境一覧/環境 GET を試します(lastModifiedTime、permissions、tenantId など、より詳細なデータを取得できます)。
  2. HTTP 401 または 403 の場合は、pac-bap-shim.js を介して pac admin list --json にフォールバックします。 PAC は BAP 上で独自のファーストパーティ クライアント ID 権限を持っており、Az CLI では常に継承されるとは限りません(2026-04-28 に検証済み:デモテナント D365DemoTSCE53051106 は、オーディエンス クレームが正しくても BAP に対する Az トークンを拒否します)。
  3. BAP トークンが指定されていない場合は、最初から PAC を使用します。

PAC shim は BAP 形式のデータを返すため、後続のコード(SKU フィルター、ランキング、分類)は変更されません。PAC が提供しないフィールド(tenantId、lastModifiedTime、permissions、isManaged)は null として返されます。ホスト検出に不可欠なフィールドはありません。また、pac admin list には Platform SKU の環境が含まれないため、PAC では Platform Hosts(PE)も表示されません。PE の検出には、BAP トークンが有効な状態で --source bap を指定する必要があります。

書き込み側の操作(provision-custom-host.js の環境作成 POST、ライフサイクル操作のポーリング)には、引き続き BAP が必要です。適切なオーディエンスを持つ Az CLI トークンは、環境一覧の呼び出しが失敗する場合でも、これらの操作では通常機能します。これは、BAP RP が読み取りとは異なるポリシーを操作に適用するためです。provision-custom-host.js が 401 を返した場合、ユーザーは対象テナントにサービス プリンシパルを登録する必要があります(または PPAC UI のフォールバック パス 4.C を使用します)。

設計上の制約

  1. PE が選択された場合、既存の PE か新たにプロビジョニングされた PE かを問わず、JIT プロビジョニングが必要です。 ProjectHostProvider.tsx(232~240 行目)のコメントより:「Platform Environment の場合、ユーザーはまだその環境にプロビジョニングされていない可能性があるため、BAP はその環境を検出できません。そのため、ユーザーの JIT をトリガーできるよう、この最初のリクエストでは getOrCreate 呼び出しから取得した組織 URL を使用します。」 Phase 2 で既存の PE が検出され、ユーザーがそれを選択した場合(Phase 3.A)、または Phase 4.0 で getOrCreate によって新しい PE がプロビジョニングされた場合、Phase 5 の instanceApiUrl に対する WhoAmI 呼び出しにより、以降のホスト操作より前に JIT がトリガーされます。(Custom Host の場合は、呼び出し元が構成上アクセス権を持っています。)
  2. CannotRedirect は理論上の例外ではなく、実際に発生する終端状態です。 ProjectHostEnvironmentId(ソース環境の組織設定)が PE を指している一方で、DefaultCustomPipelinesHostEnvForTenant(管理者テナント設定)が別の場所を指している場合に発生します。この状態をスキルで検出し、固有のエラーとして通知する必要があります。何も通知せずに処理を続けると、パイプライン操作が誤ったホストに対して実行されます。
  3. Custom Host の高速パスは管理者専用です。 PPAC の New custom host フローは DeploymentHubCreatePipelinesHostForAdminsOnly によって制限されており、グローバル管理者/Power Platform 管理者/Dynamics 管理者にのみ表示されます(eng.ms のドキュメント)。BAP 環境作成 API にも同等の特権が必要です。非管理者には 403 が返されます。スキルは事前確認のうえでその旨を通知し、手動のパスへスムーズにフォールバックします。
  4. BAP 環境 GET の 404 は、原因を特定できません。 PowerPipelines_PE_Knowledge.md §6.A にあるとおり、削除済み、無効、PE なし、アクセス権なしのいずれの場合も、区別されずに 404 が返されます。単一の 404 だけで「ホストが存在しない」と判断することはありません。操作に進む前に、環境一覧と組織設定で照合します。
  5. 各環境は一度に 1 つのホストにのみバインドできます。 再バインドには Force Link が必要で、以前のホストに破壊的な影響を与えます。これは対象外です(対象外項目を参照)。
  6. スキルはユーザーの OAuth コンテキストで実行されます。Power Apps UI と同じスコープおよびオーディエンスを使用します。BAP 呼び出しでは https://service.powerapps.com/ オーディエンスを使用します。

getOrCreate の冪等性 — BAP の getOrCreate エンドポイントは冪等です(既存の PE の場合は 200 と provisioningState === 'Succeeded' を返し、新しい PE の場合は 202 とライフサイクル操作を返します)。Phase 4.0 ではこの性質を活用します。PE がすでにあるテナントに対して getOrCreate を呼び出しても安全で、既存の PE が返されるだけです。provision-platform-host.js ヘルパーは戻り値の alreadyExisted: true | false フラグによってその違いを示します(テレメトリブロック docs/alm/last-host-check.json に platformHostAlreadyExisted として記録されます)。

前提条件

  • PAC CLI にログイン済みであること(pac env who が成功すること)
  • Azure CLI にログイン済みであること(az account show が成功すること)
  • ソース Dataverse 環境の URL があること(Power Pages プロジェクトから呼び出す場合は powerpages.config.json から読み取ります。それ以外の場合は引数として渡します)
  • Phase 4 の管理者専用パスを使用する場合、呼び出し元がグローバル管理者/Power Platform 管理者/Dynamics 管理者であること(権限がない場合、スキルが検出し、403 を明確に通知します)

フェーズ

フェーズ 1 — 前提条件を検出し、テナントのコンテキストを収集する

このフェーズの開始時に、すべてのタスクをあらかじめ作成してください。

作成するタスク:

  1. "ローカルキャッシュを確認し、前提条件を検出する"
  2. "解決順序を実行してホストを特定する"
  3. "アクションをユーザーに確認する"
  4. "選択したパスを実行する"
  5. "JIT プロビジョニングを行い、ホストを検証する"
  6. "ホストチェックのアーティファクトを書き込む"

手順:

  1. ローカルキャッシュの高速パス。 docs/alm/last-host-check.json が存在し、かつ Date.now() - Date.parse(checkedAt) < cacheMaxAgeMs(デフォルトは 24h。--cacheMaxAgeHours で設定可能)の場合:

    • キャッシュされた finalHostEnvUrl のオリジンに対する HOST_TOKEN を取得します。
    • 1 回の低コストなプローブ:GET {finalHostEnvUrl}/api/data/v9.0/solutions?$filter=uniquename eq 'msdyn_AppDeploymentAnchor'&$select=version&$top=1(1 回のラウンドトリップで Pipelines がインストールされていることを確認し、バージョンも取得します)
      • 200 → キャッシュは有効です。キャッシュファイルから RESOLUTION を設定します。ACTION_TAKEN = "none" を設定します。フェーズ 2~5 をスキップし、「キャッシュ済みホストを再利用した」という概要とともにフェーズ 6 に進みます。
      • 404 / 403 / タイムアウト / ネットワークエラー → キャッシュが古いか、アクセスできなくなっています。手順 1 に進み、すべての解決を実行します。失敗として扱わないでください。環境の削除や権限の変更後に古いキャッシュが残ることは想定内です。
    • ファイルが存在しない、形式が不正、cacheMaxAgeMs より古い、または ready: false を含む場合は、手順 1 に進みます。
    • --no-cache が指定されている場合(CI / スモークテストで使用)は、この手順全体をスキップします。
  2. verify-alm-prerequisites.js を実行します:

    node "${PLUGIN_ROOT}/scripts/lib/verify-alm-prerequisites.js"
    

    .envUrl(devEnvUrl)、.token(DEV_TOKEN)、.userId、.tenantId、.organizationId を取得します。認証に失敗した場合は、スクリプトの対処方法のメッセージとともに停止します。

  3. detect-project-context.js を実行します(非致命的です。このスキルは Power Pages プロジェクト以外でも有効です):

    node "${PLUGIN_ROOT}/scripts/lib/detect-project-context.js"
    

    メッセージ表示用に .siteName と .solutionManifest を取得します。

  4. BAP トークンを取得します(Dataverse とは対象オーディエンスが異なります):

    az account get-access-token --resource "https://service.powerapps.com/" --query accessToken -o tsv
    

    BAP_TOKEN として保存します。これは、フェーズ 2 および 4 におけるすべての BAP /providers/Microsoft.BusinessAppPlatform/... 呼び出しで使用します。

3a. テナントの表示名を解決する(1 回限り、ベストエフォート)。フェーズ 1.4 およびフェーズ 4.0 では、ユーザーが対象テナントを確認できるように、テナント GUID とともに人間が読めるテナント名を表示します。Microsoft Graph の組織エンドポイントから取得します:

az rest --method GET --url "https://graph.microsoft.com/v1.0/organization?$select=id,displayName" --resource "https://graph.microsoft.com/" --query "value[0].displayName" -o tsv

TENANT_DISPLAY_NAME として保存します。失敗した場合(Graph の権限がない、ネットワークエラー、マルチテナントの曖昧さ)は、TENANT_DISPLAY_NAME = null にフォールバックして続行します。フェーズ 1.4 / 4.0 のプロンプトでは、表示名が null の場合にテナント GUID のみが表示されます。

🚦 ゲート(同意 · ensure-pipelines-host:1.4.tenant-identity): ホスト検出を行う前に、テナントの表示名 + テナント GUID + 開発環境 URL を表示します。これは、誤ったテナントを対象にしないための最初のガードです。キャンセルすると、BAP / Dataverse の呼び出しを行わずに正常に終了します。

  1. テナント ID の確認ゲート。 AskUserQuestion を使って、次の内容をユーザーに提示します:

    "テナント {TENANT_DISPLAY_NAME}({tenantId})、組織 {organizationId}、開発環境 {devEnvUrl} の Pipelines ホスト設定を確認します。続行しますか? 1. はい / 2. キャンセル"

    (TENANT_DISPLAY_NAME が null の場合は、太字のテナント名部分を省略し、テナント GUID から始めます。)

    これは、誤ったテナントに対する操作を防ぐ同意ゲートの最初のものです。

フェーズ 1.5 — 現在の Pipelines ホストのドキュメントに基づいて確認する

参照:${PLUGIN_ROOT}/references/alm-docs-grounding.md

このステップは約30秒以内に完了してください。MCP の検索または取得でエラーが発生した場合は、1行のメモを記録して続行してください。このスキルはオフラインでも実行できる必要があります。

  1. microsoft_docs_search を次のクエリで実行します:Power Platform Pipelines host environment Platform Host Custom Host。
  2. microsoft_docs_fetch を使用して、https://learn.microsoft.com/en-us/power-platform/alm/pipelines(およびホストの設定、既定のカスタムホストの構成、または管理者ロールの要件に関する関連ページを最大1件)を並列で取得します。
  3. Microsoft Learn が現在説明している Platform と Custom Host のトレードオフ、解決順序(org-db 設定 → BAP 環境メタデータ → テナントの既定値)、管理者ロールの要件について、1段落の要約を作成します。このスキル独自の 解決順序 セクションおよび ${PLUGIN_ROOT}/references/cicd-pipeline-patterns.md と比較し、相違点(例:新しい Platform-Host SKU、既定のカスタムホスト設定名の変更、新しいテナントポリシー制御)があれば明示します。
  4. この要約をフェーズ 2 以降の判断に反映します。スキルの動作を黙って変更しないでください。フェーズ 3(ユーザーに操作を確認)より前に、相違点をソフト警告としてユーザーに提示します。
フェーズ 2 — 解決順序を実行してホストを特定する

このフェーズは読み取り専用です。ユーザー確認フェーズで分岐処理に使用する RESOLUTION オブジェクトを生成します。

このフェーズは ProjectHostProvider.tsx を正確に反映します。そのフック内の useState 変数は、RESOLUTION の次のフィールドに対応します。

TS 変数対応するフィールド
orgSetting.orgDbOrgSettingValueorgSettingHostEnvId
initialProjectHostEnvironmentId(同じ)
isInitialHostPlatformEnvironmentisPlatform
defaultCustomPipelinesHosttenantDefaultCustomHostEnvId
finalProjectHostEnvironmentIdfinalHostEnvId
projectHostStatusstatus

手順:

  1. 組織設定の確認(tsx の103行目にある useGetOrgDbOrgSetting('ProjectHostEnvironmentId') を反映)。新しいヘルパー check-env-host-binding.js:

    POST {devEnvUrl}/api/data/v9.0/GetOrgDbOrgSetting
    Authorization: Bearer {DEV_TOKEN}
    Body: { "SettingName": "ProjectHostEnvironmentId" }
    
    • SettingValue が空 → 現在のバインドはありません。手順4に進みます。
    • 空でない → orgSettingHostEnvId として保存します。手順2に進みます。
  2. BAP 経由で環境を解決(tsx の483行目にある useGetEnvironmentByName(initialProjectHostEnvironmentId) を反映)。新しいヘルパー resolve-env-by-id.js:

    GET https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/environments/{envId}?api-version=2020-06-01&$expand=properties.linkedEnvironmentMetadata,properties.permissions
    Authorization: Bearer {BAP_TOKEN}
    
    • 200 → environmentSku、displayName、linkedEnvironmentMetadata.instanceApiUrl、linkedEnvironmentMetadata.instanceUrl を取得します。RESOLUTION.isPlatform = (environmentSku === 'Platform') に設定します。
    • 404 → 対応する操作の前に原因を特定します(制約5)。list-tenant-envs.js(手順5)を実行し、環境が一覧にあるか確認します。
      • 一覧にある → ユーザーにはアクセス権がありません。RESOLUTION.status = "PermissionDenied" に設定し、ユーザーに提示して停止します。
      • 一覧にない → 環境は実際に削除または無効化されています。RESOLUTION.status = "OrgSettingStale" に設定し、ユーザーに ProjectHostEnvironmentId をクリアして再実行するよう推奨し、停止します。
    • 403 → RESOLUTION.status = "PermissionDenied" に設定して停止します。
  3. isPlatform === true の場合、既定のカスタムテナント設定の確認(tsx の148~213行目)を反映します。既存の discover-pipelines-host.js を再利用します。

    node "${PLUGIN_ROOT}/scripts/lib/discover-pipelines-host.js" \
      --envUrl "{devEnvUrl}" --token "{DEV_TOKEN}" --userId "{userId}"
    
    • found: false → テナントに管理者の既定カスタムホストがありません。finalHostEnvId = orgSettingHostEnvId(PE)に設定します。RESOLUTION.status = "AvailableUsingPlatformHost" に設定します。
    • found: true かつ hostEnvUrl が orgSettingHostEnvId と一致 → 管理者の既定値と組織設定が一致しています。finalHostEnvId = orgSettingHostEnvId に設定します。RESOLUTION.status = "AvailableUsingCustomHostByAdminDefault" に設定します。
    • found: true かつ hostEnvUrl が orgSettingHostEnvId と一致しない → CannotRedirect(制約3)です。RESOLUTION.status = "CannotRedirect" に設定し、両方の URL を取得します。具体的なエラーメッセージを表示して停止します。解決できるのは管理者のみです。

    isPlatform === false(Custom Host)の場合:そのまま使用します。finalHostEnvId = orgSettingHostEnvId に設定します。RESOLUTION.status = "AvailableUsingCustomHost" に設定します。手順4~5をスキップし、手順6に進みます。

  4. 組織設定がない場合 → NoHost と宣言する前にテナント全体を検索します。 ソース環境がバインドされていなくても、テナント内に利用可能なカスタムホストがすでに存在する可能性があります(管理者が作成したもの、または別のプロジェクトでこのスキルを以前に実行した際に作成されたもの)。作成を提案する前に、必ずインベントリを確認してください。

  5. テナント環境のインベントリ作成と Pipelines の存在確認(判断用 — RESOLUTION.status に反映されます)。新しいヘルパー list-tenant-envs.js:

    ステップ 5a — 環境の一覧表示:

    GET https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/environments?api-version=2020-06-01&$expand=properties.linkedEnvironmentMetadata
    Authorization: Bearer {BAP_TOKEN}
    

    各環境について { envId, displayName, environmentSku, instanceApiUrl, isManaged, hasDataverse: !!instanceApiUrl } を取得します。

    ステップ 5b — 環境ごとの Pipelines の存在確認(並列実行、同時実行数は最大 10。SKU フィルターと maxEnvsToProbe の上限で制限):

    事前フィルター(大規模なテナントですべての環境を確認するのを避けます — 調査では環境が 1000 以上あるテナントが確認されています):

    • Dataverse がない環境(linkedEnvironmentMetadata.instanceApiUrl == null)はスキップします。
    • --skus に含まれない環境はスキップします(既定値:Production,Sandbox — どちらも Phase 4.B の既存環境へのインストールで Pipelines アプリの有効なホストになります)。PE は常に environmentSku === 'Platform' として報告されるため、対象に含めます。Trial 環境を含めるには --skus Production,Sandbox,Trial を指定します(4.B によるアプリのインストール対象にはなりますが、4.A による環境の作成対象にはなりません — Trial ライセンスのテナントでは、環境作成時に NotEnoughCapacity_HasTrialLicense が返されます)。
    • 残りを lastModifiedTime の降順で並べ替えます。
    • --maxEnvsToProbe(既定値は 50)までに制限します。同時実行数 10 で 5 秒未満で処理でき、一般的なテナントの 80% をカバーします。
    • 上限に達してもホストが見つからなかった場合は、警告を表示します:"Scanned N of M envs (filter: Production+Sandbox, sorted by lastModifiedTime). Pass --maxEnvsToProbe N+ or --skus Production,Sandbox,Trial to widen."

    確認クエリ(1 回のクエリで存在確認とバージョン取得の両方を行います):

    GET {instanceApiUrl}/api/data/v9.0/solutions?$filter=uniquename eq 'msdyn_AppDeploymentAnchor'&$select=uniquename,version&$top=1
    Authorization: Bearer {HOST_TOKEN-per-env}
    OData-Version: 4.0
    OData-MaxVersion: 4.0
    
    • 200 で value.length === 1 → Pipelines がインストールされています。value[0].version を pipelinesSolutionVersion として取得します。カスタムホスト候補(または environmentSku === 'Platform' の場合は PE)としてマークします。
    • 200 で value.length === 0 → Pipelines はありません。Dataverse があり、呼び出し元にアクセス権がある場合は、eligible-for-app-install としてマークします。
    • 404 → エンティティは存在しますが、Dataverse に到達できないか、URL が正しくありません。候補ではないものとして扱います。
    • 403 → 呼び出し元にアクセス権がありません。ホスト候補としてカウントしないでください。警告専用の inaccessibleEnvs[] に追加します。
    • タイムアウト/5xx → 警告に記録し、候補ではないものとして扱います。再試行しないでください。

    deploymentpipelines?$top=0 を使わない理由は何ですか? 適切にインストールされたホストでも、Dataverse は deploymentpipelines に対する $top=0 を HTTP 400「Invalid value for $top query option」で拒否します(2026-04-28 に pascalepipelineshost.crm.dynamics.com で確認済み)。solutions?$filter=uniquename eq 'msdyn_AppDeploymentAnchor' クエリが適切な軽量プローブです。1 回の通信で済み、$top=1 ではレート制限の懸念がなく、必要なバージョンも返されます。

    ステップ 5b のトークン戦略:環境のオリジンごとに 1 つの HOST_TOKEN を、az account get-access-token --resource "{origin}" で取得し、実行中はメモリ内にキャッシュします。リソースが存在しない場合(環境が削除されている場合)を除き、トークン取得で失敗することはありません。その場合はスキップします。

    ステップ 5 の出力(RESOLUTION.candidates):

    {
      existingCustomHosts: [{ envId, instanceApiUrl, displayName, environmentSku, pipelinesSolutionVersion }, ...],
      existingPlatformHost: { envId, instanceApiUrl, displayName, ... } | null,  // at most one
      eligibleForAppInstall: [{ envId, instanceApiUrl, displayName }, ...],
      inaccessibleEnvs: [{ envId, displayName, reason: "403" | "timeout" }, ...]
    }
    

    判定ロジック(RESOLUTION.status を設定します):

    • existingCustomHosts.length === 1 → RESOLUTION.status = "AvailableUnboundCustomHost"。暫定的に、そのホストを finalHostEnvId / finalHostEnvUrl に設定します(Phase 3.C-pre で確認します)。
    • existingCustomHosts.length > 1 → RESOLUTION.status = "MultipleUnboundCustomHosts"。Phase 3.C-pre' でユーザーに選択してもらいます。
    • existingCustomHosts.length === 0 AND existingPlatformHost !== null → RESOLUTION.status = "PlatformHostExistsUnbound"。Phase 3.C-pre'' で PE の使用を提案します(作成は不要です。テナントにはすでに PE があります)。注:ソース環境と PE の実際のバインドは、setup-pipeline がソース環境を deploymentenvironments に登録する際に、文書化されている Pipelines のフローを通じて行われます。これは Custom Host と同じです。
    • すべて 0 → RESOLUTION.status = "NoHost"。Phase 3.C の判断ツリー(新規作成)に進みます。

    自己検出に関する注記: このスキルの以前の実行で作成された Custom Host(Phase 4.A の D365_ProjectHost テンプレート)には、テンプレートの一部として Pipelines ソリューションがインストールされています。管理者が作成したホストとまったく同じシグナルで existingCustomHosts に表示されます。自分で作成したホストにマーカーを付ける必要はありません。Pipelines ソリューションがインストールされているというシグナルだけで十分です。

  6. Pipelines ソリューションのバージョン確認(finalHostEnvId が判明しており、手順 5b ですでに設定されていない場合のみ)。解決済みのホストの instanceUrl で実行します。

    GET {hostEnvUrl}/api/data/v9.0/solutions?$filter=uniquename eq '{PIPELINES_SOLUTION_UNIQUE_NAME}'&$select=version,installedon
    Authorization: Bearer {HOST_TOKEN}
    

    HOST_TOKEN は {hostEnvUrl origin} を対象に az account get-access-token --resource で取得します。

    ソリューションの正確な一意の名前は未確定です。未解決の項目を参照してください。現時点での仮説は msdyn_AppDeploymentAnchor です。PIPELINES_SOLUTION_VERSION を記録します。クエリ結果が空の場合(PE 以外のホストにソリューションがない場合)は、RESOLUTION.status = "HostWithoutPipelines" とし、Phase 3.D のパスに進みます。

調査結果をユーザーに報告します。

"テナント {tenantId} のホスト状態:{RESOLUTION.status}。{ステータスに応じた概要行}"

Phase 3 — ユーザーにアクションを確認

RESOLUTION.status に応じて分岐します。各分岐の最後は、ホストがすでに使用可能な場合は 「Phase 5 に進む」、それ以外の場合は 「選択したパスで Phase 4 に進む」 となります。

3.A — ステータス AvailableUsingCustomHost / AvailableUsingCustomHostByAdminDefault / AvailableUsingPlatformHost

ホストは確立されています。確認して先に進みます。

"既存のホストが見つかりました:{finalHostEnvUrl}({RESOLUTION.status}、Pipelines ソリューション v{PIPELINES_SOLUTION_VERSION})。このホストを使用しますか?

  1. はい — 検証に進む
  2. キャンセル"
  • はい → ACTION_TAKEN = "none" を設定し、Phase 5 に進みます。
  • キャンセル → 終了します。
3.B — ステータス CannotRedirect

ロックされた状態です。続行できません。

"続行できません:{devEnvUrl} の ProjectHostEnvironmentId は Platform Host({orgSettingHostEnvId})を指していますが、テナント管理者は DefaultCustomPipelinesHostEnvForTenant に別の環境({tenantDefaultCustomHostEnvId})を設定しています。Pipelines UI では、この環境を管理者が選択した環境にリダイレクトできません。解決するには、Power Platform 管理者が(a)テナントの既定値をクリアするか、(b)この環境の組織設定を更新する必要があります。終了します。"

停止します。

3.C-pre — ステータス AvailableUnboundCustomHost(既存のカスタムホストが1つ見つかった場合)

テナントには、Pipelines がインストールされたカスタムホストがちょうど1つあります。ソース環境はまだこのホストにバインドされていませんが、setup-pipeline がホストの deploymentenvironments テーブルにソース環境を登録すると、自動的にバインドされます。再利用すれば、ホストの重複作成を避けられます。

「テナント {tenantId} に既存のカスタムホストが見つかりました。

  • 表示名: {displayName}
  • URL: {instanceApiUrl}
  • Pipelines ソリューション: v{pipelinesSolutionVersion}

ソース環境 {devEnvUrl} はまだこのホストにバインドされていません。このホストに対して setup-pipeline を初めて実行したときに、自動的にバインドされます。このホストを使用しますか?

  1. はい — 既存のホストを使用する(推奨。重複を避けられます)
  2. いいえ — 新規作成の判断ツリーを表示する(Phase 3.C)
  3. キャンセル」
  • はい → finalHostEnvUrl/Id を設定し、ACTION_TAKEN = "reuse-existing-custom" として、Phase 5 に進みます。
  • いいえ → Phase 3.C の NoHost 判断ツリーに進みます(別のホストの作成も引き続き可能です)。
  • キャンセル → 終了します。
3.C-pre' — ステータス MultipleUnboundCustomHosts(既存のカスタムホストが複数見つかった場合)

「テナント {tenantId} に、Pipelines がインストールされた既存のカスタムホストが {N} 個見つかりました。使用するホストを選択するか、新規作成してください。

  1. {host[0].displayName}({host[0].instanceApiUrl}、Pipelines v{host[0].pipelinesSolutionVersion})
  2. {host[1].displayName}(...) ... N. ... N+1. 代わりに新しいカスタムホストを作成する — Phase 3.C の判断ツリーに進む N+2. キャンセル」
  • 1..N を選択 → 選択したホストから finalHostEnvUrl/Id を設定し、ACTION_TAKEN = "reuse-existing-custom" として、Phase 5 に進みます。
  • N+1 → Phase 3.C の NoHost 判断ツリーに進みます。
  • N+2 → 終了します。
3.C-pre'' — ステータス PlatformHostExistsUnbound(PE はすでに存在し、カスタムホストはない場合)

テナントには PE がすでに存在します(誰かが Pipelines ページに初めて移動したときに、自動的にプロビジョニングされます)。スコープに関する決定に従い、このイテレーションでは PE を自動プロビジョニングしませんが、すでに存在する場合は、その使用を提案します。

「テナント {tenantId} には、Platform Host({instanceApiUrl}、Pipelines v{pipelinesSolutionVersion})がすでにあります。ソース環境はまだこのホストにバインドされていません。このホストを使用しますか?

  1. はい — 既存の Platform Host を使用する(冪等です。このテナントではすでにプロビジョニングされています)
  2. いいえ — 代わりにカスタムホストを作成する(Phase 3.C の判断ツリー)
  3. キャンセル」
  • はい → PE から finalHostEnvUrl/Id を設定し、ACTION_TAKEN = "reuse-existing-pe" として、Phase 5 に進みます。(Phase 5 の WhoAmI 呼び出しによって JIT がトリガーされます — Constraint 1。)
  • いいえ → Phase 3.C の NoHost 判断ツリーに進みます(ガバナンス上、管理者が作成したカスタムホストが優先されます)。
  • キャンセル → 終了します。
3.C — ステータス NoHost(ホストタイプの判断ツリー)

🚦 ゲート(plan · ensure-pipelines-host:3.C.host-type): 最上位のホストタイプ選択プロンプト — Platform Host/カスタムホスト/PPAC 手動/手動のエクスポート・インポート戦略/キャンセルから選択します。Phase 3 と Phase 4 の以降の処理経路を決定します。

トリガー: ステータスが NoHost で、上流の hostResolution.willProvision* フラグにも回答が含まれていない場合。 質問する理由: 自動選択すると、同意なく環境(PE またはカスタムホスト)がプロビジョニングされます。PE はテナント内で1つに限定され、管理者は削除できません。 キャンセル時に残るもの: ありません — プロビジョニングはまだ実行されていません。

🚦 ゲート(plan · ensure-pipelines-host:3.C.env-pick): 3.C の最上位オプション「カスタムホスト」のサブプロンプト — 対象となる環境の一覧(最大5件)をロールラベル(dev env、source env、staging env、production env)とともに提示し、「その他(URL を貼り付け)」の選択肢も示します。ホストタイプメニューのカスタムホスト分岐でのみ実行されます。

トリガー: ユーザーが 3.C の最上位で「カスタムホスト」を選択した場合。 質問する理由: 環境を誤って自動選択すると、ユーザーが意図していないホストを経由してパイプラインが実行されます。 キャンセル時に残るもの: ありません — アプリのインストールは実行されていません。 このプロンプトでは、まずユーザーにホストの種類(Platform Host、Custom Host、PPAC での手動設定、またはキャンセル)を選んでもらいます。Custom Host を選ぶと、インストール方法(既存の環境を使用するか、新しい環境を作成するか)を選ぶサブプロンプトが表示されます。Platform Host の手順は最も手間がかからないデフォルトの選択肢であり、最初に提示されます。

スキップ条件 — 呼び出し元がすでに回答を収集済みの場合。 このスキルが setup-pipeline から呼び出され、docs/alm/last-pipeline.json に plan-alm Phase 2 Q4 によって入力された hostResolution ブロックが含まれている場合は、プロンプトを表示する前にこれらのフラグを確認してください。

上流シグナルアクション
hostResolution.willProvisionPlatform === truePhase 3.C 全体をスキップします。Phase 4.0(新しい Platform Host のプロビジョニング)に直接進みます。4.0 の事前呼び出し確認ゲートは引き続き実行されます。以下の 4.0「呼び出し前の確認(スキップ不可)」を参照してください。
hostResolution.chosenEnvUrl が空ではない URLPhase 3.C 全体をスキップします。CHOSEN_ENV_URL = hostResolution.chosenEnvUrl を設定し、その環境を指定して Phase 4.B に直接進みます(4.B の手順 1 の「選択済み」経路が適用されます)。既存のルーティングテーブルに従って ACTION_TAKEN を設定します(オリジンが devEnvUrl と一致する場合は "user-installed-app-on-dev"、それ以外の場合は "user-installed-app")。
hostResolution.willProvisionCustom === true かつ chosenEnvUrl が空Phase 3.C をスキップします。Phase 4.A(新しい Custom Host のプロビジョニング)に直接進みます。4.A の事前呼び出し確認ゲートは引き続き実行されます。
hostResolution.willUsePpac === true かつ chosenEnvUrl が空Phase 3.C をスキップします。Phase 4.C(PPAC での手動設定)に直接進みます。
上記のいずれにも該当しない以下の説明に従って Phase 3.C を実行します。

このスキップ条件が必要な理由。 plan-alm Phase 2 Q4 の NoHost 分岐では、ホストの種類を選ぶ同じメニューが表示されるため、ユーザーはレンダリングされた ALM プランを確認しながら、計画時に一度だけ選択できます。実行時に 3.C で再度尋ねると、同じ質問に二回答えることになり、エージェントが一方の回答だけを正式なものとして扱い、もう一方を無視するリスクがあります(2026-05-05 に発生した trial-license-409 → wrong-env-fallback の連鎖の原因となったバグ)。上流シグナルがある場合は、常にその内容を信頼してください。

手順 1:最上位のホスト種類選択プロンプトを表示します。

「{devEnvUrl} にバインドされた Pipelines ホストがありません。Pipelines をホストする環境を選択してください。

Pipelines はテナントごとに 1 つの環境で動作します。パイプライン、ステージ、実行履歴はその環境に保存されます。ソース環境はそこを介してデプロイされます。

  1. Platform Host をプロビジョニング(推奨) — テナントのホーム地域に自動プロビジョニングされる、Microsoft 管理の Dataverse 環境です。Pipelines アプリはインストール済みです。冪等性があり(再実行しても安全です)、所要時間は約 3~5 分です。

  2. Custom Host をセットアップ — Pipelines を、ユーザーが管理する Dataverse 環境で実行します。既存の環境を使用するか、新しい専用環境を作成するかを選択できます。

  3. PPAC を開いて手動で作成 — オプション 2 で対応できない場合の代替手段です。

  4. キャンセル — 終了します。」

最上位のルーティング:

選択アクション
オプション 1Phase 4.0(事前呼び出し確認ゲートあり)。ACTION_TAKEN = "fast-path-platform-getorcreate"。
オプション 2以下の手順 2 にある Custom Host のサブプロンプトを表示します。
オプション 3Phase 4.C。ACTION_TAKEN = "user-created-custom-ppac"。
オプション 4終了します。

手順 2:対象となる環境の一覧を作成し、役割ラベルを適用します(ユーザーがオプション 2 → サブオプション a を選んだ場合にのみ必要です。オプション 2 の選択後に遅延実行してください)。

Phase 2 の RESOLUTION.candidates.eligibleForAppInstall[] を取得します(Dataverse があり、呼び出し元がアクセスでき、Pipelines がまだインストールされておらず、SKU がデフォルトのフィルター({Production, Sandbox})に該当する環境。試用ライセンスのテナントでは、--skus で Production,Sandbox,Trial に拡張します)。

各項目に、表示時点でプロジェクトコンテキストのラベルを付与します。URL のオリジンで照合し(小文字に変換し、末尾のスラッシュを削除し、パスとクエリは無視します)、複数のラベルは · で連結します。

ラベルソースシグナル
dev envスキルが実行対象としている環境 URL(呼び出し元の devEnvUrl / pac env who)
source envdocs/alm/last-pipeline.json の sourceEnvironmentUrl(通常は dev と同じ環境)
staging envdocs/alm/last-pipeline.json 内の任意のステージの targetEnvironmentUrl で、ステージ名が /stag|test|uat/i に一致するもの
production env名前が /prod/i に一致する任意のステージの targetEnvironmentUrl

ロールが一致しない環境は、ラベルなしで表示されます。

ステップ 2a: 対象環境リストをランク付けして上限を設定します。 AskUserQuestion は約 7〜8 個の選択肢を超えると使用できなくなります。ロールを考慮したランク付けにより、環境表示の上限を 5 件として適用します。

  1. 常に表示されるロールラベル付き環境(最優先): ステップ 2 のロール装飾で dev env、source env、staging env、または production env ラベルが付いた対象環境をすべて含めます。URL オリジンで重複を排除します。
  2. 残りの枠を最大 5 件まで埋める: 対象リストの残りから、list-tenant-envs.js のネイティブな順序(name-hint パターン → admin-perms → lastModifiedTime)で埋めます。
  3. 常に追加する: 最後の項目として「その他(URL を貼り付け)」エントリを追加します。

対象の総数は別途追跡します — eligible.length > 5 の場合、その差分をインラインで示します。

ステップ 2b: 空リストの折りたたみ。 フィルター後に有効なリストがゼロ件になった場合は、まず SKU フィルターを広げて Trial を含めてみてください(--skus Production,Sandbox,Trial で ensure-pipelines-host-detect.js を再呼び出し)。それでもゼロ件の場合は、Custom-Host サブプロンプトからサブオプション a を削除し、b(新規作成)と c(戻る)のみを提示します。ユーザーが上書きできるよう、SKU フィルターの詳細を出力します:

「SKU フィルター(Production、Sandbox、Trial)に一致する既存の環境がありませんでした。さらに範囲を広げるには --skus <comma-list> を実行するか、b を選んでまったく新しい環境を作成するか、c で戻ってください。」

ステップ 2c: Custom-Host サブプロンプトを提示します(ユーザーがオプション 2 を選んだ場合):

「Custom Host をどのようにセットアップしますか?

a. 既存の環境を使用する — そこに Pipelines アプリをインストールします。{eligibleCountSuffix} 対象の環境から選択してください:

  • {env[0].displayName}({env[0].instanceApiUrl}) — {environmentSku} — {labels if any}
  • {env[1].displayName} (...)
  • …(最大 5 件)
  • その他(URL を貼り付け) — このショートリストにない対象環境向け

⚠ Sandbox SKU の環境では、インストール前に確認プロンプトが表示されます。

b. まったく新しい専用環境を作成する — テンプレート D365_ProjectHost による自動環境作成。Pipelines アプリが事前インストールされます。Global / Power Platform / Dynamics の管理者が必要です。所要時間は約 5〜10 分です。

c. 戻る — 最上位のホストタイプメニューに戻ります。」

{eligibleCountSuffix} の置換ルール:

  • eligible.length <= 5 → 空文字列(サフィックスなし。すべての環境が表示されます)。
  • eligible.length > 5 → Showing top 5 of {N}; the remaining {N-5} eligible env(s) can be reached via the "Other (paste URL)" entry.(先頭にスペース)。

ユーザーが「その他(URL を貼り付け)」を選んだ場合、node "${PLUGIN_ROOT}/scripts/lib/list-environments.js" の環境リストを URL 入力欄に事前入力します(pac env list を JSON { displayName, environmentId, environmentUrl, uniqueName, active } に解析します。旧来の pac env list --output json は現在の PAC CLI では無効です)。これにより、ユーザーは URL を手入力するのではなく、インベントリから貼り付けるか選択できます。

このプロンプトを変更する際に検証すべきテストシナリオ:

  • 対象が 0 件 → サブオプション a が削除される(サブプロンプトには b / c のみが表示される)。
  • 対象が 1〜5 件 → すべてインラインで表示され、サフィックスなし。
  • 対象が 6 件以上で、ロールラベル付き環境(dev/staging/prod)が存在する → ロールラベル付き環境がすべて先に表示され、残りの枠はランク付けで埋められる。サフィックスに件数の差分が表示される。
  • 対象が 6 件以上で、ロールラベル付き環境が存在しない → ランク付けによる上位 5 件。サフィックスに件数の差分が表示される。

ステップ 3: サブプロンプトの回答をルーティングします。

選択内容Phase 4 のパスACTION_TAKEN
オプション 1(トップレベルの Platform Host)4.0(呼び出し前に確認し、その後 provision-platform-host.js を実行)"fast-path-platform-getorcreate"
オプション 2 → サブオプション a — リストから選択した環境の URL が devEnvUrl と一致(オリジンが同一)4.B(「どの環境か」のサブプロンプトを省略し、選択した環境の URL を CHOSEN_ENV_URL として渡す)"user-installed-app-on-dev"
オプション 2 → サブオプション a — リストにあるその他の環境を選択4.B(サブプロンプトを省略し、CHOSEN_ENV_URL を渡す)"user-installed-app"
オプション 2 → サブオプション a — 「その他(URL を貼り付け)」4.B(ユーザーが指定した URL を CHOSEN_ENV_URL として渡す)"user-installed-app"
オプション 2 → サブオプション a — environmentSku === "Sandbox" の環境を選択Step 4 の Sandbox 確認ゲートを経て、確認後に 4.B(確認まで保留)
オプション 2 → サブオプション b4.A(サブプロンプト:名前、リージョン、管理者の確認)"fast-path-custom-d365projecthost"
オプション 2 → サブオプション c(戻る)トップレベルメニューを再表示該当なし
オプション 34.C"user-created-custom-ppac"
オプション 4終了該当なし

オプション 1 とサブオプション b では、実行前にテナント ID を表示するスキップ不可の確認ゲートがあります。オプション 1 → Phase 4.0「実行前の確認」を参照してください。サブオプション b → Phase 4.A「実行前の確認(スキップ不可)」を参照してください。

Step 4(条件付き):Sandbox 確認ゲート。

サブオプション a で選択した環境の environmentSku === "Sandbox" の場合、次を表示します。

"⚠ {displayName} は Sandbox 環境です(environmentSku: Sandbox)。

Power Platform Pipelines は Production 環境で実行されることがドキュメントに記載されています。Sandbox でも動作するはずですが、サポート対象の環境一覧には含まれていません。

続行しますか?

  1. はい、自己責任で続行する
  2. 別の環境を選択する
  3. キャンセルする"
  • はい → Sandbox 環境を使用して 4.B に進みます。上記の開発環境一致ルールに従って ACTION_TAKEN を設定します。
  • 別の環境を選択する → サブオプション a の環境リストを再表示します(ピッカーのその他の状態は保持します)。
  • キャンセルする → トップレベルの Phase 3.C プロンプトに戻ります。

テレメトリに関する注記。 "user-installed-app" と "user-installed-app-on-dev" を分けることで、ロールアウト後に、ユーザーが Pipelines を開発環境と併設する頻度と、専用の別環境を使用する頻度を把握できます。新しい "fast-path-platform-getorcreate" の値により、最も手間の少ない新しいパスの利用状況を測定できます。アーティファクト内の telemetry.platformHostAlreadyExisted フラグは、冪等な既存環境(200)と新規プロビジョニング(202)の結果を区別します。Phase 4.0 で 200 が頻発する場合に、Phase 2.5 の --maxEnvsToProbe のデフォルト値を調整する際に役立ちます。

3.D — ステータス HostWithoutPipelines(まれ)

ホスト環境は存在しますが、Pipelines ソリューションがありません。

"ホスト環境 {finalHostEnvUrl} が見つかりましたが、Pipelines ソリューションがインストールされていません。PPAC から今すぐインストールしますか?

  1. はい — PPAC を開いてインストールする(手動で案内)
  2. いいえ — 終了"
  • はい → 環境を事前選択した状態で Phase 4.C に進みます。
  • いいえ → 終了します。
3.E — ステータス OrgSettingStale / PermissionDenied

具体的な失敗内容をユーザーに提示します。自動修復の対象外です。手動でのクリーンアップを推奨します。

Phase 4 — 選択したパスを実行
4.0 — 高速パス:getOrCreate によるプラットフォームホスト

🚦 ゲート(同意・ensure-pipelines-host:4.0.pre-call): BAP の getOrCreate プラットフォームホスト呼び出しを実行する前に、リクエスト本文内のテナント ID を復唱します。上流の hostResolution.willProvisionPlatform === true の場合でも省略できません。PE はテナントごとに 1 つだけ作成され、管理者が削除できないため、このゲートが誤ったテナントへの操作を防ぐ主な手段です。

トリガー: フェーズ 4.0 の開始(3.C または上流からルーティング)。 確認する理由: PE が誤ったテナントにプロビジョニングされると、テナント管理者は削除できません。 キャンセル時: 何も起こりません。プロビジョニングはまだ開始されていません。

最も手間の少ないホストプロビジョニングのパスです。D365_1stPartyAdminApps と Platform を含む本文で、冪等性のある BAP getOrCreate エンドポイントを呼び出します。ユーザーが「使い始める」をクリックした際に、make.powerapps.com → Pipelines ページが行うものと同じ呼び出しを直接実行します。仕様は useGetOrCreatePlatformEnvironment.v4.ts にあります。新しいヘルパーは provision-platform-host.js です。

サブプロンプトはありません。 BAP がテナントのホーム地理的リージョンと既定の表示名を選択するため、管理者ロールは不要です。

AskUserQuestion による呼び出し前の確認 — 省略できない単一の同意ゲートです。

「テナント {TENANT_DISPLAY_NAME}({tenantId})にプラットフォームホストをプロビジョニングしようとしています。

プラットフォームホストは、テナントのホームリージョンにある Microsoft 管理の Dataverse 環境です。各テナントに 1 つだけ作成され、冪等性があります。すでに存在する場合は、それが返されます。新規プロビジョニングには約 3~5 分かかります。

続行しますか? 1. はい/2. キャンセル」

(TENANT_DISPLAY_NAME が null の場合は、太字のテナント名部分を削除し、テナント GUID を先頭に表示します。)

上流の hostResolution.willProvisionPlatform === true の場合でもこのゲートを実行する理由 — 4.A の呼び出し前ゲートと同じ理由です。このゲートでは、正確なテナント ID を復唱するため、ユーザーが誤ったテナントへの操作に気付く最後の機会となります。PE はテナントごとに 1 つだけ作成され、管理者が削除できないため、このゲートが主な緩和策です。実装の詳細(BAP エンドポイント、本文の形式)は、意図的にユーザー向けプロンプトには含めず、この SKILL.md と provision-platform-host.js のソースに記載しています。

呼び出し:

node "${PLUGIN_ROOT}/scripts/lib/provision-platform-host.js" \
  --bapToken "{BAP_TOKEN}" \
  --correlationId "{uuid v4}"

応答処理(ヘルパーに委譲しますが、ルーティングの判断はここで行います):

  • 200 と properties.provisioningState === 'Succeeded' → テナントにはすでに PE がありました(冪等性のあるパス)。ヘルパーは { status: 'Succeeded', alreadyExisted: true, instanceApiUrl, ... } を返します。RESOLUTION.finalHostEnvUrl、finalHostEnvId、RESOLUTION.isPlatform = true、actionTaken = "fast-path-platform-getorcreate"、telemetry.platformHostAlreadyExisted = true を設定します。フェーズ 5 に進みます。防御的な注記: フェーズ 2.5 の列挙で PE を見逃したことを意味します(おそらく、PE に到達する前に --maxEnvsToProbe の上限に達したか、フェーズ 2 と 4.0 の間に競合があったためです)。デバッグレベルの注記を表示します。エラーにはしません。
  • 202 と Location → ヘルパーが provisioningState === 'Succeeded' になるまでポーリングし、{ status: 'Succeeded', alreadyExisted: false, instanceApiUrl, ... } を返します。同じフィールドを設定し、telemetry.platformHostAlreadyExisted = false とします。
  • 403 → ヘルパーが BAP の本文をそのまま含む例外をスローします。az logout && az login を推奨します。代わりにオプション 2/3/4 を提示します。(4.A の管理者権限必須という説明は再利用しないでください。getOrCreate には管理者権限は不要です。)
  • その他の 4xx/5xx → ヘルパーが例外をスローします。内容を表示し、再試行するか別のパスに切り替えるかを尋ねます。

成功時: RESOLUTION.isPlatform = true(制約 1 に従い、フェーズ 5 で JIT ブランチが選択されます)。フェーズ 5 に進みます。

4.A — 高速パス:D365_ProjectHost テンプレートによるカスタムホスト

🚦 ゲート(同意・ensure-pipelines-host:4.A.pre-call): Custom Host の作成呼び出しを実行する前に、BAP の環境作成リクエスト本文(リージョン+表示名+テンプレート)をそのまま表示します。上流で hostResolution.willProvisionCustom === true の場合でも、絶対に省略できません。誤ったテナントやリージョンへのプロビジョニングを防ぐ最後の機会です。2026-05-05 に修正されたバグは、このゲートを省略したことが原因でした。

トリガー: フェーズ 4.A の開始時。サブプロンプト(表示名、リージョン、管理者であることの確認)を収集済み。 確認する理由: Custom Host が誤ったテナントまたはリージョンにプロビジョニングされると、Azure の容量クォータを消費し、環境が誤った組織に関連付けられる可能性があります。 キャンセルした場合: 何も起こりません。まだプロビジョニングは実行されていません。

🚦 ゲート(同意・ensure-pipelines-host:4.sandbox-confirm): 選択したインストール先の環境が environmentSku=Sandbox の場合、Sandbox の制限に関する警告を表示し、インストール前に明示的な再確認を求めます。Sandbox SKU の環境が選択されるたびに 1 回実行されます。

トリガー: フェーズ 4.B/フェーズ 3.C のサブオプション a。選択した環境が Sandbox SKU。 確認する理由: 同意を得ずに Sandbox 環境へ Pipelines をインストールすると、Sandbox 環境は非アクティブ状態が続くと削除されるうえ、容量も少ないため、Pipelines が予期せず動作しなくなる可能性があります。 キャンセルした場合: 何も起こりません。アプリのインストールは実行されていません。

D365_ProjectHost テンプレートを使用した標準の環境作成 API です(eng.ms-documented。PPAC の New custom host が内部で使用するものと同じテンプレートです)。新しいヘルパー provision-custom-host.js。

API 呼び出しの前に AskUserQuestion で収集するサブプロンプト:

  1. 表示名(デフォルトの候補:"{tenant displayName} Pipelines Host")
  2. リージョン(デフォルト:BAP の tenant エンドポイントから取得したテナントのホームジオ。変更を選択できるようにします)
  3. 呼び出し元が管理者であることの確認 — 単一の AskUserQuestion 「このテナントのグローバル管理者/Power Platform 管理者/Dynamics 管理者ですか? はい/いいえ/不明」。いいえ、または不明の場合は、Path 4.B/4.C を推奨してフォールバックします。

AskUserQuestion による呼び出し前の確認 — 省略できない 2 回目の同意ゲート:

「テナント {tenantId} に対して、次の本文で POST https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/environments?api-version=2021-04-01 を呼び出そうとしています。

{
  "location": "{region}",
  "properties": {
    "displayName": "{display name}",
    "environmentSku": "Production",
    "databaseType": "CommonDataService",
    "linkedEnvironmentMetadata": { "templates": ["D365_ProjectHost"] }
  }
}

Pipelines アプリが事前インストールされた Custom Host をプロビジョニングします(約 5~10 分)。続行しますか? 1. はい/2. キャンセル」

このゲートは必ず実行してください。 plan-alm Q4 ですでに「PP Pipelines を続行」の確認を受けている場合も、上流で hostResolution.willProvisionCustom === true の場合も、少し前に管理者であることの確認に対してユーザーが「はい」と回答した場合も、省略しないでください。plan-alm Q4 と管理者であることの確認は方針に関するものです。このゲートでは正確な API 呼び出し本文(URL、リージョン、テナント、テンプレート)をそのまま表示し、誤ったテナントやリージョンへのプロビジョニングを防ぐ最後の機会をユーザーに提供します。2026-05-05 に修正されたバグは、エージェントが plan-alm の事前確認でこのゲートも済んだものとして扱ったことが原因でした。

呼び出し:

POST https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/environments?api-version=2021-04-01
Authorization: Bearer {BAP_TOKEN}
Content-Type: application/json
x-ms-correlation-id: {uuid v4}

{
  "location": "{region}",
  "properties": {
    "displayName": "{display name}",
    "environmentSku": "Production",
    "databaseType": "CommonDataService",
    "linkedEnvironmentMetadata": { "templates": ["D365_ProjectHost"] }
  }
}

応答の処理:

  • 202 + Location ヘッダー + Retry-After ヘッダー → ライフサイクル操作が完了するまで、Location URL をポーリングします。
  • 200 + 即時レスポンス本文(env-create ではまれ)→ URL を取得します。
  • 初回 POST で 403 → 「Custom Host のファストパスには、Global/Power Platform/Dynamics の管理者権限が必要です。Dataverse 環境のシステム管理者権限がある場合はパス 2(既存環境に Pipelines アプリをインストール)、管理者の支援を依頼できる場合はパス 3(PPAC UI)を提案してください。」 と伝えて処理を停止します。4.B/4.C へのシームレスなフォールバックを提示します。
  • 容量関連のコード(例:NotEnoughCapacity_HasTrialLicense_ProvisionEnvironment、NotEnoughCapacity、NotEnoughCapacity_OrganizationDisabled、EnvironmentCapacityExceeded)を伴う 409 → パス 4.B にフォールバックする前に、SKU のフォールバックを確認するプロンプトを提示します。ライセンス/容量の制約は通常、要求された SKU にのみ適用されます。より小さい SKU(Sandbox、Developer、Trial)なら同じテナントで成功することが多く、同じように動作する Pipelines ホストを作成できます(Pipelines アプリはどの SKU にもインストールできます。違いはライセンスの割り当てのみです)。以下のサブステップ「4.A — SKU fallback prompt」を参照してください。ユーザーが SKU のフォールバックを辞退するか、フォールバックも失敗した場合に限り、フェーズ 3.C/パス 4.B に戻ります。
  • その他の 4xx/5xx → エラーを提示し、再試行するか、別のパスに切り替えるかをユーザーに尋ねます。4.B に切り替える場合は、上記の「元の eligible-env リストを使用する」ルールに従います。

ポーリング:

GET {Location}
Authorization: Bearer {BAP_TOKEN}

間隔 = Retry-After の秒数(デフォルトは 10 秒)。タイムアウト = 15 分(設定可能)。各応答で provisioningState(および/または operation の state フィールド。実行中に確認)を読み取ります。

  • Creating/InProgress → ポーリングを続行
  • Succeeded → 完了。instanceApiUrl、name(環境 GUID)、displayName を取得します
  • Failed/Canceled → エラーを提示して停止します

成功時: RESOLUTION.finalHostEnvUrl、finalHostEnvId、instanceApiUrl、actionTaken = "fast-path-custom-d365projecthost" を設定します。フェーズ 5 に進みます。

4.A — SKU のフォールバックプロンプト(容量エラーへの対処)

env-create が容量関連のエラーを伴う 409 を返した場合、ユーザーのテナントには要求された SKU に割り当てられるライセンス/容量の空きがありませんが、より小さい SKU であれば空きがある可能性があります。この制約を明確に伝え、Path 4.B を提案する前にフォールバック SKU を提示します。

  1. エラー本文を読み取ります。次の項目を抽出します。

    • error.code(例:NotEnoughCapacity_HasTrialLicense_ProvisionEnvironment)
    • error.message(BAP から返される、人が読める説明。例:「Trial ライセンスでは Trial 環境のみを作成できます。」)
  2. フォールバック SKU のリストを作成します。デフォルトの順序は Production(推奨)→ Sandbox → Developer → Trial です。直前に失敗した SKU は除外します。SKU ごとに注意事項が異なります。

    SKU提案するタイミング表示する注意事項
    Productionデフォルトの第一候補なし — ドキュメントに記載されている Pipelines ホストの SKU
    Sandboxサブスクリプションはあるが、割り当て可能な Production 容量がないテナント「Sandbox SKU は Pipelines で動作しますが、ドキュメントでは非本番用とされています。Microsoft は Sandbox でホストされるアプリに異なる SLA を適用する場合があります。」
    Developer個人開発者向けのテナント「Developer SKU はシングルユーザー用です。他のチームメンバーはこのホストを介してデプロイできません。個人専用/開発専用の ALM セットアップの場合にのみ使用してください。」
    TrialTrial ライセンスのテナント(ほかに利用できる選択肢がない場合)「Trial 環境は、変換されない限り 30 日後に期限切れになります。期限切れ時には Pipelines ホストを再プロビジョニングする必要があります。」
  3. 制約をユーザーに伝え、次のプロンプトを提示します。

    「Custom Host のプロビジョニングに失敗しました({error.code}):{error.message}

    Pipelines アプリはどの SKU にも同じようにインストールされます。異なるのはライセンスの割り当てだけです。より小さい SKU で env-create を再試行するか、既存の env に Pipelines アプリをインストールする方法(Path 4.B)に切り替えられます。」

    🚦 ゲート(plan · ensure-pipelines-host:4.A.sku-fallback): env-create で容量エラーが発生しました — 別の SKU で再試行するか、Path 4.B(既存の env にインストール)に切り替えるか、キャンセルしてください。

    AskUserQuestion(選択肢のリストを動的に作成します。直前に失敗した SKU を除外し、注意事項を説明に含めます)。

    質問ヘッダー選択肢
    別の SKU で env-create を再試行しますか?SKU のフォールバック(残りの各 SKU を 1 つずつ選択肢として表示し、説明に注意事項を含める)、Path 4.B に切り替える(既存の env に Pipelines アプリをインストール)、キャンセル
  4. 回答に応じて分岐します。

    • SKU を選択:新しい SKU を本文に反映し、4.A の呼び出し前確認ゲート(スキップ不可 — 上記の「呼び出し前の確認」を参照)を再度提示してから、--environmentSku <picked> を指定して provision-custom-host.js を再呼び出しします。それも容量エラーで失敗した場合は、次の SKU を除外してプロンプトを再度提示します。容量エラーが 2 回連続した場合は、SKU のフォールバックを提示するのをやめ、Path 4.B に進みます。
    • Path 4.B:以下の「元の eligible-env リスト」のルールに従って 4.B に進みます。
    • キャンセル:何も残さず終了します。

    必ず、409 応答本文に含まれる env GUID を破棄してください。プロビジョニングに失敗しているため、その GUID は使用可能な env を表していないか、応答に混入したものです。Path 4.B では、Phase 2 の eligible-env インベントリのみを使用してください。

4.B — 既存の env に Pipelines アプリをインストール(自動)

この経路は以前、PPAC で手動操作するものでした。2026-05-08 時点では完全に自動化されています。install-pipelines-app.js は BAP の applicationPackages/install エンドポイント(PPAC の 「アプリのインストール」 ボタンを支える API と同じもの)を呼び出し、BAP が 401/403/5xx を返した場合は pac application install にフォールバックします。

サブプロンプト:対象の env を選択(env がすでに選択されている場合はスキップ):

  1. 環境がすでに選択されている場合(Phase 3.C Option 2 → sub-option a から、または hostResolution.chosenEnvUrl に関する上流のスキップルールから CHOSEN_ENV_URL が設定されている場合):サブプロンプトをスキップし、選択済みの環境でインストール手順に直接進みます。Phase 3.C Step 3 のルーティングテーブルに従って ACTION_TAKEN を設定します(CHOSEN_ENV_URL の出所が devEnvUrl と一致する場合は "user-installed-app-on-dev"、それ以外の場合は "user-installed-app")。

    それ以外の場合(レガシーのエントリーパス — 呼び出し元が 3.C を経由せずに 4.B を直接呼び出した場合、または 4.A の失敗時のフォールバック経由でここに到達した場合):対象の選択肢として RESOLUTION.candidates.eligibleForAppInstall[] にある環境の一覧と、「Other (paste URL)」を提示し、サブプロンプト 「Pipelines をホストする環境を選択してください(Phase 2 のインベントリから自動検出された環境):」 を表示します。4.A の 409 試用ライセンスフォールバックから到達した場合も、対象の一覧を適用します。409 レスポンスボディに含まれる環境 GUID は破棄してください。

環境 GUID の整合性チェック。 インストールヘルパーに渡す GUID は、Phase 2 で列挙された選択済み環境の name フィールド(または、ユーザーが貼り付けた URL の場合は pac env list)から取得する必要があります。4.A の失敗レスポンス、別の実行時の docs/alm/last-host-check.json、または他の状態パスにある GUID を決して代用しないでください。GUID を確実に特定できない場合は、ヘルパーを呼び出す前に、環境の表示名 + URL + GUID を示す AskUserQuestion でユーザーに確認してください。

呼び出し前の確認ゲート(スキップ不可 — Phase 4.0 / 4.A と同じ理由):

「テナント {TENANT_DISPLAY_NAME}({tenantId})の {displayName}({instanceApiUrl})に Power Platform Pipelines アプリケーションをインストールします。これは PPAC の アプリのインストール ボタンで実行されるのと同じインストールです。エージェントが BAP API を直接呼び出すため、手動でクリックする必要はありません。所要時間は約 2~5 分です。続行しますか? 1. はい / 2. キャンセル」

ヘルパーを呼び出します:

node "${PLUGIN_ROOT}/scripts/lib/install-pipelines-app.js" \
  --bapToken "{BAP_TOKEN}" \
  --envId "{envId}" \
  --instanceApiUrl "{instanceApiUrl}" \
  --hostToken "{HOST_TOKEN}" \
  --correlationId "{uuid}"

HOST_TOKEN は選択済み環境のオリジンに対して取得され(az account get-access-token --resource "{instanceApiUrl origin}")、ヘルパーに渡されます。これにより、ヘルパーのインストール後検証プローブ(solutions?$filter=uniquename eq 'msdyn_AppDeploymentAnchor')を、スキル側で別途検証手順を連鎖させることなく、最初から最後まで実行できます。

レスポンスの処理(ヘルパーに委任しますが、ルーティングの判断はここで行います):

  • { status: 'Succeeded', alreadyInstalled: true, installPath: 'cached' } — この環境にはパッケージがすでにインストールされています(冪等なパスです。Phase 2.5 で環境をすでにホストとして分類しているはずなので、4.B ではまれですが、念のため処理します)。上記の開発環境一致ルールに従って ACTION_TAKEN を設定し、Phase 5 に進みます。
  • { status: 'Succeeded', alreadyInstalled: false, installPath: 'bap' } — BAP の applicationPackages/install POST が成功しました(200 で同期、または 202 + Location のポーリング)。開発環境一致ルールに従って ACTION_TAKEN を設定し、Phase 5 に進みます。
  • { status: 'Succeeded', alreadyInstalled: false, installPath: 'pac', pacFallbackReason: '...' } — BAP が 401/403/5xx を返しました(通常は、Az → BAP が拒否されるテナントでのトークンの audience 不一致です。環境列挙に関して pac-bap-shim.js が扱うものと同じ状況です)。ヘルパーは pac application install にフォールバックしました。結果は同じです。フォールバックの理由を docs/alm/last-host-check.json のテレメトリに記録します。Phase 5 に進みます。
  • ヘルパーが例外をスローした場合 — BAP と PAC の両方が失敗しました。結合されたエラーメッセージをユーザーに提示します。最終手段のフォールバック(手動):PPAC の URL https://admin.powerplatform.microsoft.com/manage/environments/{envId}/dynamics365apps と、次の4つの手動手順(アプリのインストール → Power Platform Pipelines → 次へ → 規約に同意 → インストール)を表示し、その後に 「完了 — 続行」 という AskUserQuestion を提示します。確認後、環境 URL に対して verify-host-readiness.js を実行し、Pipelines ソリューションが検出された場合にのみ Phase 5 に進みます。この分岐はまれなはずです。頻繁に発生する場合は、ヘルパーの結合エラーを添えて issue を作成し、BAP/PAC のパスを調整できるようにしてください。 成功時: ヘルパーの pipelinesSolutionVersion を取得します(instanceApiUrl と hostToken が渡された場合に設定されます)。RESOLUTION.finalHostEnvUrl/Id を設定します。フェーズ 5 に進みます。
4.C — ガイド付き手動手順:PPAC の New custom host

🚦 ゲート(進行 · ensure-pipelines-host:4.C.ppac-done): 外部システムの待機ゲートです。ユーザーが PPAC の「New custom host」フローを手動で完了してから、戻って確認する必要があります。その後、スキルは BAP をポーリングして新しい環境を確認します。

トリガー: フェーズ 4.C の開始時。PPAC の URL が表示されます。 確認を求める理由: スキルは新しい環境の存在を確認せずに進行するため、後続の setup-pipeline がホストなしで失敗します。さらに、PPAC での作成が途中まで成功した状態でユーザーがゲートをキャンセルすると、ホストのバインドが一部確立された状態になります(テナントに D365_ProjectHost をテンプレートにした環境が作成されています)。 キャンセル時に残るもの: host-binding — 手動作成された環境がテナントに残る場合があります。ユーザーは PPAC から削除する必要があります。

  1. https://admin.powerplatform.microsoft.com/deployments を表示し、次の手順を案内します:「『New custom host』をクリック → 名前を入力(推奨:『{tenant} Pipelines Host』)→ テナントのホームリージョンで Production 環境を選択 → Create。プロビジョニングには 5~10 分かかります。」

    eng.ms のドキュメントによると:「パネルでは環境の種類として Production がデフォルトで選択されます。Dataverse の追加も必要です……このシナリオでは特定の組織テンプレートを使用するため、テンプレートとサンプルアプリのオプションはここでは表示されません。」(テンプレートは D365_ProjectHost です。パス 4.A で自動化されるものと同じです。)

  2. 2 つの選択肢がある AskUserQuestion を表示します:「完了しました — プロビジョニングを開始しました」/「キャンセル」。

  3. 確認後、新しい環境で Pipelines マーカーを持つものが見つかるまで、BAP の list-tenant-envs.js を 15 秒ごとにポーリングします。検出したら URL を取得し、actionTaken = "user-created-custom-ppac" を設定します。フェーズ 5 に進みます。

共通:タイムアウト処理

各パスのデフォルトは 15 分です(設定可能)。タイムアウトした場合は、ユーザーに時間を延長する(さらに 15 分)、パスを切り替える、または終了するかを尋ねます。

フェーズ 5 — JIT プロビジョニング(PE 検出時のみ)とホストの検証

finalHostEnvUrl の取得方法にかかわらず、常に実行されます。

JIT 手順(既存の PE が検出され、選択された場合のみ — RESOLUTION.isPlatform === true): 制約 2 に従い、呼び出し元ユーザーはかなり前に PE で JIT プロビジョニングされている場合も、まだ一度もされていない場合もあります。引き継ぎ前にホストで認証が機能することを確認するため、instanceApiUrl に対して WhoAmI を 1 回実行します。(カスタムホストのパスでも同じ手順が必要ですが、以下の verify-host-readiness.js のステップ 1 で自然に満たされます。環境を作成した管理者は作成時点でアクセス権を持ち、user-installed-app の場合はユーザーがすでに環境にアクセスできるためです。)

GET {instanceApiUrl}/api/data/v9.0/WhoAmI
Authorization: Bearer {HOST_TOKEN}

ここで、HOST_TOKEN = az account get-access-token --resource "{instanceApiUrl origin}" です。

期待される結果:UserId を含む 200。初回呼び出しで 404 または 403 が返された場合は、5 秒ごとに最大 60 秒まで再試行します。JIT の反映は非同期になることがあります。

検証(verify-host-readiness.js) — 次の順に確認します。

  1. WhoAmI が UserId を返します(認証を証明し、PE 検出時には JIT をトリガーします)。
  2. GET {hostEnvUrl}/api/data/v9.0/solutions?$filter=uniquename eq 'msdyn_AppDeploymentAnchor'&$select=version&$top=1 が 1 行を返します → PIPELINES_SOLUTION_VERSION を取得します。(このクエリ 1 回で Pipelines のインストール確認とバージョン取得の両方を行います。deploymentpipelines?$top=0 は Dataverse に 400 で拒否されます。)

MIN_PIPELINES_VERSION(scripts/lib/alm-thresholds.js 内の定数)と比較します。

  • すべての確認に合格 → READY = true。
  • ソリューションのバージョンが最小値未満 → 警告を出力します(致命的ではありません)。
  • いずれかの確認に失敗 → 該当する確認に固有の修正手順を示して停止します。
フェーズ 6 — ホストチェックの成果物を書き込む

docs/alm/last-host-check.json に書き込みます(存在しない場合は、先に docs/alm/ ディレクトリを作成します — node -e "require('fs').mkdirSync('docs/alm',{recursive:true})" を実行するか、プロジェクト外から実行する場合は --outputPath を使用してください)。

{
  "schemaVersion": 2,
  "checkedAt": "2026-04-28T...",
  "tenantId": "...",
  "sourceEnvUrl": "{devEnvUrl}",
  "sourceEnvId": "...",
  "resolutionStatus": "AvailableUsingPlatformHost" | "AvailableUsingCustomHost" | "AvailableUsingCustomHostByAdminDefault" | "AvailableUnboundCustomHost" | "MultipleUnboundCustomHosts" | "PlatformHostExistsUnbound" | "CannotRedirect" | "NoHost" | "OrgSettingStale" | "PermissionDenied" | "HostWithoutPipelines",
  "finalHostEnvUrl": "...",
  "finalHostEnvId": "...",
  "finalHostInstanceApiUrl": "...",
  "isPlatformHost": true | false,
  "tenantDefaultCustomHostEnvId": "...",
  "actionTaken": "none" | "reuse-existing-custom" | "reuse-existing-pe" | "fast-path-platform-getorcreate" | "fast-path-custom-d365projecthost" | "user-installed-app" | "user-installed-app-on-dev" | "user-created-custom-ppac",
  "pipelinesSolutionVersion": "9.x.y.z",
  "ready": true,
  "warnings": [
    "Pipelines solution version 9.0.0.1 is below recommended 9.1.0.0 — RetrieveDeploymentPipelineInfo may not be available."
  ],
  "candidates": {
    "existingCustomHosts": [
      { "envId": "...", "instanceApiUrl": "...", "displayName": "...", "pipelinesSolutionVersion": "..." }
    ],
    "existingPlatformHost": null,
    "eligibleForAppInstall": [
      { "envId": "...", "instanceApiUrl": "...", "displayName": "..." }
    ],
    "inaccessibleEnvs": [
      { "envId": "...", "displayName": "...", "reason": "403" }
    ]
  },
  "telemetry": {
    "correlationId": "{uuid passed to env-create, if applicable}",
    "platformHostAlreadyExisted": true | false
  }
}

telemetry.platformHostAlreadyExisted — actionTaken === "fast-path-platform-getorcreate" の場合にのみ存在します。BAP の getOrCreate が 200 + Succeeded を返した場合(冪等 — テナントにすでに PE が存在していた場合)は true、呼び出しが 202 を返し、完了までポーリングした場合は false です。Phase 2.5 の列挙で既存の PE が見つからない頻度を測定し、--maxEnvsToProbe のデフォルト値を調整できます。

スキーマバージョンの更新(1 → 2): テナント全体の列挙結果を記録するため、candidates.* ブロックを追加しました。キャッシュのファストパス(Phase 1 のステップ 0)は、schemaVersion に関係なく finalHostEnvUrl を読み取ります。candidates ブロックは情報提供用で、デバッグや再実行の判断に役立ちます。古い v1 ファイルも引き続き読み取れます — 欠落しているフィールドはすべて「まだ列挙されていない」として扱われます。

actionTaken 列挙型 — 値の定義:

  • "none" — 今回の実行前にホストがすでに確立されていたため、インストール/プロビジョニングは実行されませんでした(Phase 3.A の経路またはキャッシュのファストパス)。
  • "reuse-existing-custom" — ユーザーが、テナントにすでに存在する未バインドのカスタムホストを選択しました(Phase 3.C-pre または 3.C-pre')。
  • "reuse-existing-pe" — ユーザーが既存のプラットフォームホストを選択しました(Phase 3.C-pre'')。
  • "fast-path-platform-getorcreate" — Phase 4.0 で BAP の getOrCreate エンドポイントを呼び出しました。telemetry.platformHostAlreadyExisted フラグによって、冪等な既存ホスト(200)と新規プロビジョニング(202)の結果を区別できます。
  • "fast-path-custom-d365projecthost" — Phase 4.A で環境作成 API を使って新しいカスタムホストをプロビジョニングしました。
  • "user-installed-app" — Phase 4.B で、開発環境とは異なる既存環境に Pipelines をインストールしました。
  • "user-installed-app-on-dev" — Phase 4.B で、開発環境そのものに Pipelines をインストールしました(URL のオリジンが devEnvUrl と一致します)。"user-installed-app" とは別のテレメトリとして記録することで、ユーザーが Pipelines を開発環境と同じ環境に配置する頻度を把握できます。
  • "user-created-custom-ppac" — Phase 4.C — ユーザーが PPAC UI で環境を作成し、フローが作成後にそれを検出しました。

このファイルは setup-pipeline と deploy-pipeline によって使用されます。

スキルの使用状況を記録します。

参照:${PLUGIN_ROOT}/references/skill-tracking-reference.md

参照先のスキル追跡手順に従って、このスキルの使用状況を記録してください。--skillName "EnsurePipelinesHost" を使用します。

ALM プランを更新します(存在する場合):

node "${PLUGIN_ROOT}/scripts/lib/refresh-alm-plan-data.js" \
  --projectRoot "." \
  --phase ensure-pipelines-host \
  --render

これにより、先ほど書き込んだ docs/alm/last-host-check.json から planData.hostResolution を更新し(ホストのみ — パイプラインはまだありません)、実行前の NoHost リスクを削除してから docs/alm-plan.html を再レンダリングします。setup-pipeline の Phase 7 だけでなく、ここで実行してください — ホストのインストールには 18 分以上かかり、セッションの境界をまたぐ場合があるため、更新を先送りするとプランにホストが反映されないおそれがあります。docs/.alm-plan-data.json が存在しない場合(スタンドアロンで、ALM プランの一部ではない場合)、ヘルパーは ok:false を返して何もせずに終了します。集中管理された PostToolUse フックもバックストップとしてプランを調整しますが、ソースの段階で更新すれば、レンダリング済みのプランをすぐに最新の状態に保てます。

概要テーブルを提示します。

フィールド値
テナント{tenantId}
ソース環境{devEnvUrl}
解決ステータス{resolutionStatus}
最終ホスト{finalHostEnvUrl}
ホストの種類Platform / Custom
実行したアクション{actionTaken}
Pipelines のバージョン{pipelinesSolutionVersion}
警告{warnings}

actionTaken !== "none" の場合:

"次の手順: /power-pages:setup-pipeline を実行して、このホストに最初のパイプラインを作成してください。"

既存のスキルとの統合

setup-pipeline (✅ 配線済み)

setup-pipeline/SKILL.md のフェーズ 1 ステップ 4 は ensure-pipelines-host-detect.js (オーケストレーターラッパー) を呼び出し、resolutionStatus で分岐します。

  • AvailableUsing* → finalHostEnvUrl をそのまま使用し、続行します。
  • *Unbound* / NoHost → 再利用またはプロビジョニングのために /power-pages:ensure-pipelines-host (このスキル) に委譲します。docs/alm/last-host-check.json が ready: true を示した後に再開します。
  • CannotRedirect / OrgSettingStale / PermissionDenied → 特定の管理者解決メッセージを表示して停止します。

フェーズ 3 にあった「ユーザーにホスト URL を手動で尋ねる」という古いフォールバックは削除されました。HOST_ENV_URL は常にフェーズ 1 で設定されるか、フェーズ 3 の前にスキルが停止します。

deploy-pipeline

変更ありません。deploy-pipeline は setup-pipeline が書き込んだ docs/alm/last-pipeline.json から hostEnvUrl を読み取ります。

plan-alm (✅ 配線済み)

plan-alm のフェーズ 1 ステップ 12 は ensure-pipelines-host-detect.js を呼び出し、その結果を HOST_RESOLUTION として保存します (PIPELINE_DONE = true の場合はスキップされます)。フェーズ 2 の Q4 は HOST_RESOLUTION.status で分岐します。生成される docs/alm-plan.html には「Pipelines Host」カードと (willEnsureDuringExecution: true の場合) 「Setup pipeline」チェックリストステップの下にサブ項目が含まれます。references/cicd-pipeline-patterns.md と plan-alm-update-PLAN.md の仕様を参照してください。

脅威モデル — 組み込みの緩和策

リスクこのスキルにおける緩和策
混乱した代理 / サイレントプロビジョニングフェーズ 1.4 のテナント ID ゲート + フェーズ 3 の明示的な選択 + フェーズ 4.A の呼び出し前確認 (正確なリクエスト本文をエコー)
ホストの重複作成フェーズ 2.5 のテナント全体の列挙により、フェーズ 3 が作成を提案する前に既存のカスタムホストを検出します。フェーズ 3.C-pre / 3.C-pre' は再利用のために既存ホストを提示します。新規作成ツリーに到達するには、ユーザーが再利用を明示的に拒否 (オプション「No」) する必要があります。
古いローカルキャッシュ → 削除されたホストの使用フェーズ 1.0 のキャッシュファストパスは、再利用の前にライブの solutions?$filter=uniquename eq 'msdyn_AppDeploymentAnchor'&$top=1 プローブで検証します — 404/403/タイムアウトの場合は完全なフェーズ 2 にフォールスルーします
404 の曖昧さ → 意図しないアクションフェーズ 2.2 の曖昧さ解消ルール — 単一の 404 でアクションを実行しない。list-tenant-envs で裏付けを取る
誤ったテナントへのプロビジョニングフェーズ 1.4 は tenantId、organizationId、dev 環境 URL をエコーします。フェーズ 4.A は呼び出し前の本文で tenantId をエコーします
CannotRedirect の見逃しフェーズ 2.3 はこれを明示的に検出し、誤ったホストへの書き込みに進むのではなく、特定のエラーで停止します
JIT プロビジョニングの漏れ → サイレントな 404 連鎖フェーズ 5 は他のホスト操作の前に instanceApiUrl に対して WhoAmI 呼び出しを行います (既存の PE が検出された場合に関連)
古いソリューション → サイレント障害フェーズ 5 は PIPELINES_SOLUTION_VERSION を読み取り、MIN_PIPELINES_VERSION を下回る場合は警告します
非管理者がカスタムホストファストパスを試行フェーズ 4.A は事前に管理者ロールを確認します。403 の場合はフェーズ 4.B / 4.C に優雅にフォールバックします
テナントシングルトンの PE が誤って作成されるフェーズ 1.4 のテナント ID ゲート (テナント表示名 + テナント ID + dev 環境 URL をエコー) + フェーズ 4.0 の呼び出し前確認ゲート (呼び出し直前にテナント表示名 + テナント ID を再度エコー)。getOrCreate エンドポイントは冪等です — すでに PE を持つテナントで呼び出すと、重複を作成するのではなく既存のものを返します (200 + alreadyExisted = true)。
テレメトリの漏洩すべてのプローブ結果は docs/alm/last-host-check.json に留まります。相関 ID は生成した標準の x-ms-correlation-id UUID です。update-skill-tracking.js はカウンターと作成ツール名のみを書き込みます
特権境界すべてのパスはユーザーの OAuth コンテキストで実行されます。403/401 は「これには X 管理者ロールが必要です」というメッセージで停止として表面化します。昇格は試みません
レート制限パスごとに合計 15 分のタイムアウト。BAP からの Retry-After を尊重。最小 10 秒のポーリング間隔
強制リンクの不可逆性範囲外 — このスキルが行わないこと を参照

重要な判断ポイント(ユーザーの応答を待機)

  1. Phase 1.4 — テナント ID の確認(読み取り専用の意図)
  2. Phase 3.A/B/C-pre/C-pre'/C-pre''/C/D/E — RESOLUTION.status に基づく分岐判断
  3. Phase 3.C-pre — 既存の Custom Host を 1 つ再利用するか(Y/N/Cancel)
  4. Phase 3.C-pre' — 複数の既存 Custom Host から選択するか、新規作成するか
  5. Phase 3.C-pre'' — 既存の PE を使用するか、代わりに Custom Host を作成するか
  6. Phase 3.C — 新規作成パスの選択(4 つの選択肢:Custom-fast、app-install、PPAC-UI、キャンセル)
  7. Phase 4.A — 管理者ロールの自己申告(No / Not sure → 4.B / 4.C にフォールバック)
  8. Phase 4.A — 正確な API リクエスト本文を表示する実行前確認
  9. Phase 4.B/C — ユーザーが UI の手順を実施 → 「Done — proceed」で完了を確認
  10. Phase 5 — Pipelines ソリューションのバージョンが最小要件を下回る場合の警告確認

エラー処理

  • verify-alm-prerequisites.js が失敗 → 修正手順(az login、pac auth create)を提示して停止
  • BAP トークンの取得に失敗 → 停止し、az logout && az login を提案
  • BAP 環境 GET が 404 を返す → あいまいさを解消する処理を実行(Phase 2.2 のフォールバック)
  • BAP 環境 GET が 403 を返す → RESOLUTION.status = "PermissionDenied" を設定し、テナント ID と環境 ID を提示して停止
  • Custom Host の環境作成が 403 を返す → 4.B(アプリのインストール)または 4.C(PPAC UI)にシームレスにフォールバック
  • Custom Host の環境作成がその他の 4xx を返す → ステータスと本文を記録し、再試行するか別のパスに切り替えるかをユーザーに確認
  • ライフサイクル操作のポーリングがタイムアウト(デフォルトは 15 分) → 延長(さらに 15 分)/パスの切り替え/終了のいずれかを確認
  • RetrieveSetting が 404 を返す → 「管理者の既定カスタムホストがない」として処理(現在の discover-pipelines-host.js の動作)
  • GetOrgDbOrgSetting が 404 を返す → 「バインドされていない」として処理(UI の動作と一致)
  • JIT の再試行後、ホスト上の WhoAmI が 403 を返す → CannotRedirect の競合状態、または実際の権限の問題と考えられます。両方のエラーメッセージを示して停止
  • ユーザーがインストール済みと申告した後(4.C)に verify-host-readiness.js が Pipelines tables not found を報告 → PPAC を再確認するか、ポーリングを延長するかをユーザーに確認

進捗追跡テーブル

タスクの内容activeForm説明
ローカルキャッシュの確認と前提条件の検出キャッシュを確認し、前提条件を検出していますPhase 1.0 で docs/alm/last-host-check.json を読み取ります。情報が新しい場合は solutions?$filter=uniquename eq 'msdyn_AppDeploymentAnchor'&$top=1 を使って finalHostEnvUrl をプローブします。200 が返った場合は再利用して Phase 6 に進みます。それ以外の場合は verify-alm-prerequisites.js と detect-project-context.js を実行し、BAP_TOKEN を取得して、テナント ID の確認ゲートに進みます
解決順序を実行してホストを検索解決順序を実行していますGetOrgDbOrgSetting('ProjectHostEnvironmentId') を取得し、BAP 環境 GET を実行します。Platform の場合はテナントの既定カスタムホストを確認し、CannotRedirect を検出します。組織のバインドがない場合は、list-tenant-envs.js を使ってテナント全体のリスト取得とプローブを並列実行(最大 10 件)し、既存の Custom Host と PE を検索して、AvailableUnboundCustomHost / MultipleUnboundCustomHosts / PlatformHostExistsUnbound / NoHost に分類します
ユーザーにアクションを確認ユーザーにアクションを確認していますresolutionStatus に基づいて分岐します。AvailableUnboundCustomHost / MultipleUnboundCustomHosts / PlatformHostExistsUnbound の場合は、まず再利用するかを確認します。ユーザーが再利用を拒否した場合に限り、NoHost の新規作成ツリーに進みます。Phase 4.A では、実行前にリクエスト本文を表示して明示的な同意を得ます
選択したパスを実行選択したパスを実行していますパス A(Custom D365_ProjectHost の環境作成)/B(アプリの手動インストール)/C(PPAC の New custom host)を実行します。Retry-After の間隔でライフサイクル操作をポーリングし、15 分のタイムアウトを順守します
JIT プロビジョニングとホストの検証ホストを検証していますinstanceApiUrl に対して WhoAmI を実行します(既存の PE が検出された場合にのみ JIT をトリガーします)。deploymentpipelines テーブルのプローブと Pipelines ソリューションのバージョン確認を行い、READY フラグを設定します
ホスト確認アーティファクトを書き込みホスト確認アーティファクトを書き込んでいますdocs/alm/last-host-check.json に RESOLUTION 全体、actionTaken、correlationId を書き込み、スキルの追跡情報を更新します。概要を提示し、次に /power-pages:setup-pipeline を提案します

オープン項目(実行フェーズで解決)

これらは実環境での検証が必要です。

  1. Pipelines ソリューションの uniquename。 ✅ 2026-04-28 に解決:SIP ホスト(pascalepipelineshost.crm.dynamics.com)へのライブクエリで、msdyn_AppDeploymentAnchor v9.1.2026034.260325188 を確認しました。PIPELINES_SOLUTION_UNIQUE_NAME 定数として保存済みです。
  2. MIN_PIPELINES_VERSION。 最も古い実環境のソリューションバージョンで、どの Pipelines 機能が動作しないかをテストしたうえで設定します。暫定的な保守的推測値は "9.0.0.0" です。
  3. list-tenant-envs.js の Custom Host 検出マーカー。 ✅ 2026-04-28 に解決:ライブ BAP 環境リストクエリ(テストテナント内の環境 1000 件)で確認しました。$expand=properties.linkedEnvironmentMetadata を指定しても、linkedEnvironmentMetadata.templates は返されません。環境ごとの Dataverse プローブが必須です。プローブクエリは solutions?$filter=uniquename eq 'msdyn_AppDeploymentAnchor'&$select=version&$top=1 に修正済みです(1 回の呼び出しで存在とバージョンの両方を確認できます)。PE の検出は引き続き environmentSku === 'Platform' で簡単に行えます。
  4. 環境作成時の BapApiVersion の値。 D365_ProjectHost テンプレートは Pegasus/BAP-RP/Neptune 向けにオンボード済みです(eng.ms の PR リストによる)。PPAC UI は環境操作に 2021-04-01 を使用しています。New custom host の最新 HAR を取得して、実行中に確認してください。
  5. ライフサイクル操作のレスポンス形式。 Location URL が { properties: { provisioningState } }、{ state }、または両方のどれを返すかを確認する必要があります。HAR で確認します。
  6. テナントのホーム地域の検出。 4.A のデフォルト地域です。選択肢は、BAP_TOKEN のクレーム(tid、xms_tcdt?)、BAP の /tenant?api-version=2021-04-01 エンドポイント、または既存環境の properties.azureRegionHint です。実行中にいずれかを選択してください。
  7. コールドテナントのテスト環境。 Pipelines をこれまで使用したことのないテナントで、エンドツーエンドの検証が必要です。個人用 MSDN テナントで問題ありません。
  8. linkedEnvironmentMetadata.templates による BAP 環境リストのフィルター。 サポートされている場合は、Phase 2.5b で D365_ProjectHost を使用して作成された環境に事前フィルターを適用し、環境ごとの Dataverse プローブを省略できます。テストが必要です。サポートされていない場合は、並行数を制限した環境ごとのプローブを使用します。
  9. 環境リストのレスポンスに実際に linkedEnvironmentMetadata.templates が含まれるか。 含まれる場合は、サーバー側フィルターがなくてもクライアント側で効率よくフィルターできます。含まれない場合は、環境ごとの Dataverse プローブだけが判定手段になります。$expand=properties.linkedEnvironmentMetadata クエリパラメーターを含めた最新の BAP 環境リスト HAR を取得して確認してください(resolve-env-by-id.js ではすでに使用されています)。
  10. 環境ごとのプローブのレート制限予算。 ✅ 2026-04-28 に一部解決:Microsoft 内部テストテナントには環境が 1000 件あります(Production SKU が 526 件、Sandbox が 453 件)。すべてを無条件にプローブする方法は、並行数を 10 にしても遅すぎます。複数段階のフィルターを採用しました:
    • Dataverse のない環境を事前に除外する(テストテナントでは約 3 件を検出。効果は小さい)
    • --skus でフィルターする(デフォルトは Production。PE は常に含めます)
    • lastModifiedTime の降順で並べ替える
    • --maxEnvsToProbe で上限を設定する(デフォルトは 50。並行数 10 で約 5 秒)
    • 上限に達してホストが見つからなかった場合は、「スキャンした環境数 N/全体数 M(フィルター:...)」という警告を表示する 残作業:一般的な顧客テナント(環境数 5~50 件)に対して、上限のデフォルト値を検証してください。通常はオーバーヘッドは発生しないはずです。
  11. cacheMaxAgeMs のデフォルト値。 24 時間は暫定値です。開発テナントでホストが頻繁に変更される場合は、短縮が必要になる可能性があります。--cacheMaxAgeHours で設定可能にし、ドキュメントに記載してください。

スクリプト

すべて plugins/power-pages/scripts/lib/ 配下(または記載の場所)に同梱されています。各スクリプトは単一の目的を持つ Node スクリプトで、argv を解析し、HTTPS には validation-helpers.js を使用し、JSON を標準出力に出力します。

スクリプト目的引数出力
check-env-host-binding.jsソース環境で POST GetOrgDbOrgSetting('ProjectHostEnvironmentId') を実行します--envUrl、--token{ bound, hostEnvId }
resolve-env-by-id.js$expand=properties.linkedEnvironmentMetadata,properties.permissions を指定して BAP 環境を GET します。401/403 の場合は PAC shim にフォールバックします。--source(auto|bap|pac。既定値は auto)、--bapToken(bap の場合は必須)、--envId{ found, envId, instanceUrl, instanceApiUrl, displayName, environmentSku, isManaged, permissions, sourceUsed, fallbackReason, ... }。404 の場合は { found: false, reason: "404-ambiguous" } を返します。PAC にない場合は { found: false, reason: "not-in-pac-list" } を返します
pac-bap-shim.jspac admin list --json を BAP 形式の環境リストにラップします。Az→BAP が 401 を返した場合のフォールバックとして使用します(BAP で Az CLI のファーストパーティクライアント ID を拒否するテナントがあります)。EnvironmentUrl から instanceApiUrl を導出し、PAC の Type を BAP の environmentSku にマッピングします。PE は出力できません(PAC は Platform SKU の環境を一覧表示しません)。BAP 固有のフィールド(tenantId、lastModifiedTime、permissions)は null として返されます。該当なし(CLI がすべての環境を出力)BAP 形式の環境配列
list-tenant-envs.js一覧表示に加え、環境ごとに Pipelines の有無をプローブします(solutions?$filter=uniquename eq 'msdyn_AppDeploymentAnchor'&$select=version&$top=1)。最大 10 件を並列処理します。事前フィルター:SKU、Dataverse の有無、任意の --includeName。ランキング:名前のヒントパターン、管理者権限、更新日時。上限:--maxEnvsToProbe(既定値 30)。--source(auto|bap|pac。既定値は auto)、--bapToken(bap の場合は必須)、--skus(既定値は Production。PE は常に含まれます)、--maxEnvsToProbe、--maxConcurrency、--probeTimeoutMs、--includeName、--firstHitWins{ existingCustomHosts[], existingPlatformHost, eligibleForAppInstall[], inaccessibleEnvs[], inaccessibilityBreakdown, totalEnvsInTenant, envsAfterFilter, envsProbed, hitProbeCap, earlyExitOnFirstHit, probeDurationMs, sourceUsed, fallbackReason }
verify-host-readiness.jsWhoAmI(認証を確認し、PE 検出パスで JIT をトリガーします)→ msdyn_AppDeploymentAnchor のソリューションフィルター(1 回の呼び出しで有無とバージョンを確認します)--hostEnvUrl、--hostToken、--skipWhoAmI(任意)、--minPipelinesVersion(任意){ ready, pipelinesSolutionVersion, checks: { whoami, solutions }, warnings[] }
provision-custom-host.jsD365_ProjectHost テンプレート、Production SKU、CommonDataService databaseType を指定して BAP 環境作成を POST します。Location ヘッダーを使用し、Retry-After の間隔でライフサイクル操作をポーリングします。properties.provisioningState/state/status.code の形式に対応します。5xx の一時エラー時は再試行します。401/403 の場合は明示的なガイダンスを表示します。--bapToken、--displayName、--region、--correlationId(任意)、--timeoutSec(任意、既定値 900)、--apiVersion(任意、既定値 2021-04-01){ status, envId, instanceUrl, instanceApiUrl, displayName, environmentSku, provisioningState, durationSec, correlationId, pollAttempts, locationHeader }
provision-platform-host.jsD365_1stPartyAdminApps テンプレートと Platform SKU を指定して、BAP getOrCreate を POST します。200 の冪等パス(既存の PE を返す)の場合は alreadyExisted: true を返し、202 と Location ポーリングのパス(新規にプロビジョニング)の場合は alreadyExisted: false を返します。Phase 4.0 で使用します。--bapToken、--correlationId(任意)、--timeoutSec(任意、既定値 600)、--apiVersion(任意、既定値 2021-04-01)、--bapBase(任意){ status, alreadyExisted, envId, instanceUrl, instanceApiUrl, displayName, environmentSku, provisioningState, durationSec, correlationId, pollAttempts, locationHeader }
install-pipelines-app.js既存の環境で Power Platform Pipelines アプリケーションパッケージを検出してインストールします。解決方法:BAP applicationPackages LIST + /install POST → 200 同期/202 と Location ポーリング。401/403/5xx の場合は PAC CLI にフォールバックします(pac application install --environment-id ... --application-list msdyn_AppDeploymentAnchor)。インストール POST の 409 は冪等(インストール済み)として扱います。インストール後の Dataverse 検証プローブは任意です。Phase 4.B で使用します(2026-05-08 に手動の PPAC クリック操作を置き換えました)。--bapToken、--envId、--instanceApiUrl(任意 — 検証用)、--hostToken(任意 — 検証用)、--no-pac-fallback(任意。既定では PAC にフォールバックします)、--correlationId(任意)、--timeoutSec(任意、既定値 600)、--apiVersion(任意、既定値 2022-03-01-preview)、--bapBase(任意){ status, alreadyInstalled, installPath: 'bap'|'pac'|'cached', packageUniqueName, pipelinesSolutionVersion, durationSec, correlationId, pollAttempts, locationHeader, pacFallbackReason }
ensure-pipelines-host-detect.js検出専用のオーケストレーターラッパーです。Phase 1.0(キャッシュの高速パス)+ Phase 2(テナント全体の列挙を含む解決順序)+ Phase 5(ホストが見つかった場合の検証)を実行します。常に actionTaken: "none" を出力します。plan-alm の Phase 1 と setup-pipeline の Phase 1 で使用します。既定の --source auto は BAP を先に試し、401/403 の場合は PAC CLI shim にフォールバックします — Az CLI のトークンが BAP に拒否されるテナントでも動作します。--envUrl、--token、--userId、--bapToken(--source auto または pac の場合は任意)、--source(auto|bap|pac)、--projectRoot、--cacheMaxAgeHours(任意)、--no-cache、--includeName、--maxEnvsToProbe、--skus、--minPipelinesVersiondocs/alm/last-host-check.json のスキーマ(sourceUsed、fallbackReason を含む)
validate-ensure-host.js(スキル scripts/)PostToolUse Stop-hook バリデーターです。スキーマ v1 と v2 との前方互換性があります。CannotRedirect/OrgSettingStale/PermissionDenied は文書化された終端エラー状態として扱います(ホストが使用可能でなくても、スキル自体は正常に実行されています)。該当なし(標準入力から JSON {cwd} を読み取ります)終了コード 0(承認)または終了コード 2(ブロック)
再利用される既存のヘルパー (変更なし):
  • verify-alm-prerequisites.js
  • detect-project-context.js
  • discover-pipelines-host.js (テナントのデフォルトおよびカスタムホストのプローブ。ラッパー内のフェーズ 2 ステップ 3 から呼び出されます)
  • update-skill-tracking.js

検証スクリプト

skills/ensure-pipelines-host/scripts/validate-ensure-host.js (Skill ツールに対する集中型 PostToolUse フックによって実行されます。skills/ensure-pipelines-host/SKILL.md が存在するため、このスキルは自動的に追跡されます — scripts/lib/powerpages-hook-utils.js を参照):

  • cwd に docs/alm/last-host-check.json が存在しない場合 → 終了コード 0 (ensure-host セッションではありません)。
  • 存在する場合: schemaVersion === 1 または 2 (前方互換) を検証します。必須フィールド (tenantId、sourceEnvUrl、resolutionStatus) が設定されていること。終端エラー以外のステータスでは ready === true であること。ready === true の場合に finalHostEnvUrl が設定されていること。
  • 終端エラーステータス (CannotRedirect / OrgSettingStale / PermissionDenied) は ready: false で受け入れられます — スキルは正常に実行され、手動または管理者による解決が必要な状態を検出したことを示します。
  • candidates ブロック (v2) は任意です — 存在しなくても検証は失敗しません。

併設されたプロンプトフックによるチェック:

  1. 次のいずれか: (a) フェーズ 1.0 のキャッシュ高速パスが成功し、キャッシュされたホストを再利用した、または (b) 完全なフローが実行された:
    • テナント ID ゲートが確認された。
    • ソース環境が未バインドの場合のテナント全体の列挙を含む、完全な解決順序によって RESOLUTION.status が決定された。
    • ステータスが AvailableUnbound*、MultipleUnboundCustomHosts、または PlatformHostExistsUnbound の場合、ユーザーが再利用または新規作成を明示的に選択した。
    • ステータスがプロビジョニングが必要であることを示していた場合 (NoHost)、ユーザーが明示的に選択したパスが完了した (actionTaken が fast-path-*、user-installed-*、または user-created-* の値のいずれか — つまり "none" でも "reuse-existing-*" でもない)。
  2. verify-host-readiness.js が ready: true を報告した (または文書化された終端エラー状態に到達した)。
  3. docs/alm/last-host-check.json が schemaVersion: 2 で書き込まれ、テナント全体の列挙が実行された場合には candidates ブロックが設定された。
  4. サマリーが提示された。

コメント