Microsoft Entra IDのTemporary Access Pass(TAP)を一括発行して安全にメール配布する方法【PowerShell解説】

「Microsoft Entra ID の Temporary Access Pass(TAP)を 200 名分まとめて発行して、社外メール宛てに安全に配りたい」――そんなときに必要なのは、難解なスクリプトではなく、仕組みと落とし穴を理解したうえでの“現場で回せる”運用設計です。本記事では、一括発行からメール配布、権限・ポリシー・自動化まで、実務に耐えるやり方をサンプルコード付きで整理します。

目次

Temporary Access Pass(TAP)とは何か

Temporary Access Pass(TAP)は、Microsoft Entra ID(旧 Azure AD)が提供する時間制限付きのサインイン用コードです。パスワードレス認証や MFA 登録、認証方法喪失時の復旧などの「ブートストラップ(立ち上げ)」用途で使われます。

項目内容
用途初回サインイン、パスワードレス(FIDO2/パスキー/Authenticator)登録、認証情報紛失時の復旧など
特徴有効期限付き・回数制限(単回/複数回)付きのコード。1 ユーザーにつき有効 TAP は 1 つだけ。
発行方法Entra 管理センターの GUI、または Graph API / Microsoft Graph PowerShell(New-MgUserAuthenticationTemporaryAccessPassMethod)
利用イメージTAP で一度サインイン → セキュリティ情報ページで FIDO2 や Microsoft Authenticator を登録 → 以降はパスワードレスで運用

TAP は「一時的にサインインを許可して、本命の認証方法を登録させるための足がかり」と考えると分かりやすいです。

TAP のポリシー(有効期間や長さ)のざっくり仕様

TAP の寿命やコード長などは、テナント単位の TAP ポリシーで制御されます。代表的な設定値は次の通りです。

設定項目既定値の例許可される範囲ポイント
最小有効期間(Minutes)60 分(1 時間)10 ~ 43,200 分(最大 30 日)ここで指定した値未満の TAP は作れない
最大有効期間(Minutes)480 分(8 時間)10 ~ 43,200 分管理者が発行できる TAP の上限時間
既定有効期間(Minutes)60 分最小~最大の範囲内GUI から TAP を作成したときのデフォルト値
単回利用かどうか既定では「複数回利用可」のことが多い単回利用 / 複数回利用テナントポリシーで「常に単回のみ」に固定することも可能

なお、1 ユーザーに有効な TAP は 1 個だけです。新しく TAP を作成すると、既存の TAP が有効期間内でも自動的に置き換えられます。

なぜ「一括発行」は簡単なのに「配布」が難しいのか

Microsoft Graph PowerShell SDK を使えば、New-MgUserAuthenticationTemporaryAccessPassMethod で TAP 自体を大量発行するのは難しくありません。

本当に悩ましいのは次の 2 点です。

  • どうやって本人だけに安全に TAP を届けるか
  • PowerShell に不慣れな運用担当でも回せる運用にできるか

とくに TAP は「まだサインインできない人に渡すコード」なので、次のような制約が出ます。

  • 社用 M365 メールアドレス(@contoso.com)に送っても、本人がまだサインインできない
  • 初期パスワードと同様、万一漏れるとアカウント乗っ取りのリスクがある
  • CSV やログに TAP を残したままにすると、後から誰でも見えてしまう

したがって、「一括発行+安全な配布」を実現するには、技術要素(Graph / PowerShell)と運用設計(連絡先・権限・ログ方針)をセットで設計する必要があります。

現場向けの現実解:おすすめアーキテクチャ

ここでは「最大 200 名規模のユーザーに TAP を一括発行し、外部メールアドレスに配る」という前提で、現実的かつシンプルな構成を示します。

コンポーネント役割実装イメージ
① 連絡先一覧対象ユーザーと送信先外部メールを紐づけるUPN / ObjectId と 外部メールアドレスを持つ CSV
② TAP ポリシーTAP の有効期間や単回利用設定を制御Entra 管理センターの「認証方法 > Temporary Access Pass」ポリシー
③ 送信元メールボックスTAP を送信する差出人専用サービスアカウント or 共有メールボックス
④ スクリプト実行環境一括発行とメール送信を実行管理者 PC の PowerShell、のちに Azure Automation へ移行
⑤ ログ・監査「誰にいつ送ったか」を追跡ユーザー ID / 宛先 / 実行日時 / 成否のみ CSV に出力(TAP 本体は記録しない)

① 連絡先の確保:CSV + 認証方法メールの併用

まず、最低限次の 2 列を持つ CSV を用意します。

ID,Email
[email protected],[email protected]
[email protected],
  • ID … ユーザーの UPN か ObjectId(どちらでも可)
  • Email … TAP を送りたい 社外メール(個人メール等)

運用上は、Email が空のユーザーも出てくるので、その場合は Entra の「認証方法に登録済みメール(emailAuthenticationMethod)」を Graph から取得して補完します。

② TAP ポリシーの設計

Entra 管理センター > Entra ID > 認証方法 > ポリシー > Temporary Access Pass から、TAP ポリシーを有効化します。

  • テスト用に「検証グループ」を作り、そのグループをポリシーの対象にする
  • 最小/最大/既定の有効期間と、単回利用の既定値を決めておく
  • 一括発行スクリプトで指定する lifetimeInMinutes は、この最小~最大の範囲内で設定する

例えば「入社当日だけ有効にしたい」なら 4~8 時間程度、「トラブル対応用」なら 1~2 時間など、用途ごとにガイドラインを決めておくと運用しやすくなります。

③ 送信者(差出人)設計

おすすめは「専用のサービスアカウント」を差出人にするパターンです。

  • 例:[email protected] というライセンス付きアカウントを 1 つ用意
  • このアカウントで Graph にサインインし、そのまま差出人として利用
  • 必要に応じて、共有メールボックスや Microsoft 365 グループに対して Send As 権限を付与し、From を切り替える

Graph 経由でメールを送るには、少なくとも Mail.Send(もしくは「他人のメールボックスから送る」場合は Mail.Send.Shared)の権限が必要です。

④ 運用基盤:まずは手動 PowerShell、慣れたら自動化

いきなり Azure Automation や Logic Apps で自動化に振るより、次のステップを踏む方が安全です。

  1. 管理者 PC 上で PowerShell スクリプトを手動実行(少人数でテスト)
  2. 対象を 50 ~ 200 名に広げて、本番に近い形で検証
  3. 安定したら Azure Automation Runbook(マネージド ID+スケジュール)や Logic Apps で半自動化

なお、Entra ID Governance(P2 ライセンス)を利用している場合は、Lifecycle Workflows の「Generate Temporary Access Pass and send via email to user’s manager」タスクを使うと、GUI ベースで「TAP を自動生成し、マネージャー宛てにメール送信」することも可能です。ただし、宛先は基本的に「ユーザー本人やマネージャーの mail 属性」であり、任意の個人メール宛てに柔軟に送る用途にはやや不向きです。

⑤ セキュリティ配慮ポイント

  • メールの 件名には TAP を書かない(本文のみ)
  • TAP 本文をそのままログや監査ファイルに残さない
  • 必要に応じて M365 メッセージ暗号化 や、外部宛てメールの DLP ポリシーを検討
  • 誤送信対策として、事前に CSV の宛先メールをダブルチェックする

事前準備:必要権限と前提条件

必要なロール・権限

TAP の作成と送信には、概ね次の権限が必要です。

種類内容用途
Entra ロールAuthentication Administrator または Authentication Policy Administrator(+ユーザー管理系ロール)などTAP ポリシーの設定と、対象ユーザーへの TAP 発行
Graph スコープUserAuthenticationMethod.ReadWrite.AllTAP や emailAuthenticationMethod の作成・更新
Graph スコープUser.Read.All(利用ユーザー一覧参照用)任意(ID の解決やログ用途)
Graph スコープMail.Send(場合により Mail.Send.Shared)メール送信

New-MgUserAuthenticationTemporaryAccessPassMethod 自体には UserAuthenticationMethod.ReadWrite.All が要求されます。

また、認証方法メールを読み出す Get-MgUserAuthenticationEmailMethod には、UserAuthenticationMethod.Read.All または ReadWrite 系の権限が必要です。

PowerShell モジュール

最新の Microsoft Graph PowerShell モジュールを利用します。

# 管理者権限で一度だけ実行
Install-Module Microsoft.Graph -Scope AllUsers

# TAP 関連のコマンドレットが含まれるモジュール
Import-Module Microsoft.Graph.Identity.SignIns
Import-Module Microsoft.Graph.Users.Actions

実装フロー:一括発行とメール配布のステップ

ステップ 1:Graph に接続

$scopes = @(
  "UserAuthenticationMethod.ReadWrite.All",
  "User.Read.All",
  "Mail.Send"
)

Connect-MgGraph -Scopes $scopes

初回実行時はブラウザが開き、指定スコープに対する同意(管理者承認)が求められます。

ステップ 2:CSV の読み込み

$CsvPath           = "C:\temp\tap_targets.csv"  # ID,Email 列入り
$ResultLog         = "C:\temp\tap_results.csv"
$LifetimeInMinutes = 240                         # TAP 有効期間(例:4 時間)
$IsUsableOnce      = $true                       # 単回利用なら $true
$SenderUserId      = "[email protected]"       # Connect-MgGraph でサインインするアカウント
$FromAddress       = "[email protected]"       # メールの差出人(基本は SenderUserId と同じ)

$targets = Import-Csv $CsvPath
$results = @()

ステップ 3:TAP 発行とメール送信(サンプルスクリプト)

以下が、実務でそのまま流用しやすい最小構成のサンプルです(分かりやすさ優先)。

# 前提: Microsoft.Graph モジュールをインストール済み
# Install-Module Microsoft.Graph -Scope AllUsers

Import-Module Microsoft.Graph.Identity.SignIns
Import-Module Microsoft.Graph.Users.Actions

$CsvPath           = "C:\temp\tap_targets.csv"  # ID,Email 列
$ResultLog         = "C:\temp\tap_results.csv"
$LifetimeInMinutes = 240                        # 例: 4 時間(TAP ポリシーの範囲内に収める)
$IsUsableOnce      = $true                      # 単回利用なら $true
$SenderUserId      = "[email protected]"      # Graph でサインインするユーザー(サービスアカウント)
$FromAddress       = "[email protected]"      # 差出人(共有メールボックス等に差し替え可)

Connect-MgGraph -Scopes `
  "UserAuthenticationMethod.ReadWrite.All",`
  "User.Read.All",`
  "Mail.Send"

$targets = Import-Csv $CsvPath
$results = @()

foreach ($t in $targets) {
  $recipient = $null

  try {
    # 1) TAP を発行
    $tapBody = @{
      startDateTime      = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
      lifetimeInMinutes  = $LifetimeInMinutes
      isUsableOnce       = $IsUsableOnce
    }

    $tap = New-MgUserAuthenticationTemporaryAccessPassMethod `
             -UserId $t.ID `
             -BodyParameter $tapBody

    # TemporaryAccessPass プロパティは作成時にしか取得できないので、ここで必ず保管(後で再取得不可)
    $tapCode = $tap.TemporaryAccessPass

    if (-not $tapCode) {
      throw "TAP コードを取得できませんでした(ID=$($t.ID))"
    }

    # 2) 宛先メールの決定(CSV が優先、なければ認証方法メール)
    $recipient = $t.Email

    if ([string]::IsNullOrWhiteSpace($recipient)) {
      $authEmails = Get-MgUserAuthenticationEmailMethod -UserId $t.ID -All -ErrorAction SilentlyContinue
      $recipient  = $authEmails | Select-Object -ExpandProperty EmailAddress -First 1
    }

    if ([string]::IsNullOrWhiteSpace($recipient)) {
      throw "宛先メールが見つかりません(ID=$($t.ID))"
    }

    # 3) メール本文(件名には TAP を書かない)
    $expiresAtLocal = (Get-Date).AddMinutes($LifetimeInMinutes).ToString("yyyy/MM/dd HH:mm")
    $emailBody = @"
<html><body>
<p>一時アクセス パス(Temporary Access Pass: TAP)のご案内です。</p>
<p><strong>TAP コード:</strong> $tapCode</p>
<p>有効期限(目安): $expiresAtLocal<br />
※ 実際の有効期限はテナントの TAP ポリシー設定に依存します。</p>
<p>【ご注意】<br />
・本コードは第三者と共有しないでください。<br />
・コードを使ったら、速やかにパスワードレス認証(FIDO2 キー / Authenticator など)の登録を完了してください。</p>
</body></html>
"@

    $params = @{
      Message = @{
        Subject = "【TAP】一時アクセス パスのご案内"
        Body    = @{
          ContentType = "HTML"
          Content     = $emailBody
        }
        ToRecipients = @(
          @{
            EmailAddress = @{ Address = $recipient }
          }
        )
        From = @{
          EmailAddress = @{ Address = $FromAddress }
        }
      }
      SaveToSentItems = $true
    }

    # 4) メール送信
    Send-MgUserMail -UserId $SenderUserId -BodyParameter $params

    $results += [pscustomobject]@{
      UserId = $t.ID
      To     = $recipient
      Status = "Sent"
      Time   = (Get-Date)
    }

    Start-Sleep -Milliseconds 200  # 緩いスロットリング対策
  }
  catch {
    Write-Warning $_.Exception.Message

    $results += [pscustomobject]@{
      UserId = $t.ID
      To     = $recipient
      Status = "Error: $($_.Exception.Message)"
      Time   = (Get-Date)
    }
  }
}

$results | Export-Csv -NoTypeInformation -Encoding UTF8 $ResultLog

Disconnect-MgGraph

ポイントだけ抜き出すと、次のようになります。

  • New-MgUserAuthenticationTemporaryAccessPassMethod に startDateTime, lifetimeInMinutes, isUsableOnce を BodyParameter で渡す(公式ドキュメントの推奨形)。
  • TAP コード(TemporaryAccessPass)は作成時にしか取得できないため、その場でメールに埋め込む。後から Get-MgUserAuthenticationTemporaryAccessPassMethod で再取得しても値は返らない。
  • 宛先メールは CSV > 認証方法メールの優先順で決定し、それでも無ければ例外としてログに記録する。
  • ログには TAP 本体を残さず、UserId / To / Status / Time だけを出力する。

PowerShell が苦手な運用担当へのフォロー案

「スクリプトを触りたくない」という運用担当に丸投げするのは危険です。現場では、次のような“妥協案”が現実的です。

1. 実行専任者+運用担当の役割分担

  • インフラ担当(PowerShell に慣れている人)が、スクリプトのメンテナンスと実行を担当
  • 運用担当は、「CSV の作成」「テストユーザーでの動作確認」「ユーザー問い合わせ対応」を担当
  • 「手順書+スクリーンショット」で、毎回の操作をほぼクリックだけで済む形にしておく

2. バッチファイルでラップしてあげる

運用担当には run_tap_bulk.bat を渡しておき、ダブルクリックで実行させる方式にすると心理的ハードルが下がります。

@echo off
pwsh -ExecutionPolicy Bypass -File "C:\temp\tap_bulk_issue.ps1"
pause

3. Logic Apps / Power Automate / Lifecycle Workflows への発展

  • Azure Logic Apps で
    • トリガー:手動 or スケジュール
    • アクション:ストレージ上の CSV を読む → Graph API で TAP 発行 → Outlook コネクタでメール送信
  • Entra Lifecycle Workflows(P2)で
    • 「Generate Temporary Access Pass and send via email to user’s manager」タスクを使って入社日に自動発行
    • 宛先はマネージャーになるが、「マネージャーから本人に共有する」という運用を徹底すれば、現場負荷を減らせる

無料で「完全な TAP 一括発行 GUI ツール」が提供されているわけではないため、PowerShell スクリプトを最小限ラップしてあげるのが、コストと自由度のバランスが良いアプローチです。

よくある詰まりポイントと対処法

症状原因対処
New-MgUserAuthenticationTemporaryAccessPassMethod 実行時に「Request Authorization failed」Graph スコープが不足(UserAuthenticationMethod.ReadWrite.All 未付与)Connect-MgGraph -Scopes "UserAuthenticationMethod.ReadWrite.All", ... で接続し、テナント管理者に同意をもらう。
Send-MgUserMail で Access DeniedMail.Send 権限不足、または送信先のメールボックスに Send As / Send On Behalf 権限がないシンプルに「サインイン中の自分のメールボックス」から送る構成にするか、必要に応じて Mail.Send.Shared と Exchange 側の Send As を付与。
TAP 発行時に「Validation エラー」(lifetime エラーなど)lifetimeInMinutes が TAP ポリシーの最小/最大範囲外ポリシーの minimumLifetimeInMinutes / maximumLifetimeInMinutes を確認し、その範囲内で値を指定する。
ユーザーが TAP を入力してもサインインできないTAP ポリシーでそのユーザー/グループが有効になっていない TAP の有効時間を過ぎている 単回利用 TAP をすでに 1 回使い切っているポリシーの対象グループを確認し、Get-MgUserAuthenticationTemporaryAccessPassMethod で TAP の状態(isUsable, methodUsabilityReason)を確認。
宛先メールが取れないユーザーがいるCSV にも emailAuthenticationMethod にもメールが登録されていない事前に「外部連絡先メールの登録」を入社フローに組み込む/手作業で補完する
「PowerShell が怖い」と言われる黒い画面に慣れていない上記のバッチラッパー+画面付き手順書+少人数テストで心理的ハードルを下げる

運用ベストプラクティスまとめ

  • 最小権限の原則
    • TAP 発行用の専用サービスアカウントを作り、不要な管理ロールは付与しない
    • Graph スコープも「UserAuthenticationMethod.ReadWrite.All」「Mail.Send」など必要最低限に絞る
  • ログと監査
    • 誰にいつ TAP を送ったかは CSV ログに残すが、TAP 本体は保存しない
    • 必要であれば、結果 CSV を SharePoint / OneDrive に保存し、アクセス権を限定
  • メッセージの保護
    • 高リスクなユーザー(経営層など)には、メッセージ暗号化や期限付きリンクを検討
    • メールテンプレートはシンプルにし、フィッシングと紛らわしくならないようにする
  • 段階導入
    • まず 3~5 名でテスト → 10~20 名のパイロット → 50~200 名の本番と段階的に拡大
    • テストフェーズで「ユーザー側の操作マニュアル(スクリーンショット付き)」を整備
  • TAP だけで終わらせない
    • TAP 利用後は、必ず FIDO2 や Microsoft Authenticator を登録させる(https://aka.ms/mysecurityinfo へのリンクを案内メールに含める)。
    • 必要に応じて passwordProfile.forceChangePasswordNextSignIn を設定し、パスワード変更を強制するワークフローを別途実装

おわりに:TAP 一括発行は「配布設計」が 8 割

TAP 自体の発行処理は、Graph PowerShell で数行書けば簡単に一括実行できます。しかし実務で問題になりがちなのは、

  • どのメールアドレスに送るか(外部連絡先の整備)
  • だれがいつスクリプトを実行するか(権限と責任分界)
  • 誤送信・情報漏えいをどう防ぐか(ログと監査)

といった「運用設計」の部分です。

本記事のサンプル構成(CSV+Graph PowerShell+専用サービスアカウント+簡易ログ)をベースに、組織の規模やセキュリティ要件にあわせてアレンジすれば、最大 200 名規模の TAP 一括発行・配布は十分現実的に運用できます。まずは小さく試し、段階的に自動化・高度化していくのがおすすめです。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次