「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 で自動化に振るより、次のステップを踏む方が安全です。
- 管理者 PC 上で PowerShell スクリプトを手動実行(少人数でテスト)
- 対象を 50 ~ 200 名に広げて、本番に近い形で検証
- 安定したら 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.All | TAP や 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 Denied | Mail.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 一括発行・配布は十分現実的に運用できます。まずは小さく試し、段階的に自動化・高度化していくのがおすすめです。

コメント