# 機能設計書 475-Copy-DbaAgentJob

## 概要

本ドキュメントは、SQL Server Agentジョブをソースインスタンスから宛先インスタンスに依存関係検証付きで移行するPowerShellコマンド「Copy-DbaAgentJob」の機能設計書である。

### 本機能の処理概要

Copy-DbaAgentJobは、SQL Server Agentジョブをソースインスタンスから1つ以上の宛先インスタンスにコピーする機能である。データベース、ログイン、プロキシアカウント、オペレーターなどの依存関係を自動的に検証し、不足している場合は適切なメッセージとともにスキップする。

**業務上の目的・背景**：サーバー移行、災害復旧、環境間でのジョブ展開において、ジョブの手動再作成は煩雑でエラーが発生しやすい。本機能を使用することで、複雑な依存関係を持つジョブを効率的に移行でき、前提条件のチェックを自動化することでミスを防止できる。特に、メンテナンスプランに関連付けられたジョブは自動的にスキップされ、依存関係の不足も明確にレポートされる。

**機能の利用シーン**：
- 本番サーバーから災害復旧サーバーへのジョブ構成の複製
- 開発環境から本番環境へのジョブデプロイ
- サーバー統合・移行プロジェクトでのジョブ移行
- Always On可用性グループ間でのジョブ同期

**主要な処理内容**：
1. ソースサーバーへの接続とジョブ一覧の取得
2. 宛先サーバーへの接続
3. 各ジョブの依存関係検証（データベース、ログイン、プロキシ、オペレーター）
4. メンテナンスプラン関連ジョブの検出とスキップ
5. 既存ジョブとの重複チェック
6. UseLastModifiedによる変更日付比較（オプション）
7. SMOスクリプトによるジョブの作成
8. アラートとジョブの関連付け復元
9. ソース/宛先でのジョブ無効化（オプション）

**関連システム・外部連携**：SQL Server Agentサービス、msdbデータベース、データベース、ログイン、プロキシアカウント、オペレーター、メンテナンスプランとの連携。

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

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Source | DbaInstanceParameter | No | コピー元SQL Serverインスタンス | SQL Server 2000以上。InputObject使用時は不要 |
| SourceSqlCredential | PSCredential | No | ソース接続用の資格情報 | - |
| Destination | DbaInstanceParameter[] | Yes | コピー先SQL Serverインスタンス（複数可） | SQL Server 2000以上 |
| DestinationSqlCredential | PSCredential | No | 宛先接続用の資格情報 | - |
| Job | object[] | No | コピーするジョブ名（ワイルドカード対応） | - |
| ExcludeJob | object[] | No | 除外するジョブ名（ワイルドカード対応） | - |
| DisableOnSource | switch | No | コピー後にソースでジョブを無効化 | - |
| DisableOnDestination | switch | No | 宛先でジョブを無効状態で作成 | - |
| Force | switch | No | 既存ジョブを削除して再作成。不足オーナーをsaに設定 | - |
| UseLastModified | switch | No | 変更日付を比較してインクリメンタル同期 | - |
| InputObject | Job[] | No | Get-DbaAgentJobからのパイプ入力 | - |
| WhatIf | switch | No | 実行内容のプレビュー | - |
| Confirm | switch | No | 実行前の確認プロンプト | - |
| EnableException | switch | No | 例外をスローするかどうか | - |

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. ソースサーバー接続とジョブ取得（begin）
   └─ Sourceパラメータ指定時はGet-DbaAgentJobでジョブ取得
2. 宛先サーバー接続（process）
   └─ 各宛先インスタンスにConnect-DbaInstanceで接続
3. 各ジョブの処理（foreach serverJob）
   ├─ フィルタリング（Job/ExcludeJobパラメータ）
   ├─ メンテナンスプラン関連付け確認
   ├─ データベース依存関係確認
   ├─ ログイン依存関係確認
   ├─ プロキシアカウント依存関係確認
   ├─ オペレーター依存関係確認
   ├─ 既存ジョブとの重複確認
   │   ├─ UseLastModified: 変更日付比較
   │   └─ Force: 削除して再作成
   ├─ ジョブの作成（Script()とQuery実行）
   ├─ アラート関連付けの復元（Force/UseLastModified時）
   ├─ ジョブの有効/無効状態設定
   └─ ソースでの無効化（DisableOnSource時）
4. 結果出力
   └─ 各操作ごとにMigrationObjectを出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{Source指定?}
    B -->|Yes| C[Get-DbaAgentJobでジョブ取得]
    B -->|No| D[InputObjectを使用]
    C --> E[foreach 宛先インスタンス]
    D --> E
    E --> F[宛先サーバー接続]
    F --> G[foreach ジョブ]
    G --> H{Job/ExcludeJobでフィルタ}
    H -->|除外| I[次のジョブへ]
    H -->|対象| J{メンテナンスプラン関連?}
    J -->|Yes| K[Skipped: メンテナンスプラン関連]
    J -->|No| L{データベース依存確認}
    L -->|NG| M[Skipped: DB不足]
    L -->|OK| N{ログイン依存確認}
    N -->|NG| O{Force指定?}
    O -->|No| P[Skipped: ログイン不足]
    O -->|Yes| Q[オーナーをsaに設定して続行]
    N -->|OK| Q
    Q --> R{プロキシ依存確認}
    R -->|NG| S[Skipped: プロキシ不足]
    R -->|OK| T{オペレーター依存確認}
    T -->|NG| U[Skipped: オペレーター不足]
    T -->|OK| V{宛先に既存?}
    V -->|Yes| W{UseLastModified?}
    W -->|Yes| X[変更日付比較]
    X -->|ソースが新しい| Y[削除して再作成]
    X -->|同じまたは宛先が新しい| Z[Skipped]
    W -->|No| AA{Force?}
    AA -->|Yes| Y
    AA -->|No| AB[Skipped: 既存]
    V -->|No| AC[ジョブ作成]
    Y --> AD[アラート関連付け復元]
    AD --> AC
    AC --> AE{DisableOnDestination?}
    AE -->|Yes| AF[宛先で無効化]
    AE -->|No| AG{DisableOnSource?}
    AF --> AG
    AG -->|Yes| AH[ソースで無効化]
    AG -->|No| I
    AH --> I
    K --> I
    M --> I
    P --> I
    S --> I
    U --> I
    Z --> I
    AB --> I
    I --> G
    G --> E
    E --> AI[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | メンテナンスプラン除外 | sysmaintplan_subplansに関連付けられたジョブはスキップ | 常時 |
| BR-002 | データベース依存 | ジョブステップで使用するデータベースが宛先に存在しない場合はスキップ | ActiveScripting/AnalysisQuery/AnalysisCommand以外のサブシステム |
| BR-003 | ログイン依存 | ジョブオーナーのログインが宛先に存在しない場合、Forceなしでスキップ | 常時 |
| BR-004 | ログインForce動作 | ログイン不足時にForce指定があればオーナーをsaに設定 | Force指定時 |
| BR-005 | プロキシ依存 | ジョブステップで使用するプロキシが宛先に存在しない場合はスキップ | ジョブステップにProxyNameが設定されている場合 |
| BR-006 | オペレーター依存 | ジョブの通知先オペレーターが宛先に存在しない場合はスキップ | ジョブにオペレーター設定がある場合 |
| BR-007 | UseLastModified動作 | 変更日付比較でソースが新しい場合のみ更新 | UseLastModified指定時 |
| BR-008 | アラート復元 | ジョブ削除・再作成時は関連アラートのジョブ関連付けを復元 | Force/UseLastModifiedでジョブを再作成した場合 |

### 計算ロジック

**UseLastModifiedの比較ロジック**:
- ソース date_modified > 宛先 date_modified: 削除して再作成
- ソース date_modified = 宛先 date_modified: スキップ
- ソース date_modified < 宛先 date_modified: スキップ（警告付き）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| メンテナンスプラン確認 | msdb.dbo.sysmaintplan_subplans | SELECT | ジョブとメンテナンスプランの関連確認 |
| 変更日付取得 | msdb.dbo.sysjobs | SELECT | date_modifiedの比較 |
| アラート関連取得 | msdb.dbo.sysalerts | SELECT | ジョブに関連付けられたアラートの取得 |
| ジョブ削除 | msdb.dbo.sysjobs等 | DELETE | Job.Drop()により削除 |
| ジョブ作成 | msdb.dbo.sysjobs等 | INSERT | Job.Script()で生成したT-SQLを実行 |
| アラート更新 | msdb.dbo.sysalerts | UPDATE | sp_update_alertでジョブ関連付け復元 |

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

#### msdb.dbo.sysjobs

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | date_modified | WHERE name = @jobName | UseLastModified用 |
| INSERT | 全カラム | ソースジョブの設定値 | SMO Script()で生成 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ConnectionError | 接続エラー | ソースまたは宛先に接続できない | Stop-Functionで処理を中断 |
| MaintenancePlan | メンテナンスプラン関連 | ジョブがメンテナンスプランに関連 | Skippedとして記録し次のジョブへ |
| DatabaseMissing | DB不足 | ジョブステップのDBが宛先に存在しない | Skippedとして記録し次のジョブへ |
| LoginMissing | ログイン不足 | ジョブオーナーが宛先に存在しない | Skipped（Forceなし）またはsa設定（Forceあり） |
| ProxyMissing | プロキシ不足 | ジョブステップのプロキシが宛先に存在しない | Skippedとして記録し次のジョブへ |
| OperatorMissing | オペレーター不足 | 通知先オペレーターが宛先に存在しない | Skippedとして記録し次のジョブへ |

### リトライ仕様

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

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

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

## パフォーマンス要件

特になし。ジョブ数に比例して処理時間が増加するが、通常は数秒から数分程度。

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

- ソースおよび宛先の両方でsysadmin権限が必要
- SQL認証使用時は資格情報がSecureStringとして管理される
- Forceオプション使用時はジョブオーナーがsaに変更される場合がある
- WhatIfパラメータによる事前確認が可能

## 備考

- メンテナンスプランに関連付けられたジョブは、Copy-DbaDbMaintenanceSolutionで別途移行する必要がある
- ジョブの有効/無効状態はソースから継承されるが、DisableOnDestinationで上書き可能
- UseLastModifiedは大量のジョブがある環境でのインクリメンタル同期に有効

---

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

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

### 推奨読解順序

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

SMOのJobオブジェクトの構造と、関連するデータベース、ログイン、プロキシ、オペレーターとの依存関係を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Copy-DbaAgentJob.ps1 | `public/Copy-DbaAgentJob.ps1` | 172-186行目で依存関係情報を取得 |

**読解のコツ**: Jobオブジェクトは.JobSteps、.OwnerLoginName、.OperatorToEmail等のプロパティで依存情報にアクセスできる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Copy-DbaAgentJob.ps1 | `public/Copy-DbaAgentJob.ps1` | 124-140行目のパラメータ定義、141-161行目のbeginブロック |

**主要処理フロー**:
1. **141-161行目**: beginブロックでGet-DbaAgentJobによるジョブ取得
2. **197-215行目**: メンテナンスプラン関連確認
3. **217-229行目**: データベース依存確認
4. **231-244行目**: ログイン依存確認
5. **246-258行目**: プロキシ依存確認
6. **260-272行目**: オペレーター依存確認
7. **274-390行目**: 既存確認とUseLastModified/Force処理
8. **392-442行目**: ジョブ作成とアラート復元
9. **444-458行目**: 無効化処理

#### Step 3: UseLastModifiedロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Copy-DbaAgentJob.ps1 | `public/Copy-DbaAgentJob.ps1` | 275-358行目のUseLastModified処理 |

**主要処理フロー**:
- **278-292行目**: ソースと宛先のdate_modifiedをInvoke-DbaQueryで取得
- **305-327行目**: ソースが新しい場合は削除して再作成
- **328-336行目**: 日付が同じ場合はスキップ
- **337-346行目**: 宛先が新しい場合は警告付きでスキップ

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

```
Copy-DbaAgentJob
    │
    ├─ Get-DbaAgentJob（Source指定時）
    │      └─ ソースジョブ取得
    │
    ├─ Connect-DbaInstance（Destination）
    │      └─ 宛先サーバー接続
    │
    ├─ $sourceServer.Query()（メンテナンスプラン確認）
    │      └─ sysmaintplan_subplansへのクエリ
    │
    ├─ Invoke-DbaQuery（UseLastModified時）
    │      └─ date_modifiedの取得
    │
    ├─ $destServer.JobServer.Jobs[$jobName].Drop()
    │      └─ 既存ジョブの削除
    │
    ├─ $serverJob.Script()
    │      └─ ジョブ作成スクリプト生成
    │
    ├─ $destServer.Query()
    │      └─ T-SQL実行（ジョブ作成）
    │
    └─ Invoke-DbaQuery（アラート復元時）
           └─ sp_update_alertでジョブ関連付け
```

### データフロー図

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

Source/InputObject ───▶ Get-DbaAgentJob ───▶ $InputObject (ジョブ一覧)
                                    │
Destination        ───▶ Connect-DbaInstance ───▶ $destServer
                                    │
                                    ▼
各ジョブ ───▶ 依存関係チェック ───▶ スキップ or 続行
                    │
                    ├─ メンテナンスプラン確認
                    ├─ データベース確認
                    ├─ ログイン確認
                    ├─ プロキシ確認
                    └─ オペレーター確認
                    │
                    ▼
           既存確認/UseLastModified ───▶ 削除 or スキップ
                    │
                    ▼
           Script()でT-SQL生成 ───▶ Query()で実行
                    │
                    ▼
           アラート関連付け復元
                    │
                    ▼
           有効/無効状態設定
                    │
                    ▼
                [MigrationObject出力]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Copy-DbaAgentJob.ps1 | `public/Copy-DbaAgentJob.ps1` | ソース | メイン処理ロジック |
| Get-DbaAgentJob.ps1 | `public/Get-DbaAgentJob.ps1` | ソース | ジョブ取得用コマンド |
| Copy-DbaAgentJobStep.ps1 | `public/Copy-DbaAgentJobStep.ps1` | ソース | ジョブステップのみのコピー |
| Copy-DbaAgentProxy.ps1 | `public/Copy-DbaAgentProxy.ps1` | ソース | 前提となるプロキシコピー |
| Copy-DbaAgentOperator.ps1 | `public/Copy-DbaAgentOperator.ps1` | ソース | 前提となるオペレーターコピー |
| Connect-DbaInstance.ps1 | `public/Connect-DbaInstance.ps1` | ソース | SQL Server接続用コマンド |
| Copy-DbaAgentJob.Tests.ps1 | `tests/Copy-DbaAgentJob.Tests.ps1` | テスト | 単体テスト |
