# 機能設計書 167-Invoke-DbaDbDataMasking

## 概要

本ドキュメントは、dbatools PowerShellモジュールの`Invoke-DbaDbDataMasking`コマンドレットに関する機能設計書である。このコマンドは、構成可能なマスキングルールを使用して、機密性の高い本番データをランダム化された値に置き換える機能を提供する。

### 本機能の処理概要

Invoke-DbaDbDataMaskingは、JSON構成ファイルに基づいてSQL Serverデータベース内の機密データをランダム化された値に置き換える。これにより、DBAは実際の顧客データを公開することなく、開発、テスト、トレーニング環境用の安全な非本番データセットを作成できる。

**業務上の目的・背景**：
GDPR、CCPA、PCI-DSSなどの規制要件により、本番データを開発・テスト環境で直接使用することは禁止されている場合が多い。このコマンドは、本番データの構造と参照整合性を維持しながら、個人情報や機密情報を安全にマスキングし、コンプライアンス準拠の環境を構築することを支援する。

**機能の利用シーン**：
- 開発環境への本番データコピー前のマスキング
- テストデータベースの匿名化
- トレーニング環境用データの準備
- 外部ベンダーへのデータ提供時の匿名化
- コンプライアンス監査対応

**主要な処理内容**：
1. JSON構成ファイルの読み込みと検証
2. 決定論的値テーブルの作成（tempdb）
3. 各テーブルの処理
   - IDENTITYカラムの追加/マスキングインデックスの作成
   - ユニークインデックスに対応した値の生成
   - バッチ処理によるUPDATE文の実行
4. アクション/コンポジット処理
5. クリーンアップと辞書エクスポート

**関連システム・外部連携**：
- Bogusライブラリ（偽データ生成）
- SQL Server Database Engine
- Test-DbaDbDataMaskingConfig（構成検証）
- Get-DbaRandomizedValue（ランダム値生成）
- Convert-DbaMaskingValue（値変換）
- Convert-DbaIndexToTable（インデックス変換）

**権限による制御**：
- 対象テーブルへのUPDATE権限が必要
- tempdbへのテーブル作成権限が必要
- ALTER TABLE権限が必要（IDENTITYカラム追加時）

## 関連画面

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

## 機能種別

データ変換 / データマスキング / セキュリティ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| SqlInstance | DbaInstanceParameter[] | No | ターゲットのSQL Serverインスタンス | - |
| SqlCredential | PSCredential | No | 代替資格情報 | - |
| Database | string[] | No | マスキング対象データベース（ワイルドカード対応） | - |
| Table | string[] | No | マスキング対象テーブル（ワイルドカード対応） | - |
| Column | string[] | No | マスキング対象カラム（ワイルドカード対応） | - |
| FilePath | object | Yes | JSON構成ファイルのパス | パイプライン入力対応 |
| Locale | string | No | ロケール（デフォルト: 'en'） | - |
| CharacterString | string | No | ランダム文字列生成に使用する文字セット | デフォルト: 英数字 |
| ExcludeTable | string[] | No | 除外するテーブル（ワイルドカード対応） | - |
| ExcludeColumn | string[] | No | 除外するカラム（ワイルドカード対応） | - |
| MaxValue | int | No | 生成文字列の最大長オーバーライド | - |
| ModulusFactor | int | No | NULL値の頻度制御（デフォルト: 10） | - |
| ExactLength | switch | No | 元データの長さに一致させる | - |
| CommandTimeout | int | No | SQLコマンドタイムアウト秒数（デフォルト: 300） | - |
| BatchSize | int | No | バッチあたりの行数（デフォルト: 1000） | - |
| Retry | int | No | ユニーク値生成の最大リトライ回数（デフォルト: 1000） | - |
| DictionaryFilePath | string[] | No | 決定論的値マッピングCSVファイルパス | - |
| DictionaryExportPath | string | No | 決定論的値マッピングのエクスポート先 | - |
| EnableException | switch | No | 例外を有効化 | - |

### 入力データソース

- JSON構成ファイル（New-DbaDbMaskingConfigで生成）
- 決定論的値マッピングCSVファイル（オプション）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | string | SQL Serverインスタンスのコンピュータ名 |
| InstanceName | string | SQL Serverインスタンス名 |
| SqlInstance | string | 完全なSQL Serverインスタンス名（computer\instance） |
| Database | string | マスキングが実行されたデータベース名 |
| Schema | string | マスキングされたテーブルのスキーマ名 |
| Table | string | マスキングされたテーブル名 |
| Columns | string[] | マスキングされたカラム名の配列 |
| Rows | int | テーブル内でマスキングされた行数 |
| Elapsed | TimeSpan | マスキング操作にかかった時間 |
| Status | string | テーブルのマスキングが"Successful"か"Failed"か |

### 出力先

コンソール（PSCustomObject）

## 処理フロー

### 処理シーケンス

```
1. beginブロック
   ├─ サポートデータ型/Fakerタイプの定義
   └─ デフォルト値の設定（ModulusFactor, CommandTimeout, BatchSize, Retry）
2. processブロック
   ├─ 構成ファイルの読み込みと検証
   └─ インスタンスループ
       ├─ Connect-DbaInstance
       ├─ 決定論的値テーブルの作成（tempdb）
       ├─ 辞書ファイルのインポート（オプション）
       └─ データベースループ
           └─ テーブルループ
               ├─ IDENTITYカラムの追加（なければ）
               ├─ マスキングインデックスの作成
               ├─ ユニークインデックス用テンポラリテーブル作成
               ├─ 行ごとのマスキング（バッチ処理）
               │   ├─ StaticValue処理
               │   ├─ KeepNull処理
               │   ├─ ユニーク値テーブルからの取得
               │   ├─ 決定論的値の処理
               │   └─ ランダム値生成
               ├─ Action処理（DateTime, Number, Column）
               ├─ Composite処理
               ├─ クリーンアップ（インデックス、IDENTITYカラム削除）
               └─ 結果オブジェクト生成
       └─ 辞書エクスポート（オプション）
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[構成ファイル読み込み]
    B --> C{検証OK?}
    C -->|No| D[Stop-Function]
    C -->|Yes| E[インスタンスループ]

    E --> F[決定論的値テーブル作成]
    F --> G{辞書ファイルあり?}
    G -->|Yes| H[Import-DbaCsv]
    G -->|No| I[データベースループ]
    H --> I

    I --> J[テーブルループ]
    J --> K{ExcludeTable?}
    K -->|Yes| J
    K -->|No| L{テーブル存在?}

    L -->|No| M[Stop-Function Continue]
    L -->|Yes| N{IDENTITYカラムあり?}

    M --> J
    N -->|No| O[IDENTITYカラム追加]
    N -->|Yes| P[マスキングインデックス作成]
    O --> P

    P --> Q{HasUniqueIndex?}
    Q -->|Yes| R[ユニーク値テーブル作成]
    Q -->|No| S[行データ取得]
    R --> S

    S --> T[バッチ処理ループ]
    T --> U[カラムループ]
    U --> V{StaticValue?}

    V -->|Yes| W[静的値設定]
    V -->|No| X{KeepNull & Nullable?}

    X -->|Yes| Y[NULL維持]
    X -->|No| Z{ユニークインデックス?}

    Z -->|Yes| AA[ユニーク値テーブルから取得]
    Z -->|No| AB{Deterministic?}

    AB -->|Yes| AC[決定論的値処理]
    AB -->|No| AD[Get-DbaRandomizedValue]

    W --> AE[UPDATE文に追加]
    Y --> AE
    AA --> AE
    AC --> AE
    AD --> AE

    AE --> AF{バッチサイズ到達?}
    AF -->|Yes| AG[Invoke-DbaQuery実行]
    AF -->|No| T

    AG --> AH{Action/Compositeあり?}
    AH -->|Yes| AI[Action/Composite処理]
    AH -->|No| AJ[クリーンアップ]
    AI --> AJ

    AJ --> AK[結果オブジェクト出力]
    AK --> AL{次のテーブル?}
    AL -->|Yes| J
    AL -->|No| AM{辞書エクスポート?}

    AM -->|Yes| AN[CSVエクスポート]
    AM -->|No| AO{次のインスタンス?}
    AN --> AO
    AO -->|Yes| E
    AO -->|No| AP[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | デフォルト値 | ModulusFactor=10, CommandTimeout=300, BatchSize=1000, Retry=1000 | 未指定時 |
| BR-002 | 決定論的マスキング | 同じ元値は常に同じマスク値にマッピング | Deterministic=true |
| BR-003 | KeepNull | 元値がNULLの場合はNULLを維持 | KeepNull=true & Nullable |
| BR-004 | StaticValue | 構成で指定された静的値を使用 | StaticValue指定時 |
| BR-005 | バッチ処理 | 指定されたバッチサイズでUPDATE実行 | 常時 |
| BR-006 | リトライ制限 | ユニーク値生成の最大リトライ回数を超えると停止 | HasUniqueIndex |
| BR-007 | 未サポートカラム | Identity, ForeignKey, Computed, Hierarchyid, Geography, Geometry, Xml | 常時除外 |

### 計算ロジック

**バッチ数の計算**:
```
totalBatches = Math.Ceiling(data.Count / BatchSize)
```

**NULL頻度の計算**:
```
(nullmod++) % ModulusFactor == 0 かつ !KeepNull かつ Nullable の場合にNULL
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 決定論的値テーブル作成 | tempdb.dbo.DeterministicValues | CREATE | 決定論的マッピング用 |
| マスキングIDカラム追加 | 対象テーブル | ALTER | IDENTITYカラムがない場合 |
| マスキングインデックス作成 | 対象テーブル | CREATE INDEX | パフォーマンス最適化 |
| データ取得 | 対象テーブル | SELECT | マスキング対象データ取得 |
| データ更新 | 対象テーブル | UPDATE | マスキング値への更新 |
| クリーンアップ | 対象テーブル、tempdb | DROP | インデックス、カラム、テーブル削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ConfigError | 構成ファイル検証失敗 | Stop-Function |
| - | ConnectionError | SQL Server接続失敗 | Stop-Function -Continue |
| - | TableNotFound | テーブルが存在しない | Stop-Function -Continue |
| - | UniqueRetryExceeded | リトライ回数超過 | Stop-Function |
| - | UpdateError | UPDATE実行失敗 | maskingErrorFlag=true、Status="Failed" |

### リトライ仕様

- ユニーク値生成: 最大Retry回（デフォルト1000回）まで再試行
- UPDATE失敗: リトライなし（次のバッチに継続）

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

- バッチごとにInvoke-DbaQueryで実行（暗黙的トランザクション）
- 明示的なトランザクション管理なし

## パフォーマンス要件

- BatchSizeでメモリ使用量とパフォーマンスのバランスを調整
- CommandTimeoutで長時間クエリの制御
- マスキングインデックスによるUPDATEパフォーマンス最適化

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

- DictionaryExportPathに出力されるファイルは元値とマスク値のマッピングを含むため、厳重に管理すること
- 決定論的マスキングは復元リスクがあるため、用途を限定すること

## 備考

- New-DbaDbMaskingConfigで構成ファイルを生成可能
- Action機能（DateTime加減算、Number演算）は単純なマスキングより高度な変換に使用
- Composite機能は複数値の組み合わせによるマスキングに使用

---

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

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

### 推奨読解順序

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

サポートデータ型とFakerタイプの構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | サポートデータ型 | 187-199行目 | supportedDataTypes配列 |
| 1-2 | Fakerタイプ | 201-205行目 | supportedFakerMaskingTypes, supportedFakerSubTypes |

**読解のコツ**: Get-DbaRandomizedTypeからサポートタイプを取得している点に注目。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Invoke-DbaDbDataMasking.ps1 | `public/Invoke-DbaDbDataMasking.ps1` | 関数全体の構造とパラメータ定義 |

**主要処理フロー**:
1. **160-183行目**: パラメータ定義
2. **184-227行目**: beginブロック（デフォルト設定）
3. **229-1353行目**: processブロック（メイン処理）

#### Step 3: インフラストラクチャ準備

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | 決定論的値テーブル | 281-301行目 | DeterministicValuesテーブル作成 |
| 3-2 | 辞書インポート | 303-317行目 | Import-DbaCsvによるマッピング読み込み |

#### Step 4: テーブル処理ループ

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | IDENTITYカラム処理 | 353-373行目 | MaskingIDカラム追加 |
| 4-2 | マスキングインデックス | 376-403行目 | NIX__Schema_Table_Maskingインデックス |
| 4-3 | ユニーク値処理 | 435-756行目 | HasUniqueIndex対応 |

#### Step 5: マスキング実行

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | バッチ処理 | 800-1075行目 | 行ごとのUPDATE文構築 |
| 5-2 | Action処理 | 1077-1157行目 | DateTime/Number/Column操作 |
| 5-3 | Composite処理 | 1159-1233行目 | 複合値生成 |

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

```
Invoke-DbaDbDataMasking
    │
    ├─ Test-DbaDbDataMaskingConfig
    │      └─ 構成ファイル検証
    │
    ├─ Connect-DbaInstance
    │
    ├─ Import-DbaCsv (辞書インポート時)
    │
    ├─ Convert-DbaIndexToTable
    │      └─ ユニークインデックス情報取得
    │
    ├─ Get-DbaRandomizedValue
    │      └─ 各カラムの値生成
    │
    ├─ Convert-DbaMaskingValue
    │      └─ 値のSQL形式変換
    │
    └─ Invoke-DbaQuery
           └─ UPDATE実行
```

### データフロー図

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

FilePath(JSON) ─────────────▶ 構成読み込み・検証
DictionaryFilePath ─────────▶ 辞書インポート（オプション）
                                        │
SqlInstance ─────────────────▶ Connect-DbaInstance
Database ────────────────────▶
                                        │
                               ┌────────▼────────┐
                               │ 決定論的値テーブル │
                               │ (tempdb)        │
                               └────────┬────────┘
                                        │
Table ───────────────────────▶ テーブルループ
ExcludeTable ────────────────▶
                                        │
                               ┌────────▼────────┐
                               │ IDENTITY追加    │
                               │ マスキングIndex │
                               └────────┬────────┘
                                        │
Column ──────────────────────▶ カラムフィルタリング
ExcludeColumn ───────────────▶
                                        │
                               ┌────────▼────────┐
Locale ──────────────────────▶│ Get-DbaRandomized│
CharacterString ─────────────▶│ Value            │
MaxValue ────────────────────▶│                  │
                               └────────┬────────┘
                                        │
BatchSize ───────────────────▶ バッチUPDATE実行
CommandTimeout ──────────────▶
                                        │
                                        ▼
DictionaryExportPath ────────▶ 辞書CSVエクスポート
                                        │
                                        ▼
                               ┌────────────────────┐
                               │ PSCustomObject生成  │──────▶ コンソール出力
                               │ - Database         │
                               │ - Schema           │
                               │ - Table            │
                               │ - Rows             │
                               │ - Status           │
                               └────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Invoke-DbaDbDataMasking.ps1 | `public/Invoke-DbaDbDataMasking.ps1` | ソース | メイン関数定義 |
| New-DbaDbMaskingConfig.ps1 | `public/New-DbaDbMaskingConfig.ps1` | ソース | 構成ファイル生成 |
| Test-DbaDbDataMaskingConfig.ps1 | `public/Test-DbaDbDataMaskingConfig.ps1` | ソース | 構成ファイル検証 |
| Get-DbaRandomizedValue.ps1 | `public/Get-DbaRandomizedValue.ps1` | ソース | ランダム値生成 |
| Convert-DbaMaskingValue.ps1 | 内部関数 | ソース | 値変換 |
| Convert-DbaIndexToTable.ps1 | 内部関数 | ソース | インデックス情報取得 |
