# 機能設計書 480-Copy-DbaAgentSchedule

## 概要

本ドキュメントは、SQL Server Agentの共有ジョブスケジュールをソースインスタンスから宛先インスタンスにコピーするPowerShellコマンド「Copy-DbaAgentSchedule」の機能設計書である。

### 本機能の処理概要

Copy-DbaAgentScheduleは、SQL Server Agentの共有ジョブスケジュール（ジョブ固有のスケジュールではない）をソースインスタンスから1つ以上の宛先インスタンスにコピーする機能である。T-SQLスクリプトを使用してスケジュール定義を移行する。

**業務上の目的・背景**：複数のサーバー間でジョブスケジュールを標準化する場合や、新しいインスタンスに既存のスケジュール構成を展開する場合、複雑な繰り返しスケジュールを手動で再作成することは時間がかかりミスが発生しやすい。本機能を使用することで、特定のタイミング要件を持つ複雑なスケジュールを効率的に移行できる。

**機能の利用シーン**：
- 本番サーバーから災害復旧サーバーへのスケジュール構成の複製
- 新規サーバー構築時の標準スケジュール設定の展開
- サーバー統合・移行プロジェクトでのスケジュール移行
- 複数環境間でのスケジュール設定の標準化

**主要な処理内容**：
1. ソースサーバーへの接続とスケジュール取得（またはInputObject使用）
2. 宛先サーバーへの接続
3. 宛先の既存スケジュールキャッシュの更新
4. 各スケジュールの処理
5. 既存スケジュールとの重複チェック（ジョブ関連付け確認含む）
6. SMOスクリプトによるスケジュールの作成
7. 処理結果の出力

**関連システム・外部連携**：SQL Server Agentサービス、msdbデータベース。

**権限による制御**：ソースおよび宛先の両方でsysadmin固定サーバーロールのメンバーシップが必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | SQL Server Management Studio - SQL Server Agent - Jobs - Schedules | 参照画面 | スケジュール設定の確認 |

## 機能種別

データ移行処理 / SMOスクリプティング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Source | DbaInstanceParameter | No | コピー元SQL Serverインスタンス | SQL Server 2005以上（MinimumVersion 9）。InputObject使用時は不要 |
| SourceSqlCredential | PSCredential | No | ソース接続用の資格情報 | - |
| Destination | DbaInstanceParameter[] | Yes | コピー先SQL Serverインスタンス（複数可） | SQL Server 2005以上（MinimumVersion 9） |
| DestinationSqlCredential | PSCredential | No | 宛先接続用の資格情報 | - |
| Schedule | string[] | No | コピーするスケジュール名（ワイルドカード対応） | - |
| Id | int[] | No | コピーするスケジュールID | 重複スケジュール名がある場合に使用 |
| InputObject | JobSchedule[] | No | Get-DbaAgentScheduleからのパイプ入力 | - |
| Force | switch | No | 既存スケジュールを削除して再作成（ジョブ関連付けがある場合は不可） | - |
| WhatIf | switch | No | 実行内容のプレビュー | - |
| Confirm | switch | No | 実行前の確認プロンプト | - |
| EnableException | switch | No | 例外をスローするかどうか | - |

### 入力データソース

- ソースSQL ServerのJobServer.SharedSchedulesコレクション
- パイプライン経由のJobScheduleオブジェクト（Get-DbaAgentScheduleから）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| DateTime | DbaDateTime | 処理実行日時（UTC） |
| SourceServer | string | ソースSQL Serverインスタンス名 |
| DestinationServer | string | 宛先SQL Serverインスタンス名 |
| Name | string | スケジュール名 |
| Type | string | オブジェクトタイプ（Agent Schedule） |
| Status | string | 処理結果（Successful, Failed, Skipped） |
| Notes | string | 追加情報（スキップ理由など） |

### 出力先

パイプライン出力（PSCustomObject - MigrationObject）

## 処理フロー

### 処理シーケンス

```
1. ソースサーバー接続とスケジュール取得（begin）
   └─ Sourceパラメータ指定時はGet-DbaAgentScheduleでスケジュール取得
2. 宛先サーバー接続（process）
   └─ Connect-DbaInstance -MinimumVersion 9で宛先に接続
3. 宛先スケジュールキャッシュの更新
   └─ $destServer.JobServer.SharedSchedules.Refresh()
4. 各スケジュールの処理（foreach currentschedule）
   ├─ 既存スケジュールの確認
   │   ├─ 既存でForceなし: スキップ
   │   ├─ 既存でForceあり: ジョブ関連付け確認
   │   │   ├─ ジョブ関連付けあり: スキップ
   │   │   └─ ジョブ関連付けなし: 削除して再作成
   └─ Script()でスケジュール作成
5. 結果出力
   └─ 各操作ごとにMigrationObjectを出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{Source指定?}
    B -->|Yes| C[Connect-DbaInstance -MinimumVersion 9]
    B -->|No| D{InputObject指定?}
    D -->|No| E[エラー: SourceまたはInputObject必須]
    D -->|Yes| F[InputObjectを使用]
    C --> G[Get-DbaAgentScheduleでスケジュール取得]
    G --> H[foreach 宛先インスタンス]
    F --> H
    H --> I[宛先サーバー接続]
    I --> J[SharedSchedules.Refresh]
    J --> K[Get-DbaAgentScheduleで宛先スケジュール取得]
    K --> L[foreach スケジュール]
    L --> M{宛先に既存?}
    M -->|Yes| N{Force指定?}
    N -->|No| O[Skipped: 既に存在]
    N -->|Yes| P{ジョブ関連付けあり?}
    P -->|Yes| Q[Skipped: ジョブ関連付けあり]
    P -->|No| R[既存スケジュール削除]
    M -->|No| S[スケジュール作成]
    R --> S
    S --> T{作成成功?}
    T -->|Yes| U[Successful]
    T -->|No| V[Failed]
    O --> W[次のスケジュールへ]
    Q --> W
    U --> W
    V --> W
    W --> L
    L --> H
    H --> X[終了]
    E --> X
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 共有スケジュールのみ | ジョブ固有のスケジュールではなく、SharedSchedulesのみが対象 | 常時 |
| BR-002 | Force動作 | Forceが指定された場合、既存スケジュールを削除して再作成 | 宛先に同名スケジュールが存在する場合 |
| BR-003 | ジョブ関連付け保護 | ジョブに関連付けられたスケジュールはForce指定時も削除されない | 常時 |
| BR-004 | 入力ソース必須 | SourceまたはInputObjectのいずれかが必須 | 常時 |
| BR-005 | 最小バージョン | SQL Server 2005以降が必要 | 常時 |
| BR-006 | スケジュール名重複 | SQL Serverは同名スケジュールを許可するため、Idパラメータで特定可能 | 重複スケジュール名がある場合 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| スケジュール削除 | msdb.dbo.sysschedules | DELETE | SMO Drop()により削除 |
| スケジュール作成 | msdb.dbo.sysschedules | INSERT | SMO Script()で生成したT-SQLを実行 |

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

#### msdb.dbo.sysschedules

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | schedule_id, name, freq_type, freq_interval, etc. | ソーススケジュールの設定値 | SMO Script()で生成 |
| DELETE | - | WHERE name = @scheduleName | SMO Drop()で削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ConnectionError | 接続エラー | ソースまたは宛先に接続できない | Stop-Functionで処理を中断 |
| ParameterError | パラメータエラー | SourceもInputObjectも指定されていない | Stop-Functionでエラーメッセージを表示 |
| JobAssociation | ジョブ関連付け | スケジュールがジョブに関連付けられている | Skippedとして記録し次のスケジュールへ |
| DropError | 削除エラー | 既存スケジュールの削除に失敗 | Failedとして記録し次のスケジュールへ |
| CreateError | 作成エラー | スケジュールの作成に失敗 | Failedとして記録し次のスケジュールへ |

### リトライ仕様

リトライ処理は実装されていない。エラー発生時は次のスケジュールの処理に移行する。

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

個々のスケジュール作成操作は独立したトランザクションとして実行される。一括トランザクションは使用されない。

## パフォーマンス要件

特になし。スケジュール数に比例して処理時間が増加するが、通常は数秒程度。

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

- ソースおよび宛先の両方でsysadmin権限が必要
- SQL認証使用時は資格情報がSecureStringとして管理される
- ジョブに関連付けられたスケジュールは保護されているため、誤って削除されることはない
- WhatIfパラメータによる事前確認が可能

## 備考

- SharedSchedules（共有スケジュール）のみが対象で、ジョブ固有のスケジュールは含まれない
- スケジュール移行後、ジョブとの関連付けは別途行う必要がある
- Out-GridViewと組み合わせて選択的にスケジュールをコピー可能

---

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

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

### 推奨読解順序

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

SMOのJobScheduleオブジェクトの構造と、共有スケジュールの概念を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Copy-DbaAgentSchedule.ps1 | `public/Copy-DbaAgentSchedule.ps1` | 120行目でGet-DbaAgentScheduleによるスケジュール取得 |

**読解のコツ**: JobScheduleオブジェクトは$server.JobServer.SharedSchedulesに格納されており、Parentプロパティでサーバーにアクセスできる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Copy-DbaAgentSchedule.ps1 | `public/Copy-DbaAgentSchedule.ps1` | 96-109行目のパラメータ定義、110-123行目のbeginブロック |

**主要処理フロー**:
1. **110-123行目**: beginブロックでソース接続とスケジュール取得
2. **128-131行目**: 入力検証（SourceまたはInputObject必須）
3. **141行目**: SharedSchedules.Refresh()でキャッシュ更新
4. **143行目**: Get-DbaAgentScheduleで宛先スケジュール取得
5. **158-190行目**: 既存確認とForce処理（ジョブ関連付け確認含む）
6. **192-207行目**: Script()でスケジュール作成

#### Step 3: ジョブ関連付け確認を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Copy-DbaAgentSchedule.ps1 | `public/Copy-DbaAgentSchedule.ps1` | 168-175行目のジョブ関連付け確認 |

**主要処理フロー**:
- **168行目**: ShouldProcessでジョブ関連付け確認
- **169行目**: $destServer.JobServer.Jobs.JobSchedules.Nameでジョブに関連付けられたスケジュール名を取得
- **170-174行目**: 関連付けがある場合はスキップ

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

```
Copy-DbaAgentSchedule
    │
    ├─ Connect-DbaInstance -MinimumVersion 9（Source）
    │      └─ ソースサーバー接続
    │
    ├─ Get-DbaAgentSchedule（スケジュール取得）
    │      └─ Schedule/Idパラメータでフィルタリング
    │
    ├─ Connect-DbaInstance -MinimumVersion 9（Destination）
    │      └─ 宛先サーバー接続
    │
    ├─ $destServer.JobServer.SharedSchedules.Refresh()
    │      └─ キャッシュ更新
    │
    ├─ Get-DbaAgentSchedule（宛先スケジュール確認）
    │      └─ 既存スケジュール取得
    │
    ├─ $destServer.JobServer.Jobs.JobSchedules.Name
    │      └─ ジョブ関連付け確認
    │
    ├─ $destServer.JobServer.SharedSchedules[$scheduleName].Drop()
    │      └─ 既存スケジュールの削除（Force時）
    │
    ├─ $currentschedule.Script()
    │      └─ スケジュール作成スクリプト生成
    │
    └─ $destServer.Query()
           └─ T-SQL実行（sp_add_schedule）
```

### データフロー図

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

Source           ───▶ Connect-DbaInstance ───▶ $sourceServer
                                │
                                ▼
Get-DbaAgentSchedule ───▶ スケジュール一覧
                                │
Destination      ───▶ Connect-DbaInstance ───▶ $destServer
                                │
                                ▼
SharedSchedules.Refresh() ───▶ キャッシュ更新
                                │
                                ▼
各スケジュール ───▶ 既存確認 / ジョブ関連付け確認 ───▶ スキップ or 続行
                    │
                    ▼
           Script()でT-SQL生成 ───▶ Query()で実行
                    │
                    ▼
                [MigrationObject出力]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Copy-DbaAgentSchedule.ps1 | `public/Copy-DbaAgentSchedule.ps1` | ソース | メイン処理ロジック |
| Get-DbaAgentSchedule.ps1 | `public/Get-DbaAgentSchedule.ps1` | ソース | スケジュール取得用コマンド |
| Copy-DbaAgentJob.ps1 | `public/Copy-DbaAgentJob.ps1` | ソース | ジョブコピー（スケジュール含む） |
| Connect-DbaInstance.ps1 | `public/Connect-DbaInstance.ps1` | ソース | SQL Server接続用コマンド |
