# 機能設計書 280-New-DbaDbSnapshot

## 概要

本ドキュメントは、ポイントインタイムリカバリとテストシナリオ用にデータベーススナップショットを作成するdbatools PowerShellコマンド`New-DbaDbSnapshot`の機能設計書です。

### 本機能の処理概要

`New-DbaDbSnapshot`は、特定の瞬間のデータベース状態をキャプチャする読み取り専用のデータベーススナップショットを作成します。スナップショットは、バックアップファイルから復元することなくデータベースを以前の状態に戻す高速な方法を提供し、メンテナンス前のスナップショット、テストシナリオ、または迅速なロールバックポイントに最適です。

**業務上の目的・背景**：データベーススナップショットは、変更操作前の安全ポイントの確保、テストデータのリセット、レポート用の一貫したデータビューの提供に使用されます。本コマンドにより、スナップショットファイル構造の手動作成を排除し、タイムスタンプ付きのスナップショット名を自動生成して、効率的なスナップショット管理を実現します。

**機能の利用シーン**：
- メンテナンス作業前のデータ保護
- テスト環境でのデータリセットポイント作成
- レポート用の一貫したデータビュー
- 本番データベースの迅速なロールバックポイント

**主要な処理内容**：
1. データベースオブジェクトの取得と検証
2. スナップショット名の生成（デフォルトまたはカスタム）
3. スナップショットファイル構造の作成
4. SMO Database オブジェクトの作成とファイルグループ設定
5. スナップショットの作成（Create）
6. Get-DbaDbSnapshotで結果出力

**関連システム・外部連携**：SMO (SQL Server Management Objects) を使用し、SQL ServerのCREATE DATABASE AS SNAPSHOT文を内部で実行します。

**権限による制御**：CREATE DATABASE権限が必要です。FILESTREAMファイルグループを含むデータベースには-Forceが必要です。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | PowerShellコンソール | 主画面 | コマンド実行・結果表示 |

## 機能種別

作成操作（CREATE DATABASE）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| SqlInstance | DbaInstanceParameter[] | No | 対象SQL Serverインスタンス | - |
| SqlCredential | PSCredential | No | 代替認証情報 | Windows/SQL認証対応 |
| Database | object[] | No | 対象データベース名 | - |
| ExcludeDatabase | object[] | No | 除外データベース名 | - |
| AllDatabases | switch | No | 全ユーザーデータベース対象 | - |
| Name | string | No | カスタムスナップショット名 | 単一DB時のみ |
| NameSuffix | string | No | スナップショット名サフィックス | テンプレート対応 |
| Path | string | No | スナップショットファイルパス | - |
| InputObject | Microsoft.SqlServer.Management.Smo.Database[] | No | パイプライン入力データベース | ValueFromPipeline |
| Force | switch | No | FILESTREAMを含む部分スナップショット許可 | - |
| EnableException | switch | No | 例外処理の有効化 | - |
| WhatIf | switch | No | 実行シミュレーション | SupportsShouldProcess |
| Confirm | switch | No | 確認プロンプト | ConfirmImpact='Medium' |

### 入力データソース

- SQL Serverインスタンスへの接続情報
- Get-DbaDatabaseからのデータベースオブジェクト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | string | SQL Serverのコンピュータ名 |
| InstanceName | string | インスタンス名 |
| SqlInstance | string | 完全修飾インスタンス名 |
| Name | string | スナップショット名 |
| SnapshotOf | string | ソースデータベース名 |
| CreateDate | DateTime | 作成日時 |
| DiskUsage | dbasize | ディスク使用量 |

### 出力先

パイプライン出力（Microsoft.SqlServer.Management.Smo.Database オブジェクト、Get-DbaDbSnapshot経由）

## 処理フロー

### 処理シーケンス

```
1. beginブロック
   └─ デフォルトサフィックス生成（yyyyMMdd_HHmmss）
   └─ NameSuffixテンプレート検証
   └─ Resolve-SnapshotError関数定義
2. パラメータ検証
   └─ Database/AllDatabasesの必須確認
3. SqlInstanceからデータベース取得
   └─ Get-DbaDatabase使用
4. Pathの存在確認（指定時）
   └─ Test-DbaPath使用
5. 各データベースの検証とInputObject追加
   └─ ミラーリング、スナップショット、システムDB除外
6. 複数DB + Name指定時のエラー
   └─ NameSuffix使用を促す
7. スナップショット名生成
   └─ NameSuffix/Name/デフォルトから決定
8. 既存スナップショット名重複確認
   └─ 警告出力でスキップ
9. FILESTREAMとメモリ最適化確認
   └─ MEMORY_OPTIMIZED_DATA → 不可
   └─ FILESTREAM + !Force → スキップ
10. ファイル構造作成
    └─ CustomFileStructureハッシュテーブル
11. SMO Database/FileGroup/DataFile作成
    └─ DatabaseSnapshotBaseName設定
12. スナップショット作成
    └─ SnapDB.Create() または $server.Query($sql)
13. Get-DbaDbSnapshotで結果出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[デフォルトサフィックス生成]
    B --> C{Database/AllDatabases<br/>指定あり?}
    C -->|No| D[エラー終了]
    C -->|Yes| E[SqlInstanceループ]
    E --> F[Connect-DbaInstance]
    F --> G{Path指定?}
    G -->|Yes| H{Test-DbaPath<br/>OK?}
    G -->|No| I[データベース検証]
    H -->|No| J[スキップ]
    H -->|Yes| I
    I --> K{ミラーリング/<br/>スナップショット/<br/>システムDB?}
    K -->|除外対象| L[警告出力]
    K -->|対象| M[InputObject追加]
    L --> N[次のDB]
    M --> O{複数DB<br/>かつ<br/>Name指定?}
    O -->|Yes| P[エラー：NameSuffix使用を]
    O -->|No| Q[スナップショットループ]
    Q --> R[スナップショット名生成]
    R --> S{名前重複?}
    S -->|Yes| T[警告出力]
    S -->|No| U{MEMORY_OPTIMIZED?}
    T --> V[次のスナップショット]
    U -->|Yes| W[警告：スナップショット不可]
    U -->|No| X{FILESTREAM?}
    W --> V
    X -->|Yes + !Force| Y[警告：-Force必要]
    X -->|No or Force| Z[ファイル構造作成]
    Y --> V
    Z --> AA[SMO Database作成]
    AA --> AB[SnapDB.Create]
    AB --> AC{成功?}
    AC -->|Yes| AD[Get-DbaDbSnapshot出力]
    AC -->|No| AE[T-SQL実行リトライ]
    AE --> AF{成功?}
    AF -->|Yes| AD
    AF -->|No| AG[エラー出力]
    AD --> V
    AG --> V
    V --> AH{次あり?}
    AH -->|Yes| Q
    AH -->|No| AI{次のインスタンス<br/>あり?}
    AI -->|Yes| E
    AI -->|No| AJ[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-280-01 | 最小バージョン | SQL Server 2005（バージョン9）以上が必要 | 常時 |
| BR-280-02 | 対象制限 | システムDB（master, model, tempdb）は対象外 | 常時 |
| BR-280-03 | スナップショット除外 | 既存スナップショットからのスナップショット不可 | 常時 |
| BR-280-04 | メモリ最適化不可 | MEMORY_OPTIMIZED_DATAを含むDBはスナップショット不可 | 常時 |
| BR-280-05 | FILESTREAM制限 | FILESTREAMを含むDBは-Force必須で部分スナップショット | FILESTREAM存在時 |
| BR-280-06 | 名前重複防止 | 既存スナップショット名と同名は作成不可 | 常時 |
| BR-280-07 | Name単一DB | Nameパラメータは単一DB時のみ使用可能 | 複数DB対象時 |
| BR-280-08 | デフォルトサフィックス | yyyyMMdd_HHmmss形式 | NameSuffix未指定時 |

### 計算ロジック

スナップショット名の決定:
```powershell
if ($NameSuffix.Length -gt 0) {
    $SnapName = $NameSuffix -f $db.Name
    if ($SnapName -eq $NameSuffix) {
        # 補間なし、単純追加
        $SnapName = '{0}{1}' -f $db.Name, $NameSuffix
    }
} elseif ($Name.Length -gt 0) {
    $SnapName = $Name
} else {
    $SnapName = "{0}_{1}" -f $db.Name, $DefaultSuffix
}
```

スナップショットファイル名の生成:
```powershell
$fName = [IO.Path]::Combine($basePath,
    ("{0}_{1}_{2:0000}_{3:000}{4}" -f
        $basename, $DefaultSuffix,
        (Get-Date).MilliSecond, $counter, $originalExtension))
$fName = [IO.Path]::ChangeExtension($fName, "ss")
```

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

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

| 操作 | 対象 | 操作種別 | 概要 |
|-----|-------------|---------|------|
| スナップショット作成 | Database | CREATE DATABASE | AS SNAPSHOT OF |

### SQL文（内部で生成）

#### スナップショット作成（SMO生成）
```sql
CREATE DATABASE [HR_20240101_120000]
AS SNAPSHOT OF [HR]
```

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | パラメータエラー | Database/AllDatabases未指定 | Stop-Function |
| - | パス不正 | Path存在しない | Stop-Function -Continue |
| - | 名前重複 | 同名スナップショット存在 | 警告出力、スキップ |
| - | メモリ最適化 | MEMORY_OPTIMIZED_DATA存在 | 警告出力、スキップ |
| - | FILESTREAM | FILESTREAM + !Force | 警告出力、スキップ |
| - | 作成失敗 | Create()失敗 | T-SQL実行リトライ |

### リトライ仕様

- SMO Create()失敗時はT-SQL直接実行でリトライ
- `$server.Query($sql[0])` で再試行

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

- CREATE DATABASE文はSQL Serverによって自動的にトランザクション管理
- 失敗時は自動ロールバック

## パフォーマンス要件

- スナップショット作成は即座に完了（コピーオンライト方式）
- ディスク使用量は変更があった場合のみ増加

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

- CREATE DATABASE権限が必要
- ConfirmImpact='Medium'による確認プロンプト
- -WhatIfによる事前シミュレーション
- PSCredentialによる安全な認証情報管理

## 備考

- スナップショットは通常のバックアップの代替ではない
- 不要になったスナップショットはパフォーマンス影響を避けるため削除推奨
- FILESTREAMデータは部分スナップショットに含まれない
- 部分スナップショットからのデータベース復元は不可

---

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

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

### 推奨読解順序

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

スナップショットファイル構造とSMOオブジェクト構築を理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | New-DbaDbSnapshot.ps1 | `public/New-DbaDbSnapshot.ps1` | 290-322行目: CustomFileStructure構築 |
| 1-2 | New-DbaDbSnapshot.ps1 | `public/New-DbaDbSnapshot.ps1` | 324-334行目: SMO Database/FileGroup/DataFile作成 |

**読解のコツ**: スナップショットファイルの拡張子は".ss"が事実上の標準です（311行目）。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | New-DbaDbSnapshot.ps1 | `public/New-DbaDbSnapshot.ps1` | 関数全体の構造（391行） |

**主要処理フロー**:
1. **137行目**: CmdletBinding - SupportsShouldProcess, ConfirmImpact='Medium'
2. **138-151行目**: パラメータ定義（13個）
3. **153-188行目**: beginブロック - 初期化とResolve-SnapshotError関数
4. **189-195行目**: パラメータ検証
5. **197-244行目**: データベース取得と検証
6. **246-268行目**: スナップショット名生成
7. **269-288行目**: FILESTREAMとメモリ最適化チェック
8. **289-334行目**: ファイル構造とSMOオブジェクト作成
9. **336-340行目**: SQLスクリプト生成
10. **342-387行目**: スナップショット作成と結果出力

#### Step 3: エラーハンドリングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | New-DbaDbSnapshot.ps1 | `public/New-DbaDbSnapshot.ps1` | 168-187行目: Resolve-SnapshotError関数 |
| 3-2 | New-DbaDbSnapshot.ps1 | `public/New-DbaDbSnapshot.ps1` | 346-387行目: 多段階エラーハンドリング |

**エラーハンドリングのコツ**:
- SMO Create()失敗時はT-SQL直接実行を試行
- 読み取り専用スナップショットでのSMOプロパティ設定問題に対応

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

```
New-DbaDbSnapshot
    │
    ├─ begin ブロック
    │      ├─ DefaultSuffix生成 (yyyyMMdd_HHmmss)
    │      ├─ NameSuffixテンプレート検証
    │      └─ Resolve-SnapshotError関数定義
    │
    ├─ パラメータ検証
    │      └─ Database or AllDatabases必須
    │
    ├─ foreach ($instance in $SqlInstance)
    │      ├─ Connect-DbaInstance -MinimumVersion 9
    │      ├─ Test-DbaPath (Path指定時)
    │      └─ データベース検証ループ
    │             ├─ ミラーリングDB → InputObject追加
    │             ├─ スナップショット → 警告、スキップ
    │             ├─ システムDB → 警告、スキップ
    │             ├─ AGセカンダリ → InputObject追加
    │             └─ 通常DB → InputObject追加
    │
    └─ foreach ($db in $InputObject)
           │
           ├─ スナップショット名生成
           │      ├─ NameSuffix → テンプレート補間
           │      ├─ Name → そのまま使用
           │      └─ デフォルト → {DB}_{Suffix}
           │
           ├─ 既存名チェック
           │
           ├─ FileGroup検証
           │      ├─ MEMORY_OPTIMIZED → 不可、スキップ
           │      └─ FILESTREAM + !Force → スキップ
           │
           ├─ CustomFileStructure構築
           │      └─ 各FileGroup/Fileのパス生成
           │
           ├─ SMO Database作成
           │      ├─ DatabaseSnapshotBaseName設定
           │      ├─ FileGroup追加
           │      └─ DataFile追加
           │
           ├─ SnapDB.Create()
           │      └─ 失敗時: $server.Query($sql)
           │
           └─ Get-DbaDbSnapshot -Snapshot $SnapName
```

### データフロー図

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

SqlInstance ───────▶ Connect-DbaInstance ──────▶ Server Object
Database ──────────▶ データベース検証
AllDatabases ──────▶ システムDB除外
ExcludeDatabase ───▶ 除外処理
     or                     │
InputObject ────────────────┤
                            ▼
Name ──────────────▶ スナップショット名生成
NameSuffix ────────▶ (NameSuffix -f $db.Name)
                            │
                            ▼
                    FileGroup検証
                    (FILESTREAM, MEMORY_OPTIMIZED)
                            │
                            ▼
Path ──────────────▶ ファイルパス生成
                    (.ss拡張子)
                            │
                            ▼
                    SMO Database/FileGroup/DataFile
                            │
                            ▼
                    SnapDB.Create()
                            │
                            ▼
                    Get-DbaDbSnapshot ──────────▶ 出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| New-DbaDbSnapshot.ps1 | `public/New-DbaDbSnapshot.ps1` | ソース | メイン機能実装（391行） |
| New-DbaDbSnapshot.Tests.ps1 | `tests/New-DbaDbSnapshot.Tests.ps1` | テスト | 単体テスト |
| Get-DbaDbSnapshot.ps1 | `public/Get-DbaDbSnapshot.ps1` | ソース | 結果出力に使用 |
| Remove-DbaDbSnapshot.ps1 | `public/Remove-DbaDbSnapshot.ps1` | ソース | スナップショット削除 |
| Restore-DbaDbSnapshot.ps1 | `public/Restore-DbaDbSnapshot.ps1` | ソース | スナップショットから復元 |
| Test-DbaPath.ps1 | `public/Test-DbaPath.ps1` | ソース | パス存在確認 |
