# 機能設計書 573-Remove-DbaDbOrphanUser

## 概要

本ドキュメントは、SQL Serverの孤立データベースユーザーを削除する `Remove-DbaDbOrphanUser` 機能の設計仕様を定義するものです。

### 本機能の処理概要

`Remove-DbaDbOrphanUser` は、対応するSQL Serverログインが存在しなくなった孤立データベースユーザー（Orphan User）を削除するdbatools PowerShellコマンドレットです。スキーマ所有権の移譲や空スキーマの削除を自動的に処理し、依存関係の問題を解決しながらユーザーを安全に削除します。

**業務上の目的・背景**：データベースの移行、復元、またはログインの削除後に、対応するログインのないデータベースユーザーが残る「孤立ユーザー」が発生します。これらは、セキュリティ監査の問題となり、データベースの整合性にも影響を与える可能性があります。本機能は、こうした孤立ユーザーを効率的に検出・削除し、データベースセキュリティを維持します。

**機能の利用シーン**：
- データベース復元後のユーザークリーンアップ
- サーバー間でのデータベース移行後の整理
- ログイン削除後の関連ユーザーの削除
- 定期的なセキュリティメンテナンス
- セキュリティ監査対応

**主要な処理内容**：
1. 対象SQL Serverインスタンスへの接続
2. 対象データベースの取得（コンテナ型データベースを除外）
3. Get-DbaDbOrphanUserによる孤立ユーザーの検出
4. スキーマ所有権の確認と処理（空スキーマの削除、所有権の移譲）
5. 同名ログインの存在確認（Force未指定時は削除をブロック）
6. T-SQLまたはsp_droploginによるユーザー削除

**関連システム・外部連携**：SQL Server SMOライブラリ、Get-DbaDbOrphanUser、Repair-DbaDbOrphanUserとの連携。

**権限による制御**：ALTER ANY USER権限または同等の権限が必要。スキーマ所有権の変更にはALTER SCHEMA権限も必要です。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | SSMSユーザー管理画面 | 参照画面 | GUIでのユーザー削除に相当する操作 |

## 機能種別

CRUD操作（Delete） / データ整合性維持

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| SqlInstance | DbaInstanceParameter[] | Yes | 対象のSQL Serverインスタンス | 有効なインスタンス名 |
| SqlCredential | PSCredential | No | 代替認証情報 | 有効なPSCredentialオブジェクト |
| Database | Object[] | No | 対象データベース | 存在するデータベース名 |
| ExcludeDatabase | Object[] | No | 除外データベース | 存在するデータベース名 |
| User | Object[] | No | 削除対象ユーザー名 | - |
| Force | Switch | No | 強制削除フラグ | - |
| EnableException | Switch | No | 例外を有効化するスイッチ | - |

### 入力データソース

- PowerShellコマンドライン入力
- パイプライン入力（SqlInstance、User）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | String | SQL Serverが動作するコンピュータ名 |
| InstanceName | String | SQL Serverインスタンス名 |
| SqlInstance | String | 完全なインスタンス名 |
| DatabaseName | String | データベース名 |
| SchemaName | String | 操作対象スキーマ名 |
| Action | String | 実行したアクション（"DROP" または "ALTER OWNER"） |
| SchemaOwnerBefore | String | 操作前のスキーマオーナー |
| SchemaOwnerAfter | String | 操作後のスキーマオーナー（"dbo" または "N/A"） |

### 出力先

- PowerShellパイプライン（PSCustomObject）
- 注意：ユーザー削除自体は出力オブジェクトを生成せず、スキーマ操作のみが出力される

## 処理フロー

### 処理シーケンス

```
1. begin ブロック
   └─ Force指定時はConfirmPreferenceを'none'に設定
2. インスタンスループ開始
   └─ 各SqlInstanceに対して処理を実行
3. インスタンス接続
   └─ Connect-DbaInstanceを使用して接続
4. データベースコレクション取得
   ├─ アクセス可能・読み取り専用でないDBを取得
   ├─ Databaseフィルタ適用
   └─ ExcludeDatabaseフィルタ適用
5. データベースループ
   ├─ コンテナ型データベースをスキップ（SQL 2012以降）
   ├─ Get-DbaDbOrphanUserで孤立ユーザー取得
   └─ Userフィルタ適用
6. ユーザーループ
   ├─ 同名ログイン存在確認
   ├─ スキーマ所有権確認（SQL 2005以降）
   ├─ スキーマ処理（削除 or オーナー変更）
   └─ ユーザー削除実行
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[Connect-DbaInstance]
    B --> C{接続成功?}
    C -->|No| D[エラー出力・次へ]
    C -->|Yes| E[データベースコレクション取得]
    E --> F[DBループ開始]
    F --> G{コンテナ型DB?}
    G -->|Yes| H[スキップ]
    G -->|No| I[孤立ユーザー取得]
    I --> J{ユーザーあり?}
    J -->|No| K[次のDB]
    J -->|Yes| L[ユーザーループ開始]
    L --> M{同名ログイン存在?}
    M -->|Yes| N{Force指定?}
    N -->|No| O[警告・スキップ]
    N -->|Yes| P[スキーマ確認]
    M -->|No| P
    P --> Q{スキーマ所有?}
    Q -->|No| R[ユーザー削除]
    Q -->|Yes| S{オブジェクトあり?}
    S -->|Yes| T{Force指定?}
    T -->|No| U[警告・スキップ]
    T -->|Yes| V[オーナーをdboに変更]
    S -->|No| W{スキーマ名=ユーザー名?}
    W -->|Yes| X[スキーマ削除]
    W -->|No| Y[オーナーをdboに変更]
    V --> R
    X --> R
    Y --> R
    R --> Z{次のユーザー?}
    O --> Z
    U --> Z
    Z -->|Yes| L
    Z -->|No| K
    K --> AA{次のDB?}
    H --> AA
    AA -->|Yes| F
    AA -->|No| AB[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | コンテナ型DBスキップ | コンテナ型データベースは孤立ユーザーが存在しないためスキップ | SQL Server 2012以降 |
| BR-002 | 同名ログイン保護 | 同名ログインが存在する場合、Repair-DbaDbOrphanUserでの修復を推奨 | Force未指定時 |
| BR-003 | 空スキーマ削除 | ユーザーと同名の空スキーマは削除 | スキーマにオブジェクトがない場合 |
| BR-004 | スキーマオーナー移譲 | ユーザーが所有するスキーマのオーナーをdboに変更 | スキーマ名がユーザー名と異なる場合 |
| BR-005 | オブジェクト所有スキーマ | オブジェクトを含むスキーマの場合、Forceが必要 | スキーマにオブジェクトがある場合 |

### 計算ロジック

SQL Server 2008以下の場合、EnumObjects()に0x1FFFFFFFを渡してオブジェクトを列挙します。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| スキーマオーナー変更 | sys.schemas | UPDATE | スキーマのprincipal_idを更新 |
| スキーマ削除 | sys.schemas | DELETE | スキーマの削除 |
| ユーザー削除 | sys.database_principals | DELETE | ユーザーの削除 |

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

#### sys.database_principals

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | principal_id | 対象ユーザーのID | DROP USER文で実行 |

#### sys.schemas

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | principal_id | dboのprincipal_id | ALTER AUTHORIZATION文 |
| DELETE | schema_id | 対象スキーマのID | DROP SCHEMA文 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ConnectionError | 接続エラー | インスタンスへの接続失敗 | 接続情報・ネットワーク確認 |
| SchemaOwnsObjects | スキーマ依存エラー | スキーマにオブジェクトが存在 | -Forceを使用 |
| MatchingLoginExists | ログイン存在 | 同名ログインが存在 | -Forceを使用またはRepair-DbaDbOrphanUserを使用 |

### リトライ仕様

エラー発生時はStop-Functionで処理を中断し、次のオブジェクトへ継続します。

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

ExecuteNonQuery()メソッドで実行され、各SQL文は個別のトランザクションとして処理されます。

## パフォーマンス要件

孤立ユーザーの検出は各データベースのユーザー数に依存します。大規模データベースでは、EnumObjects()の呼び出しに時間がかかる場合があります。

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

- ALTER ANY USER権限が必要
- スキーマオーナー変更にはALTER SCHEMA権限が必要
- 監査ログによる操作追跡を推奨
- 削除前にRepair-DbaDbOrphanUserでの修復可能性を検討

## 備考

- SQL Server 2005以降でスキーマ処理が有効
- SQL Server 2000ではsp_droploginを使用
- Repair-DbaDbOrphanUserから呼び出された場合、ログイン存在チェックをスキップ

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | User (SMO) | Microsoft.SqlServer.Management.Smo | SMOのUserクラスの構造 |
| 1-2 | Schema (SMO) | Microsoft.SqlServer.Management.Smo | SMOのSchemaクラスとEnumOwnedObjects() |

**読解のコツ**: 孤立ユーザーはLoginプロパティが無効または存在しないUserオブジェクトです。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Remove-DbaDbOrphanUser.ps1 | `public/Remove-DbaDbOrphanUser.ps1` | 関数定義とパラメータバインディング |

**主要処理フロー**:
1. **120-132行目**: パラメータ定義
2. **133-137行目**: begin ブロック - Force時のConfirmPreference設定
3. **138-343行目**: process ブロック - メイン処理

#### Step 3: 孤立ユーザー検出を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Remove-DbaDbOrphanUser.ps1 | `public/Remove-DbaDbOrphanUser.ps1` | Get-DbaDbOrphanUserとの連携 |

**主要処理フロー**:
- **174-185行目**: 呼び出し元の判定とユーザー取得処理
- **181行目**: Get-DbaDbOrphanUserで孤立ユーザーを検出

#### Step 4: スキーマ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Remove-DbaDbOrphanUser.ps1 | `public/Remove-DbaDbOrphanUser.ps1` | スキーマ所有権の確認と処理 |

**主要処理フロー**:
- **205-295行目**: スキーマ処理のメインロジック
- **213行目**: ユーザーが所有するスキーマを取得
- **225-229行目**: バージョン別のEnumObjects()呼び出し
- **231-253行目**: オブジェクトがあるスキーマの処理（Force確認）
- **254-289行目**: 空スキーマの処理（削除またはオーナー変更）

#### Step 5: ユーザー削除を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Remove-DbaDbOrphanUser.ps1 | `public/Remove-DbaDbOrphanUser.ps1` | ユーザー削除の実行 |

**主要処理フロー**:
- **297-308行目**: T-SQL/sp_droploginの構築
- **310-329行目**: 同名ログイン存在時の処理（Force確認）
- **322-328行目**: ExecuteNonQueryによる削除実行

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

```
Remove-DbaDbOrphanUser
    │
    ├─ Connect-DbaInstance
    │
    ├─ Get-DbaDbOrphanUser
    │      └─ 孤立ユーザー検出
    │
    ├─ Schema.EnumOwnedObjects()
    │      └─ スキーマ内オブジェクト確認
    │
    ├─ Database.EnumObjects()
    │      └─ スキーマ内オブジェクトカウント
    │
    └─ Database.ExecuteNonQuery()
           └─ ALTER AUTHORIZATION / DROP SCHEMA / DROP USER
```

### データフロー図

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

SqlInstance ─────────▶ Connect-DbaInstance
                              │
                              ▼
Database ────────────▶ データベースコレクション取得
                              │
                              ▼
                      Get-DbaDbOrphanUser ──────▶ 孤立ユーザー一覧
                              │
User ────────────────▶ ユーザーフィルタ
                              │
                              ▼
                      スキーマ所有権確認
                              │
                              ├─▶ ALTER AUTHORIZATION ──▶ PSCustomObject
                              │                           (Action="ALTER OWNER")
                              │
                              ├─▶ DROP SCHEMA ──────────▶ PSCustomObject
                              │                           (Action="DROP")
                              │
                              └─▶ DROP USER ────────────▶ (出力なし)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Remove-DbaDbOrphanUser.ps1 | `public/Remove-DbaDbOrphanUser.ps1` | ソース | メイン関数定義 |
| Get-DbaDbOrphanUser.ps1 | `public/Get-DbaDbOrphanUser.ps1` | ソース | 孤立ユーザー検出 |
| Repair-DbaDbOrphanUser.ps1 | `public/Repair-DbaDbOrphanUser.ps1` | ソース | 孤立ユーザー修復（呼び出し元確認用） |
| Connect-DbaInstance.ps1 | `public/Connect-DbaInstance.ps1` | ソース | インスタンス接続 |
| Stop-Function.ps1 | `private/functions/Stop-Function.ps1` | ソース | エラー処理 |
| Write-Message.ps1 | `private/functions/Write-Message.ps1` | ソース | メッセージ出力 |
