# 機能設計書 343-Test-DbaAgSpn

## 概要

本ドキュメントは、dbatools PowerShellモジュールのTest-DbaAgSpn関数の機能設計書である。この関数はAvailability Groupリスナー用のService Principal Name (SPN) がActive Directoryに正しく登録されているかを検証する。

### 本機能の処理概要

Test-DbaAgSpn関数は、Availability Groupリスナーに必要なSPNがActive Directoryに正しく登録されているかを検証し、Kerberos認証の問題を特定する機能を提供する。

**業務上の目的・背景**：Availability Groupリスナー経由でSQL Serverに接続する際、Kerberos認証を使用するためには適切なSPNが登録されている必要がある。SPNが未登録の場合、クライアントはWindows統合認証を使用したリスナー経由の接続に失敗するか、NTLMにフォールバックする。この関数は、リスナーのSPN設定を検証することで、Kerberos認証の問題を事前に特定し、クライアント接続の問題を予防する。

**機能の利用シーン**：新しいAvailability Groupリスナーをセットアップした後のSPN検証、クライアント接続の認証問題をトラブルシューティングする場合、セキュリティ監査の一環としてSPN設定を検証する場合に使用される。

**主要な処理内容**：
1. 指定されたSQLインスタンスからAvailability Groupとリスナー情報を取得する
2. 各リスナーに必要なSPN（インスタンス名ベースとポート番号ベース）を生成する
3. Active Directoryに対してSPNの存在を確認する
4. 検証結果を構造化されたオブジェクトとして出力する

**関連システム・外部連携**：SQL Server SMO (Availability Group/Listener情報取得)、Active Directory (SPN検証)、Get-DbaADObject内部関数によるADオブジェクト検索。

**権限による制御**：SQL ServerへのアクセスおよびActive Directoryの読み取り権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLIコマンド | 主機能 | PowerShellコマンドラインから直接実行 |

## 機能種別

検証処理（Active Directory SPN検証）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| SqlInstance | DbaInstanceParameter[] | No | 対象のSQL Serverインスタンス | SQL Server 2012以上 |
| SqlCredential | PSCredential | No | SQL Server接続用の資格情報 | 有効なPSCredentialオブジェクト |
| Credential | PSCredential | No | Active Directory接続用の資格情報 | 有効なPSCredentialオブジェクト |
| AvailabilityGroup | string[] | No | 検証対象のAvailability Group名 | AG名の配列 |
| Listener | string[] | No | 検証対象のリスナー名 | リスナー名の配列 |
| InputObject | AvailabilityGroup[] | No | パイプライン入力用AGオブジェクト | SMO AvailabilityGroupオブジェクト |
| EnableException | switch | No | 例外処理の動作を制御 | true/false |

### 入力データソース

- SqlInstance: SQL Serverインスタンス指定による直接入力
- パイプライン入力: Get-DbaAvailabilityGroupからのAvailabilityGroupオブジェクト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | string | SQL Serverホストの完全修飾ネットワーク名 |
| SqlInstance | string | SQL Serverインスタンス名 |
| InstanceName | string | インスタンス名（デフォルトはMSSQLSERVER） |
| SqlProduct | string | SQL Serverバージョンとエディション情報 |
| InstanceServiceAccount | string | SQL Serverサービスアカウント |
| RequiredSPN | string | Active Directoryに登録されるべきSPN |
| IsSet | boolean | SPNがActive Directoryに登録されているか |
| Cluster | boolean | クラスタ構成かどうか |
| TcpEnabled | boolean | TCP/IPプロトコルが有効か（常にtrue） |
| Port | int | リスナーのTCPポート番号 |
| DynamicPort | boolean | 動的ポートかどうか（常にfalse） |
| Warning | string | 警告メッセージ（またはNone） |
| Error | string | エラーメッセージ（SPNが未設定の場合は"SPN missing"） |

### 出力先

PowerShellパイプライン（PSCustomObject）

## 処理フロー

### 処理シーケンス

```
1. 入力検証
   └─ SqlInstanceまたはInputObjectが指定されているか確認
   └─ 未指定の場合はエラー終了

2. Availability Group情報取得
   └─ SqlInstance指定時はGet-DbaAvailabilityGroupで取得
   └─ InputObject指定時はそのまま使用

3. リスナー情報取得
   └─ Listener指定時はフィルタリング
   └─ 未指定時は全リスナーを対象

4. SPN生成と検証
   └─ 各リスナーに対して2種類のSPNを生成
       - MSSQLSvc/listener.domain.com（インスタンス名ベース）
       - MSSQLSvc/listener.domain.com:port（ポート番号ベース）
   └─ サービスアカウントがVirtualまたはManagedの場合は調整
   └─ Active DirectoryでSPN登録を確認

5. 結果出力
   └─ 各SPNについて検証結果オブジェクトを出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{SqlInstance or InputObject?}
    B -->|なし| C[エラー: 必須パラメータ未指定]
    B -->|SqlInstance| D[Get-DbaAvailabilityGroup]
    B -->|InputObject| E[InputObjectを使用]
    D --> F[各AGのループ]
    E --> F
    F --> G{Listener指定?}
    G -->|Yes| H[指定リスナーをフィルタ]
    G -->|No| I[全リスナーを取得]
    H --> J[各リスナーのループ]
    I --> J
    J --> K[SPN生成: インスタンス名ベース]
    K --> L[SPN生成: ポート番号ベース]
    L --> M[サービスアカウント調整]
    M --> N[ADでSPN検索]
    N --> O{SPN存在?}
    O -->|Yes| P[IsSet=true]
    O -->|No| Q[IsSet=false, Error="SPN missing"]
    P --> R[結果オブジェクト出力]
    Q --> R
    R --> S{次のSPN?}
    S -->|Yes| J
    S -->|No| T[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | SPN形式（インスタンス名） | MSSQLSvc/listener.domain.com または MSSQLSvc/listener.domain.com:InstanceName | 常に適用 |
| BR-002 | SPN形式（ポート番号） | MSSQLSvc/listener.domain.com:port | 常に適用 |
| BR-003 | 仮想アカウント処理 | LocalSystemまたはNT SERVICE\*の場合はコンピュータアカウントに変換 | 該当アカウント時 |
| BR-004 | マネージドサービスアカウント | $で終わるアカウントはコンピュータとして検索 | 該当アカウント時 |
| BR-005 | 結果キャッシュ | 同一サービスアカウントの重複検索を回避 | AD検索時 |

### 計算ロジック

該当なし

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | SQL ServerへのSELECTのみ（AG/リスナー情報取得） |

### テーブル別操作詳細

該当なし（SMO経由でのメタデータ読み取りのみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 入力検証エラー | SqlInstanceとInputObjectが両方未指定 | どちらかを指定 |
| - | AD検索失敗 | ドメイン解決不可またはアクセス権不足 | 資格情報とドメイン接続を確認 |
| - | プロパティアクセス不可 | サービスアカウントのSPN検査権限がない | 適切な権限を持つ資格情報を使用 |

### リトライ仕様

明示的なリトライ機能はなし。ADキャッシュ（resultCache）により同一アカウントの重複検索を回避。

## トランザクション仕様

読み取り専用操作のため、トランザクション管理は不要。

## パフォーマンス要件

- resultCacheにより同一サービスアカウントの重複AD検索を回避
- 大量のリスナーがある場合はAD検索回数に応じた時間が必要

## セキュリティ考慮事項

- SQL Serverへの接続にはSqlCredentialを使用可能
- Active Directory検索にはCredentialを使用可能
- 読み取り専用操作のため、セキュリティリスクは低い
- CredentialおよびDomainName プロパティはデフォルト表示から除外

## 備考

- Microsoft公式ドキュメント（AG リスナーとSPN設定）を参考に実装
- Get-DbaAvailabilityGroupとのパイプライン連携をサポート
- Set-DbaSpnとのパイプライン連携で未登録SPNを自動設定可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

出力されるPSCustomObjectの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Test-DbaAgSpn.ps1 | `public/Test-DbaAgSpn.ps1` | 144-159行目と161-176行目の出力オブジェクト構造を確認 |

**読解のコツ**: 各リスナーに対して2つのSPNオブジェクト（インスタンス名ベースとポート番号ベース）が生成される。

#### Step 2: エントリーポイントを理解する

関数の入口と主要パラメータを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Test-DbaAgSpn.ps1 | `public/Test-DbaAgSpn.ps1` | 92-102行目のパラメータ定義を確認 |

**主要処理フロー**:
1. **92-102行目**: param()ブロックでパラメータ定義
2. **103-107行目**: begin{}ブロックで結果キャッシュを初期化

#### Step 3: 処理ロジックを理解する

processブロック内の主要処理を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Test-DbaAgSpn.ps1 | `public/Test-DbaAgSpn.ps1` | 108-228行目のprocess{}ブロック |

**主要処理フロー**:
- **109-116行目**: 入力検証とAvailability Group取得
- **118-124行目**: リスナーの取得とフィルタリング
- **127-177行目**: 各リスナーに対するSPN生成
- **180-227行目**: AD検索とSPN検証

#### Step 4: SPN生成ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Test-DbaAgSpn.ps1 | `public/Test-DbaAgSpn.ps1` | 134-142行目: FQDN生成、138-142行目: SPN形式決定 |

**主要処理フロー**:
- **134-136行目**: FQDNとリスナーDNS名の構築
- **138-142行目**: インスタンス名に基づくSPN形式の決定
- **161-167行目**: ポート番号ベースのSPN生成

### プログラム呼び出し階層図

```
Test-DbaAgSpn
    │
    ├─ Get-DbaAvailabilityGroup (SqlInstance指定時)
    │      └─ SQL Server SMO経由でAG情報取得
    │
    ├─ Get-DbaAgListener
    │      └─ SQL Server SMO経由でリスナー情報取得
    │
    ├─ Get-DbaADObject (private/functions/Get-DbaADObject.ps1)
    │      └─ AD検索でサービスアカウント取得
    │
    └─ $result.GetUnderlyingObject().Properties.servicePrincipalName
           └─ SPN登録確認
```

### データフロー図

```
[入力]                       [処理]                              [出力]

SqlInstance ──────┬──▶ Get-DbaAvailabilityGroup ──▶ AG情報
                  │              │
InputObject ──────┘              ▼
                         Get-DbaAgListener ──▶ リスナー情報
                                │
                                ▼
                         SPN形式生成 ───────▶ 2種類のSPN
                         (インスタンス名/ポート)     │
                                │                    │
                                ▼                    │
                         Get-DbaADObject ───────────┤
                                │                    │
                                ▼                    ▼
                         SPN存在確認 ──────▶ PSCustomObject
                                            (検証結果)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Test-DbaAgSpn.ps1 | `public/Test-DbaAgSpn.ps1` | ソース | メイン関数 |
| Get-DbaADObject.ps1 | `private/functions/Get-DbaADObject.ps1` | ソース | ADオブジェクト検索の内部関数 |
| Get-DbaAvailabilityGroup.ps1 | `public/Get-DbaAvailabilityGroup.ps1` | ソース | AG情報取得関数 |
| Get-DbaAgListener.ps1 | `public/Get-DbaAgListener.ps1` | ソース | リスナー情報取得関数 |
| Set-DbaSpn.ps1 | `public/Set-DbaSpn.ps1` | ソース | パイプライン出力先として使用可能 |
