# 画面設計書 142-SPN管理

## 概要

本ドキュメントは、dbatools PowerShellモジュールにおけるSQL ServerのService Principal Name（SPN）管理機能の設計仕様を定義する。

### 本画面の処理概要

Active DirectoryにおけるSQL ServerのSPN（Service Principal Name）を管理するための機能群を提供する。SPNはKerberos認証において不可欠な要素であり、正しく構成されていない場合、統合Windows認証が失敗したり、二重ホップ問題が発生したりする。

**業務上の目的・背景**：SQL ServerがKerberos認証を使用するためには、適切なSPNがActive Directoryに登録されている必要がある。SPNが欠落、重複、または誤った設定になっている場合、クライアントはSQL Serverに対してKerberos認証を使用できず、NTLM認証にフォールバックする。これにより、リンクサーバーや分散クエリなどのシナリオでセキュリティ上の問題や機能制限が発生する。本機能を使用することで、SPNの監査、登録、削除、検証を自動化し、Kerberos認証環境を適切に維持できる。

**画面へのアクセス方法**：PowerShellコンソールまたはスクリプトから以下のコマンドを実行する。
- `Get-DbaSpn` - 既存SPNの取得
- `Set-DbaSpn` - SPNの登録（委任設定含む）
- `Remove-DbaSpn` - SPNの削除（委任設定含む）
- `Test-DbaSpn` - SPN構成の検証

**主要な操作・処理内容**：
1. SPN取得（Get-DbaSpn）：コンピュータ名またはサービスアカウント名を指定して、Active Directoryに登録されているSPNを取得
2. SPN登録（Set-DbaSpn）：指定したサービスアカウントにSPNを登録し、オプションで制約付き委任も設定
3. SPN削除（Remove-DbaSpn）：SPNをサービスアカウントから削除し、関連する委任設定もクリーンアップ
4. SPN検証（Test-DbaSpn）：SQL ServerインスタンスのSPN構成を検証し、必要なSPNが正しく登録されているかを確認

**画面遷移**：CLIベースのため画面遷移は存在しない。Test-DbaSpnの出力をSet-DbaSpnやRemove-DbaSpnにパイプラインで渡すことで、不足SPNの一括登録や既存SPNの一括削除が可能。

**権限による表示制御**：Active Directory操作にはドメインへの書き込み権限が必要。Credentialパラメータにより代替資格情報を指定可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 340 | Get-DbaSpn | 主機能 | SPNの取得 |
| 342 | Set-DbaSpn | 主機能 | SPNの設定 |
| 341 | Remove-DbaSpn | 主機能 | SPNの削除 |
| 345 | Test-DbaSpn | 補助機能 | SPNのテスト・検証 |
| - | Get-DbaADObject | 補助機能 | Active Directoryオブジェクト取得 |
| - | Resolve-DbaNetworkName | 補助機能 | ネットワーク名解決 |

## 画面種別

コマンドラインインターフェース（CLI）/ PowerShell関数

## URL/ルーティング

```powershell
# SPNの取得
Get-DbaSpn -ComputerName <コンピュータ名>
Get-DbaSpn -AccountName <ドメイン\アカウント名>

# SPNの設定
Set-DbaSpn -SPN <SPN> -ServiceAccount <ドメイン\アカウント名>

# SPNの削除
Remove-DbaSpn -SPN <SPN> -ServiceAccount <ドメイン\アカウント名>

# SPNの検証
Test-DbaSpn -ComputerName <コンピュータ名>
```

## 入出力項目

### Get-DbaSpn パラメータ

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|------|------|
| ComputerName | string[] | No | 検索対象コンピュータ名 |
| AccountName | string[] | No | 検索対象サービスアカウント名 |
| Credential | PSCredential | No | AD接続用資格情報 |
| EnableException | switch | No | 例外処理モードの有効化 |

### Set-DbaSpn パラメータ

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|------|------|
| SPN | string | Yes | 登録するSPN（例：MSSQLSvc/server:port） |
| ServiceAccount | string | Yes | SPNを登録するサービスアカウント |
| Credential | PSCredential | No | AD接続用資格情報 |
| NoDelegation | switch | No | 委任設定をスキップ |
| EnableException | switch | No | 例外処理モードの有効化 |

### Remove-DbaSpn パラメータ

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|------|------|
| SPN | string | Yes | 削除するSPN |
| ServiceAccount | string | Yes | SPNを持つサービスアカウント |
| Credential | PSCredential | No | AD接続用資格情報 |
| EnableException | switch | No | 例外処理モードの有効化 |

### Test-DbaSpn パラメータ

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|------|------|
| ComputerName | DbaInstanceParameter[] | Yes | 検証対象コンピュータ名 |
| Credential | PSCredential | No | AD接続用資格情報 |
| EnableException | switch | No | 例外処理モードの有効化 |

## 表示項目

### Get-DbaSpn 出力

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Input | string | 検索に使用した入力値 |
| AccountName | string | SPNを持つサービスアカウント名 |
| ServiceClass | string | サービスクラス（常に "MSSQLSvc"） |
| Port | int | ポート番号（存在する場合） |
| SPN | string | 完全なSPN文字列 |

### Set-DbaSpn 出力

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Name | string | 処理されたSPN |
| ServiceAccount | string | 対象サービスアカウント |
| Property | string | 変更されたADプロパティ名 |
| IsSet | boolean | 設定成功フラグ |
| Notes | string | 操作結果のメッセージ |

### Remove-DbaSpn 出力

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Name | string | 処理されたSPN |
| ServiceAccount | string | 対象サービスアカウント |
| Property | string | 変更されたADプロパティ名 |
| IsSet | boolean | SPN残存フラグ（削除成功ならfalse） |
| Notes | string | 操作結果のメッセージ |

### Test-DbaSpn 出力

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | string | コンピュータ名（クラスター仮想名を含む） |
| InstanceName | string | SQL Serverインスタンス名 |
| SqlProduct | string | SQL Server製品バージョン |
| InstanceServiceAccount | string | インスタンスのサービスアカウント |
| RequiredSPN | string | 必要なSPN |
| IsSet | boolean | SPNがADに登録されているか |
| Cluster | boolean | クラスター構成かどうか |
| TcpEnabled | boolean | TCP/IPが有効か |
| Port | string | 使用ポート |
| DynamicPort | boolean | 動的ポートを使用しているか |
| Warning | string | 警告メッセージ |
| Error | string | エラーメッセージ |

## イベント仕様

### 1-SPN取得

**Get-DbaSpn 実行時**

1. ComputerNameまたはAccountNameパラメータに基づき検索モードを決定
2. ComputerName指定時：Test-DbaSpnを内部で呼び出し、IsSet=trueのSPNを取得
3. AccountName指定時：Get-DbaADObjectでADアカウントを検索
4. servicePrincipalNameプロパティからSPN情報を抽出
5. PSCustomObjectとして結果を出力

### 2-SPN登録

**Set-DbaSpn 実行時**

1. Get-DbaADObjectでサービスアカウントをADから検索
2. アカウントタイプ（User/Computer）を判別
3. GetUnderlyingObject()でDirectoryEntryを取得
4. servicePrincipalNameプロパティにSPNを追加
5. CommitChanges()で変更を保存
6. NoDelegation未指定時、msDS-AllowedToDelegateTo プロパティにも追加
7. 結果をPSCustomObjectとして出力

### 3-SPN削除

**Remove-DbaSpn 実行時**

1. Get-DbaADObjectでサービスアカウントをADから検索
2. servicePrincipalNameプロパティからSPNを削除
3. CommitChanges()で変更を保存
4. msDS-AllowedToDelegateTo プロパティからも削除
5. 結果をPSCustomObjectとして出力

### 4-SPN検証

**Test-DbaSpn 実行時**

1. Resolve-DbaNetworkNameでFQDNを解決
2. Invoke-ManagedComputerCommandでWMI経由でSQL Serverインスタンス情報を取得
3. 各インスタンスのTCP/IP設定、ポート情報を取得
4. 必要なSPN（MSSQLSvc/FQDN:port）を生成
5. Get-DbaADObjectでサービスアカウントのSPNを検索
6. 必要なSPNがADに登録されているか検証
7. 結果をPSCustomObjectとして出力

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| SPN取得 | なし | N/A | データベース操作なし |
| SPN登録 | なし | N/A | Active Directory操作のみ |
| SPN削除 | なし | N/A | Active Directory操作のみ |
| SPN検証 | なし | N/A | WMI/AD読み取りのみ |

本機能はActive Directoryに対する操作であり、SQL Serverデータベースへの直接的な更新は行わない。

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 発生条件 |
|-------------|------|---------------|---------|
| MSG001 | 成功 | "Successfully added SPN" | SPN登録成功時 |
| MSG002 | 失敗 | "Failed to add SPN" | SPN登録失敗時 |
| MSG003 | 成功 | "Successfully added constrained delegation" | 委任設定成功時 |
| MSG004 | 失敗 | "Failed to add constrained delegation" | 委任設定失敗時 |
| MSG005 | 成功 | "Successfully removed SPN" | SPN削除成功時 |
| MSG006 | 警告 | "SPN not found" | 削除対象SPNが存在しない場合 |
| MSG007 | 成功 | "Successfully removed delegation" | 委任設定削除成功時 |
| MSG008 | 情報 | "Delegation not found" | 委任設定が存在しない場合 |
| MSG009 | エラー | "SPN missing" | Test-DbaSpnで必要なSPNが未登録 |
| MSG010 | 警告 | "Dynamic port is enabled" | 動的ポートが有効な場合 |

## 例外処理

| 例外条件 | 対応処理 |
|---------|---------|
| ADアカウントが見つからない | Stop-Function でエラーを記録、処理を停止 |
| AD接続失敗 | Stop-Function でエラーを記録、次のインスタンスへ継続 |
| SPN追加権限不足 | 例外をキャッチし、Notes に失敗理由を格納 |
| ネットワーク名解決失敗 | 警告メッセージを出力し、処理を継続 |
| WMI接続失敗 | Stop-Function でエラーを記録 |

## 備考

- SPNの形式は MSSQLSvc/hostname:port または MSSQLSvc/hostname.domain.com:port
- デフォルトインスタンスは MSSQLSvc/FQDN（ポートなし）の形式も使用
- 名前付きインスタンスは MSSQLSvc/FQDN:InstanceName の形式も使用
- LocalSystem や NT SERVICE\* アカウントはコンピュータアカウントとして処理
- gMSA（グループ管理サービスアカウント）は末尾が '$' で判別

---

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

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

### 推奨読解順序

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

各コマンドが返すPSCustomObjectの構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Get-DbaSpn.ps1 | `public/Get-DbaSpn.ps1` | 113-119行目: 出力オブジェクト構造 |
| 1-2 | Set-DbaSpn.ps1 | `public/Set-DbaSpn.ps1` | 156-162行目: SPN登録結果オブジェクト |
| 1-3 | Set-DbaSpn.ps1 | `public/Set-DbaSpn.ps1` | 182-188行目: 委任設定結果オブジェクト |
| 1-4 | Test-DbaSpn.ps1 | `public/Test-DbaSpn.ps1` | 118-134行目: 検証結果オブジェクト構造 |

**読解のコツ**: Test-DbaSpnの出力はSet-DbaSpnやRemove-DbaSpnのパイプライン入力として設計されている。RequiredSPNとInstanceServiceAccountがエイリアスでマッピング。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Test-DbaSpn.ps1 | `public/Test-DbaSpn.ps1` | 90-284行目: 全体の処理フロー |
| 2-2 | Get-DbaSpn.ps1 | `public/Get-DbaSpn.ps1` | 128-176行目: process ブロック |
| 2-3 | Set-DbaSpn.ps1 | `public/Set-DbaSpn.ps1` | 119-194行目: process ブロック |
| 2-4 | Remove-DbaSpn.ps1 | `public/Remove-DbaSpn.ps1` | 102-195行目: process ブロック |

**主要処理フロー（Test-DbaSpn）**:
1. **91-101行目**: Resolve-DbaNetworkNameでFQDNを取得
2. **107-227行目**: Invoke-ManagedComputerCommandでSQLインスタンス情報を取得
3. **236-281行目**: ADからSPNを検索し、IsSetフラグを設定

#### Step 3: AD操作ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Get-DbaSpn.ps1 | `public/Get-DbaSpn.ps1` | 74-122行目: Process-Account関数 |
| 3-2 | Set-DbaSpn.ps1 | `public/Set-DbaSpn.ps1` | 126-139行目: AD検索とDirectoryEntry取得 |
| 3-3 | Set-DbaSpn.ps1 | `public/Set-DbaSpn.ps1` | 142-163行目: SPN追加処理 |
| 3-4 | Set-DbaSpn.ps1 | `public/Set-DbaSpn.ps1` | 166-193行目: 委任設定追加処理 |

**主要処理フロー（Set-DbaSpn）**:
- **122-125行目**: アカウントタイプ判別（User/Computer）
- **127行目**: Get-DbaADObjectでAD検索
- **133行目**: GetUnderlyingObject()でDirectoryEntry取得
- **144行目**: servicePrincipalName.Add()でSPN追加
- **146行目**: CommitChanges()で保存
- **171行目**: msDS-AllowedToDelegateTo.Add()で委任設定

#### Step 4: WMI/SMO経由のインスタンス情報取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Test-DbaSpn.ps1 | `public/Test-DbaSpn.ps1` | 107-227行目: ScriptBlock定義 |
| 4-2 | Test-DbaSpn.ps1 | `public/Test-DbaSpn.ps1` | 117-152行目: インスタンス情報収集 |
| 4-3 | Test-DbaSpn.ps1 | `public/Test-DbaSpn.ps1` | 161-172行目: RequiredSPN生成 |
| 4-4 | Test-DbaSpn.ps1 | `public/Test-DbaSpn.ps1` | 176-225行目: TCP/IPポート情報取得 |

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

```
Test-DbaSpn
    │
    ├─ Resolve-DbaNetworkName (FQDN解決)
    │
    ├─ Invoke-ManagedComputerCommand (WMI経由でインスタンス情報取得)
    │      └─ WMI: ServerInstances, ServerProtocols
    │
    └─ Get-DbaADObject (AD検索)
           └─ servicePrincipalName プロパティ確認

Get-DbaSpn
    │
    ├─ Test-DbaSpn (ComputerName指定時)
    │
    └─ Get-DbaADObject (AccountName指定時)
           └─ Process-Account 関数

Set-DbaSpn
    │
    ├─ Get-DbaADObject (アカウント検索)
    │      └─ GetUnderlyingObject() → DirectoryEntry
    │
    └─ DirectoryEntry操作
           ├─ servicePrincipalName.Add()
           ├─ msDS-AllowedToDelegateTo.Add()
           └─ CommitChanges()

Remove-DbaSpn
    │
    ├─ Get-DbaADObject (アカウント検索)
    │      └─ GetUnderlyingObject() → DirectoryEntry
    │
    └─ DirectoryEntry操作
           ├─ servicePrincipalName.Remove()
           ├─ msDS-AllowedToDelegateTo.Remove()
           └─ CommitChanges()
```

### データフロー図

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

ComputerName ───────▶ Resolve-DbaNetworkName ───▶ FQDN
                              │
                              ▼
                    Invoke-ManagedComputerCommand
                              │
                              ▼
                    WMI: SQL Serverインスタンス情報
                              │
                              ▼                          PSCustomObject
                    RequiredSPN生成 ───────────────▶   │
                              │                         ├─ ComputerName
                              ▼                         ├─ InstanceName
                    Get-DbaADObject ───────────▶       ├─ RequiredSPN
                              │                         ├─ IsSet
                              ▼                         ├─ Cluster
                    servicePrincipalName               ├─ TcpEnabled
                    プロパティ確認                      └─ DynamicPort
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Get-DbaSpn.ps1 | `public/Get-DbaSpn.ps1` | ソース | SPN取得 |
| Set-DbaSpn.ps1 | `public/Set-DbaSpn.ps1` | ソース | SPN登録 |
| Remove-DbaSpn.ps1 | `public/Remove-DbaSpn.ps1` | ソース | SPN削除 |
| Test-DbaSpn.ps1 | `public/Test-DbaSpn.ps1` | ソース | SPN検証 |
| Get-DbaADObject.ps1 | `internal/functions/Get-DbaADObject.ps1` | ソース | AD検索ヘルパー |
| Resolve-DbaNetworkName.ps1 | `public/Resolve-DbaNetworkName.ps1` | ソース | ネットワーク名解決 |
| Invoke-ManagedComputerCommand.ps1 | `internal/functions/Invoke-ManagedComputerCommand.ps1` | ソース | WMI経由コマンド実行 |
