# 機能設計書 345-Test-DbaSpn

## 概要

本ドキュメントは、dbatools PowerShellモジュールのTest-DbaSpn関数の機能設計書である。この関数はSQL Serverインスタンスに必要なSPNがActive Directoryに正しく登録されているかを検証する。

### 本機能の処理概要

Test-DbaSpn関数は、対象コンピュータ上のSQL Serverインスタンスを検出し、各インスタンスに必要なSPNを生成してActive Directoryでの登録状態を確認する機能を提供する。

**業務上の目的・背景**：Kerberos認証を使用するためには、SQL ServerサービスアカウントにSPNが正しく登録されている必要がある。SPNの設定ミスや登録漏れは、Kerberos認証失敗やダブルホップ問題の原因となる。この関数は、SPNの完全な監査を実行し、設定の問題を特定することで、Kerberos認証環境の構築と維持を支援する。

**機能の利用シーン**：Kerberos認証の問題をトラブルシューティングする場合、セキュリティ監査の一環としてSPN設定を検証する場合、サーバー移行前にSPN設定を確認する場合、定期メンテナンスでSPN設定の健全性を確認する場合に使用される。

**主要な処理内容**：
1. WMI経由で対象コンピュータ上のSQL Serverインスタンスを検出する
2. 各インスタンスのTCP/IP設定とポート情報を取得する
3. 必要なSPN（インスタンス名ベースとポート番号ベース）を生成する
4. Active DirectoryでSPN登録状態を確認する
5. 検証結果を構造化されたオブジェクトとして出力する

**関連システム・外部連携**：SQL Server WMI Provider、Active Directory、Get-DbaADObject内部関数、Invoke-ManagedComputerCommand内部関数。

**権限による制御**：対象コンピュータへのWMIアクセス権限およびActive Directoryの読み取り権限が必要。

## 関連画面

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

## 機能種別

検証処理（Active Directory SPN検証）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ComputerName | DbaInstanceParameter[] | Yes | 対象のコンピュータ名 | コンピュータ名/IP/FQDN |
| Credential | PSCredential | No | リモート接続およびAD検索用の資格情報 | 有効なPSCredentialオブジェクト |
| EnableException | switch | No | 例外処理の動作を制御 | true/false |

### 入力データソース

- パラメータ指定: ComputerName直接指定
- パイプライン入力: ValueFromPipelineによるコンピュータ名リスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | string | コンピュータ名（クラスタの場合は仮想サーバー名） |
| InstanceName | string | SQL Serverインスタンス名（デフォルトは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プロトコルが有効か |
| Port | string/null | リスニングポート番号 |
| DynamicPort | boolean | 動的ポートかどうか |
| Warning | string | 警告メッセージ（またはNone） |
| Error | string | エラーメッセージ（SPNが未設定の場合は"SPN missing"） |

### 出力先

PowerShellパイプライン（PSCustomObject）

## 処理フロー

### 処理シーケンス

```
1. ホスト名解決
   └─ Resolve-DbaNetworkNameでFQDNを取得
   └─ IPアドレス解決に失敗した場合はスキップ

2. SQL Serverインスタンス検出（WMI経由）
   └─ Invoke-ManagedComputerCommandでWMI接続
   └─ 各インスタンスのサービス情報を取得
   └─ TCP/IPプロトコル設定を確認

3. SPN生成
   └─ TCP/IP有効なインスタンスのみ対象
   └─ デフォルトインスタンス: MSSQLSvc/hostname
   └─ 名前付きインスタンス: MSSQLSvc/hostname:instancename
   └─ ポートベースSPN: MSSQLSvc/hostname:port

4. 動的ポート処理
   └─ IPAll設定を確認
   └─ 各IPアドレスの設定を確認
   └─ 動的ポートの場合はWarning付与

5. Active DirectoryでSPN検証
   └─ 仮想/マネージドアカウントはコンピュータアカウントに変換
   └─ Get-DbaADObjectでサービスアカウント検索
   └─ servicePrincipalName属性を確認

6. 結果出力
   └─ 各SPNについて検証結果オブジェクトを出力
   └─ SPN未登録時はError="SPN missing"を設定
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[Resolve-DbaNetworkName]
    B --> C{IP解決成功?}
    C -->|No| D[スキップ]
    C -->|Yes| E[Invoke-ManagedComputerCommand]
    E --> F[各インスタンスのループ]
    F --> G{TCP/IP有効?}
    G -->|No| H[TcpEnabled=false]
    G -->|Yes| I[SPN生成: インスタンス名ベース]
    H --> J[次のインスタンス]
    I --> K[ポート情報取得]
    K --> L{動的ポート?}
    L -->|Yes| M[Warning="Dynamic port is enabled"]
    L -->|No| N[Port設定]
    M --> O[SPN生成: ポート番号ベース]
    N --> O
    O --> P[サービスアカウント調整]
    P --> Q[Get-DbaADObjectでAD検索]
    Q --> R{SPN存在?}
    R -->|Yes| S[IsSet=true]
    R -->|No| T[IsSet=false, Error="SPN missing"]
    S --> U[結果オブジェクト出力]
    T --> U
    U --> J
    J --> F
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | SPN形式（デフォルトインスタンス） | MSSQLSvc/hostname | InstanceName = MSSQLSERVER |
| BR-002 | SPN形式（名前付きインスタンス） | MSSQLSvc/hostname:instancename | InstanceName != MSSQLSERVER |
| BR-003 | SPN形式（ポート番号） | MSSQLSvc/hostname:port | 常に生成 |
| BR-004 | 仮想アカウント処理 | LocalSystemまたはNT SERVICE\*の場合はコンピュータアカウントに変換 | 該当アカウント時 |
| BR-005 | マネージドサービスアカウント | $で終わるアカウントはコンピュータとして検索 | 該当アカウント時 |
| BR-006 | 動的ポート警告 | 動的ポート使用時はWarning出力 | TcpDynamicPorts設定時 |
| BR-007 | IPAll優先 | IPAll設定がある場合は他の設定を上書き | IPAll設定時 |
| BR-008 | クラスタ対応 | クラスタインスタンスは仮想サーバー名を使用 | Clustered=true時 |
| BR-009 | 結果キャッシュ | 同一サービスアカウントの重複検索を回避 | AD検索時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし（WMIとAD操作のみ） |

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 名前解決失敗 | IPアドレス解決不可 | DNSとネットワーク接続を確認 |
| - | WMI接続失敗 | 対象コンピュータへのWMI接続失敗 | WMI設定と権限を確認 |
| - | AD検索失敗 | ドメイン解決不可またはアクセス権不足 | 資格情報とドメイン接続を確認 |
| - | プロパティアクセス不可 | サービスアカウントのSPN検査権限がない | 適切な権限を持つ資格情報を使用 |

### リトライ仕様

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

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

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

## パフォーマンス要件

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

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

- 対象コンピュータへのWMIアクセス権限が必要
- Active Directory読み取り権限が必要
- 読み取り専用操作のためセキュリティリスクは低い
- CredentialおよびDomainNameプロパティはデフォルト表示から除外

## 備考

- Set-DbaSpnおよびRemove-DbaSpnとのパイプライン連携をサポート
- 出力オブジェクトはSet-DbaSpnで直接使用可能（IsSet -eq $falseのフィルタリング後）
- 複数コンピュータの一括検証をサポート
- クラスタインスタンスの仮想サーバー名を自動検出

---

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

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

### 推奨読解順序

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

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

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

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

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

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

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

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

#### Step 3: WMI経由のインスタンス検出を理解する

ScriptBlockの処理を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Test-DbaSpn.ps1 | `public/Test-DbaSpn.ps1` | 107-227行目のScriptBlock定義 |

**主要処理フロー**:
- **117-135行目**: 出力オブジェクトの初期化
- **142-152行目**: クラスタ仮想サーバー名の処理
- **162-172行目**: TCP/IP設定の確認とSPN形式決定
- **177-225行目**: ポート情報の取得と動的ポート処理

#### Step 4: AD検索とSPN検証を理解する

processブロックの後半を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Test-DbaSpn.ps1 | `public/Test-DbaSpn.ps1` | 236-284行目のAD検索処理 |

**主要処理フロー**:
- **237-245行目**: サービスアカウントタイプの判定と変換
- **249-261行目**: Get-DbaADObjectでのAD検索（キャッシュ利用）
- **262-276行目**: SPN存在確認
- **277-279行目**: SPN未登録時のエラー設定

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

```
Test-DbaSpn
    │
    ├─ Resolve-DbaNetworkName
    │      └─ ホスト名をFQDNに解決
    │
    ├─ Invoke-ManagedComputerCommand
    │      └─ WMI経由でSQL Serverインスタンス検出
    │             ├─ $wmi.ServerInstances
    │             ├─ $wmi.Services
    │             └─ ServerProtocols (TCP/IP設定)
    │
    └─ Get-DbaADObject (private/functions/Get-DbaADObject.ps1)
           └─ AD検索でサービスアカウント取得
                  └─ servicePrincipalName属性確認
```

### データフロー図

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

ComputerName ──────▶ Resolve-DbaNetworkName ──▶ FQDN取得
                            │
                            ▼
                     Invoke-ManagedComputerCommand
                            │
                            ▼
                     WMI: ServerInstances ──▶ インスタンス一覧
                            │
                            ▼
                     TCP/IP設定確認 ───────▶ ポート/動的ポート
                            │
                            ▼
                     SPN形式生成 ──────────▶ RequiredSPN
                            │
                            ▼
                     Get-DbaADObject ─────▶ ADアカウント
                            │
                            ▼
                     SPN存在確認 ──────────▶ PSCustomObject
                                            (検証結果)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Test-DbaSpn.ps1 | `public/Test-DbaSpn.ps1` | ソース | メイン関数 |
| Get-DbaADObject.ps1 | `private/functions/Get-DbaADObject.ps1` | ソース | ADオブジェクト検索の内部関数 |
| Resolve-DbaNetworkName.ps1 | `public/Resolve-DbaNetworkName.ps1` | ソース | ホスト名解決関数 |
| Invoke-ManagedComputerCommand.ps1 | `private/functions/Invoke-ManagedComputerCommand.ps1` | ソース | WMI実行の内部関数 |
| Set-DbaSpn.ps1 | `public/Set-DbaSpn.ps1` | ソース | パイプライン出力先として使用可能 |
| Remove-DbaSpn.ps1 | `public/Remove-DbaSpn.ps1` | ソース | パイプライン出力先として使用可能 |
