# 機能設計書 430-Copy-DbaRegServer

## 概要

本ドキュメントは、dbatools PowerShellモジュールの`Copy-DbaRegServer`コマンドレットに関する機能設計書である。このコマンドレットは、Central Management Server（CMS）のグループと登録済みサーバーインスタンスをSQL Serverインスタンス間でコピーする機能を提供する。

### 本機能の処理概要

`Copy-DbaRegServer`は、ソースCMSから宛先CMSへ登録済みサーバーとサーバーグループを移行するコマンドレットである。グループとサブグループの階層構造を保持しながら移行を実行する。

**業務上の目的・背景**：企業環境では、複数のCMSを運用したり、CMSを新しいサーバーに移行したりすることがある。本機能により、複雑なサーバー組織構造を手動で再作成する必要なく、CMSの構成を効率的に移行できる。また、DR/HA環境でのCMS同期やCMS統合にも利用できる。

**機能の利用シーン**：
- CMSを新しいSQL Serverインスタンスに移行する場合
- 複数のCMS環境を統合する場合
- DR環境にCMS構成をレプリケートする場合
- 開発環境から本番環境にCMS構成をコピーする場合
- 特定のサーバーグループのみを別のCMSにコピーする場合

**主要な処理内容**：
1. ソースCMSに接続し、登録済みサーバーストアを取得する
2. 対象グループを特定する（全グループまたは指定グループ）
3. 各グループと登録済みサーバーを再帰的に宛先CMSにコピーする
4. 競合が発生した場合はスキップまたは上書き（Force指定時）
5. 結果を返却する

**関連システム・外部連携**：SQL Server Registered Servers機能と連携し、Microsoft.SqlServer.Management.RegisteredServers名前空間のオブジェクトを使用する。

**権限による制御**：ソースおよび宛先CMSサーバーへのsysadminアクセスが必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | SQL Server Management Studio - Registered Servers | 参照画面 | SSMS上での登録済みサーバーのコピー/移行に相当 |

## 機能種別

データ移行 / マイグレーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Source | DbaInstanceParameter | Yes | コピー元CMSのSQL Serverインスタンス | 有効なSQL Server接続文字列 |
| SourceSqlCredential | PSCredential | No | ソースCMS接続用の代替資格情報 | 有効なPSCredentialオブジェクト |
| Destination | DbaInstanceParameter[] | Yes | コピー先CMSのSQL Serverインスタンス | 有効なSQL Server接続文字列 |
| DestinationSqlCredential | PSCredential | No | 宛先CMS接続用の代替資格情報 | 有効なPSCredentialオブジェクト |
| Group | string[] | No | コピーする特定のトップレベルグループ。未指定時は全グループ | なし |
| SwitchServerName | switch | No | 移行時にソースサーバー名参照を宛先サーバー名に置換 | なし |
| Force | switch | No | 既存のグループ/サーバーを削除して再作成 | なし |
| WhatIf | switch | No | 実行内容を表示するのみ | なし |
| Confirm | switch | No | 実行前に確認を求める | なし |
| EnableException | switch | No | 例外をスローするモードを有効化 | なし |

### 入力データソース

- ソースSQL Serverインスタンス（Sourceパラメータ）
- 宛先SQL Serverインスタンス（Destinationパラメータ）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| DateTime | DbaDateTime | 操作のタイムスタンプ |
| SourceServer | string | ソースSQL Serverインスタンス名 |
| DestinationServer | string | 宛先SQL Serverインスタンス名 |
| Name | string | 移行されたCMSグループまたは登録サーバーの名前 |
| Type | string | オブジェクトの種類（"CMS Destination Group", "CMS Group", "CMS Instance"） |
| Status | string | 操作結果（"Successful", "Skipped", "Failed"） |
| Notes | string | 追加情報（スキップ理由やエラーメッセージ） |

### 出力先

- PowerShellパイプライン（標準出力）
- PSCustomObjectとして出力

## 処理フロー

### 処理シーケンス

```
1. beginブロック
   ├─ Force指定時はConfirmPreferenceを'none'に設定
   ├─ Invoke-ParseServerGroup関数の定義
   │   ├─ 宛先グループの作成/更新
   │   ├─ 各登録サーバーの処理
   │   │   ├─ CMS自身への登録チェック
   │   │   ├─ SwitchServerName処理
   │   │   ├─ 既存サーバーの処理（スキップまたは上書き）
   │   │   └─ サーバー登録
   │   └─ サブグループの再帰処理
   ├─ ソースCMSへの接続
   └─ 登録済みサーバーストアの取得
2. processブロック
   ├─ Test-FunctionInterruptでの中断チェック
   ├─ 各宛先インスタンスの処理
   │   ├─ 宛先CMSへの接続
   │   ├─ 宛先登録済みサーバーストアの取得
   │   └─ Invoke-ParseServerGroupの呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{Force指定?}
    B -->|Yes| C[ConfirmPreference = none]
    B -->|No| D[ソースCMS接続]
    C --> D
    D --> E{接続成功?}
    E -->|No| Z[終了]
    E -->|Yes| F[Get-DbaRegServerStore]
    F --> G[各宛先インスタンスを処理]
    G --> H[宛先CMS接続]
    H --> I[Get-DbaRegServerStore]
    I --> J{Group指定?}
    J -->|Yes| K[指定グループのみ取得]
    J -->|No| L[全グループ取得]
    K --> M[Invoke-ParseServerGroup]
    L --> M
    M --> N[宛先グループ存在確認]
    N --> O{グループ存在?}
    O -->|Yes, Force=false| P[Skipped出力]
    O -->|Yes, Force=true| Q[グループ削除]
    O -->|No| R[グループ作成]
    Q --> R
    R --> S[各登録サーバー処理]
    S --> T{CMS自身?}
    T -->|Yes, Switch=false| U[Skipped出力]
    T -->|Yes, Switch=true| V[サーバー名置換]
    T -->|No| W{サーバー存在?}
    V --> W
    W -->|Yes, Force=false| X[Skipped出力]
    W -->|Yes, Force=true| Y[サーバー削除]
    W -->|No| AA[サーバー作成]
    Y --> AA
    AA --> AB{次のサーバー?}
    P --> AB
    U --> AB
    X --> AB
    AB -->|Yes| S
    AB -->|No| AC[サブグループ再帰処理]
    AC --> AD{次のサブグループ?}
    AD -->|Yes| M
    AD -->|No| AE{次の宛先?}
    AE -->|Yes| G
    AE -->|No| Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | CMS自己登録禁止 | CMSは自身を登録済みサーバーとして登録できない | すべての実行 |
| BR-002 | SwitchServerName | CMS自身への登録時、SwitchServerName指定でソース名に置換 | SwitchServerName指定時 |
| BR-003 | 既存スキップ | Force未指定時、既存グループ/サーバーはスキップ | Force未指定時 |
| BR-004 | 強制上書き | Force指定時、既存グループ/サーバーを削除して再作成 | Force指定時 |
| BR-005 | 階層保持 | グループとサブグループの階層構造を保持して移行 | すべての実行 |
| BR-006 | 最低バージョン | SQL Server 2008（Version 10）以上が必要 | すべての実行 |

### 計算ロジック

特になし。パラメータ値はそのまま移行処理に適用される。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| CMSグループ取得 | msdb.dbo.sysmanagement_shared_server_groups | SELECT | ソースからのグループ情報取得 |
| CMSサーバー取得 | msdb.dbo.sysmanagement_shared_registered_servers | SELECT | ソースからのサーバー情報取得 |
| CMSグループ作成 | msdb.dbo.sysmanagement_shared_server_groups | INSERT | 宛先へのグループ作成 |
| CMSサーバー作成 | msdb.dbo.sysmanagement_shared_registered_servers | INSERT | 宛先へのサーバー登録 |
| CMSグループ削除 | msdb.dbo.sysmanagement_shared_server_groups | DELETE | 既存グループの削除（Force時） |
| CMSサーバー削除 | msdb.dbo.sysmanagement_shared_registered_servers | DELETE | 既存サーバーの削除（Force時） |

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

#### msdb.dbo.sysmanagement_shared_server_groups

| 操作 | 項目（カラム名） | 更新値・条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | ソースCMSから取得 | グループ情報 |
| INSERT | name, parent_id | ソースからコピー | グループ作成 |
| DELETE | server_group_id | Force指定時 | グループ削除 |

#### msdb.dbo.sysmanagement_shared_registered_servers

| 操作 | 項目（カラム名） | 更新値・条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | ソースCMSから取得 | サーバー情報 |
| INSERT | name, server_name, description, server_group_id | ソースからコピー | サーバー登録 |
| DELETE | server_id | Force指定時 | サーバー削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ConnectionError | ソースCMS接続失敗 | 接続情報を確認 |
| - | ConnectionError | 宛先CMS接続失敗 | 接続情報を確認（-Continue） |
| - | Drop失敗 | グループ削除失敗 | エラーメッセージを確認 |
| - | Create失敗 | グループ/サーバー作成失敗 | エラーメッセージを確認 |

### リトライ仕様

リトライ処理は実装されていない。エラー時は-Continueで次のアイテムを処理。

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

各グループ/サーバーの操作は個別に実行される。明示的なトランザクション制御は実装されていない。

## パフォーマンス要件

特に規定なし。メタデータの移行処理であり、データ量に応じた処理時間。

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

- SQL Server認証、Windows認証、Azure AD認証をサポート
- 接続資格情報はPSCredentialオブジェクトで安全に管理
- sysadminアクセスが必要
- 接続文字列とSecureConnectionStringは移行時に保持される

## 備考

- SQL Server 2008以降（Version 10以上）が必要
- 著者はChrissy LeMaire
- SupportsShouldProcess対応（WhatIf/Confirm）
- Groupパラメータの別名はCMSGroup
- 内部でInvoke-ParseServerGroup関数を再帰的に呼び出し

---

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

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

### 推奨読解順序

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

移行オブジェクトの構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Copy-DbaRegServer.ps1 | `public/Copy-DbaRegServer.ps1` | .OUTPUTSセクション（61-74行目）で出力オブジェクトの構造を理解 |

**読解のコツ**: 出力はPSCustomObjectであり、各移行操作（グループ作成、サーバー追加など）ごとに1オブジェクトが返却される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Copy-DbaRegServer.ps1 | `public/Copy-DbaRegServer.ps1` | パラメータ定義（93-106行目）で入力の受け取り方を確認 |

**主要処理フロー**:
1. **107-108行目**: beginブロックでのForce処理
2. **110-319行目**: Invoke-ParseServerGroup関数定義
3. **321-328行目**: ソースCMS接続とストア取得
4. **330-352行目**: processブロックでの宛先処理

#### Step 3: 再帰処理ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Copy-DbaRegServer.ps1 | `public/Copy-DbaRegServer.ps1` | Invoke-ParseServerGroup関数（110-319行目） |

**主要処理フロー**:
- **117-172行目**: 宛先グループの作成/更新
- **174-257行目**: 各登録サーバーの処理
- **259-318行目**: サブグループの再帰処理

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

```
Copy-DbaRegServer
    │
    ├─ Connect-DbaInstance (Source)
    │      └─ ソースCMS接続（MinimumVersion 10）
    │
    ├─ Get-DbaRegServerStore (Source)
    │      └─ ソース登録済みサーバーストア取得
    │
    ├─ Connect-DbaInstance (Destination)
    │      └─ 宛先CMS接続（MinimumVersion 10）
    │
    ├─ Get-DbaRegServerStore (Destination)
    │      └─ 宛先登録済みサーバーストア取得
    │
    └─ Invoke-ParseServerGroup（再帰）
           ├─ ServerGroup.Drop()（Force時）
           ├─ New-Object ServerGroup
           ├─ ServerGroup.Create()
           ├─ RegisteredServer.Drop()（Force時）
           ├─ New-Object RegisteredServer
           ├─ RegisteredServer.Create()
           └─ Invoke-ParseServerGroup（サブグループ）
```

### データフロー図

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

Source        ───────▶ Connect-DbaInstance
                            │
                            ▼
                 Get-DbaRegServerStore ───────▶ $fromCmStore
                            │
                            ▼
Destination   ───────▶ Connect-DbaInstance
                            │
                            ▼
                 Get-DbaRegServerStore ───────▶ $toCmStore
                            │
                            ▼
Group (optional) ──▶ 対象グループ選択
                            │
                            ▼
               Invoke-ParseServerGroup（再帰）
                    ├── グループ作成 ────────▶ PSCustomObject
                    ├── サーバー登録 ────────▶ PSCustomObject
                    └── サブグループ処理
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Copy-DbaRegServer.ps1 | `public/Copy-DbaRegServer.ps1` | ソース | メイン機能の実装 |
| Get-DbaRegServerStore.ps1 | `public/Get-DbaRegServerStore.ps1` | ソース | 登録済みサーバーストア取得 |
| Connect-DbaInstance.ps1 | `public/Connect-DbaInstance.ps1` | ソース | SQL Server接続 |
| Add-DbaRegServer.ps1 | `public/Add-DbaRegServer.ps1` | ソース | 登録サーバー追加（関連機能） |
| Add-DbaRegServerGroup.ps1 | `public/Add-DbaRegServerGroup.ps1` | ソース | サーバーグループ作成（関連機能） |
| Get-DbaRegServer.ps1 | `public/Get-DbaRegServer.ps1` | ソース | 登録サーバー取得（関連機能） |
| Get-DbaRegServerGroup.ps1 | `public/Get-DbaRegServerGroup.ps1` | ソース | サーバーグループ取得（関連機能） |
