# 機能設計書 477-Copy-DbaAgentJobStep

## 概要

本ドキュメントは、SQL Server Agentジョブのジョブステップをソースジョブから宛先ジョブにコピーするPowerShellコマンド「Copy-DbaAgentJobStep」の機能設計書である。

### 本機能の処理概要

Copy-DbaAgentJobStepは、SQL Server Agentジョブのジョブステップをソースジョブから宛先ジョブに同期する機能である。Copy-DbaAgentJobの-Forceオプションとは異なり、ジョブ全体を削除するのではなくステップのみを更新するため、ジョブ実行履歴が保持される。

**業務上の目的・背景**：Always On可用性グループ環境や災害復旧構成において、ジョブステップの変更を複数のレプリカ間で同期する必要がある。Copy-DbaAgentJobの-Forceオプションはジョブ全体を削除・再作成するため、貴重な実行履歴が失われる。本機能を使用することで、ジョブの所有権、スケジュール、アラート関連付け、および実行履歴を維持しながら、ステップ定義のみを更新できる。

**機能の利用シーン**：
- Always On可用性グループのプライマリからセカンダリへのジョブステップ同期
- 災害復旧サーバーへのジョブステップ更新
- 開発環境から本番環境へのジョブステップ展開
- 複数サーバー間でのジョブステップ標準化

**主要な処理内容**：
1. ソースサーバーへの接続とジョブ取得（またはInputObject使用）
2. 宛先サーバーへの接続
3. 宛先ジョブの存在確認
4. 宛先ジョブの既存ステップ削除
5. ソースジョブのステップをスクリプト化
6. ジョブIDをジョブ名に置換してスクリプト実行
7. 処理結果の出力

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

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

## 関連画面

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

## 機能種別

データ同期処理 / 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 | 除外するジョブ名 | - |
| Step | string[] | 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 Steps） |
| Status | string | 処理結果（Successful, Failed, Skipped） |
| Notes | string | 追加情報（同期したステップ数、スキップ理由など） |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. ソースサーバー接続とジョブ取得（begin）
   └─ Sourceパラメータ指定時はGet-DbaAgentJobでジョブ取得
2. 宛先サーバー接続（process）
   └─ 各宛先インスタンスにConnect-DbaInstanceで接続
3. 各ジョブの処理（foreach sourceJob）
   ├─ フィルタリング（Job/ExcludeJobパラメータ）
   ├─ 宛先ジョブの存在確認
   ├─ ソースステップのフィルタリング（Stepパラメータ）
   ├─ 宛先既存ステップの削除
   ├─ ソースステップのスクリプト生成
   ├─ ジョブIDをジョブ名に置換
   └─ スクリプト実行
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 -->|No| K[Skipped: ジョブなし]
    J -->|Yes| L{Stepパラメータ指定?}
    L -->|Yes| M[指定ステップのみフィルタ]
    L -->|No| N[全ステップ対象]
    M --> O{対象ステップあり?}
    O -->|No| P[Warning: ステップなし]
    O -->|Yes| Q[宛先既存ステップを配列化]
    N --> Q
    Q --> R{Stepパラメータ指定?}
    R -->|Yes| S[指定ステップのみ削除対象]
    R -->|No| T[全ステップ削除対象]
    S --> U[既存ステップを削除]
    T --> U
    U --> V[ステップごとにScript実行]
    V --> W[ジョブIDをジョブ名に置換]
    W --> X[Query実行]
    X --> Y[JobSteps.Refresh]
    Y --> Z{成功?}
    Z -->|Yes| AA[Successful + ステップ数]
    Z -->|No| AB[Failed]
    K --> I
    P --> I
    AA --> I
    AB --> I
    I --> G
    G --> E
    E --> AC[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 宛先ジョブ必須 | 宛先に同名のジョブが存在しない場合はスキップ | 常時 |
| BR-002 | 履歴保持 | ジョブ自体は削除せず、ステップのみを更新するため実行履歴が保持される | 常時 |
| BR-003 | ジョブID置換 | ソースのジョブIDを@job_nameに置換してスクリプト実行 | ステップ作成時 |
| BR-004 | ステップ選択 | Stepパラメータで特定のステップのみを同期可能 | Stepパラメータ指定時 |
| BR-005 | 削除後作成 | 既存ステップを削除してからソースステップを作成 | 常時 |

### 計算ロジック

特になし

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

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

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

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

#### msdb.dbo.sysjobsteps

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | WHERE job_id = @job_id | SMO Drop()で削除 |
| INSERT | step_id, step_name, command, etc. | ソースステップの設定値 | SMO Script()で生成 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ConnectionError | 接続エラー | ソースまたは宛先に接続できない | Stop-Functionで処理を中断 |
| JobNotFound | ジョブ未検出 | 宛先に同名ジョブが存在しない | Skippedとして記録し次のジョブへ |
| StepNotFound | ステップ未検出 | 指定されたステップ名が見つからない | Warningを出力し次のジョブへ |
| SyncError | 同期エラー | ステップの同期に失敗 | Failedとして記録し次のジョブへ |

### リトライ仕様

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

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

個々のステップ削除・作成操作は独立したトランザクションとして実行される。一括トランザクションは使用されない。

## パフォーマンス要件

特になし。ジョブ数とステップ数に比例して処理時間が増加するが、通常は数秒程度。

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

- ソースおよび宛先の両方でsysadmin権限が必要
- SQL認証使用時は資格情報がSecureStringとして管理される
- WhatIfパラメータによる事前確認が可能

## 備考

- Copy-DbaAgentJobの-Forceオプションと異なり、ジョブ実行履歴を保持できる
- ジョブ所有権、スケジュール、アラート関連付けは変更されない
- Always On可用性グループ環境でのジョブ同期に最適

---

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

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

### 推奨読解順序

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

SMOのJobオブジェクトとJobStepオブジェクトの構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Copy-DbaAgentJobStep.ps1 | `public/Copy-DbaAgentJobStep.ps1` | 183行目で$sourceJob.JobStepsを参照 |

**読解のコツ**: JobStepsはJobオブジェクトのコレクションプロパティで、各JobStepは.Name、.Command、.SubSystem等のプロパティを持つ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Copy-DbaAgentJobStep.ps1 | `public/Copy-DbaAgentJobStep.ps1` | 104-117行目のパラメータ定義、118-137行目のbeginブロック |

**主要処理フロー**:
1. **118-137行目**: beginブロックでGet-DbaAgentJobによるジョブ取得
2. **148-180行目**: 宛先ジョブ存在確認とフィルタリング
3. **182-190行目**: Stepパラメータによるフィルタリング
4. **192-207行目**: 既存ステップの削除
5. **209-217行目**: ソースステップのスクリプト生成と実行
6. **219-228行目**: 結果出力

#### Step 3: ジョブID置換ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Copy-DbaAgentJobStep.ps1 | `public/Copy-DbaAgentJobStep.ps1` | 214行目のジョブID置換正規表現 |

**主要処理フロー**:
- **212行目**: $sourceStep.Script()でT-SQL生成
- **214行目**: @job_id=N'GUID'を@job_name=N'JobName'に正規表現置換
- **216行目**: $destServer.Query($sql)で実行

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

```
Copy-DbaAgentJobStep
    │
    ├─ Get-DbaAgentJob（Source指定時）
    │      └─ ソースジョブ取得
    │
    ├─ Connect-DbaInstance（Destination）
    │      └─ 宛先サーバー接続
    │
    ├─ $destJob.JobSteps（既存ステップ取得）
    │      └─ 配列化して列挙可能にする
    │
    ├─ $stepToRemove.Drop()
    │      └─ 既存ステップの削除
    │
    ├─ $sourceStep.Script()
    │      └─ ステップ作成スクリプト生成
    │
    └─ $destServer.Query()
           └─ T-SQL実行（sp_add_jobstep）
```

### データフロー図

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

Source/InputObject ───▶ Get-DbaAgentJob ───▶ $InputObject (ジョブ一覧)
                                    │
Destination        ───▶ Connect-DbaInstance ───▶ $destServer
                                    │
                                    ▼
各ジョブ ───▶ 宛先ジョブ存在確認 ───▶ スキップ or 続行
                    │
                    ▼
           Stepフィルタリング
                    │
                    ▼
           既存ステップ削除 ───▶ Drop()
                    │
                    ▼
           ソースステップScript() ───▶ ジョブID置換
                    │
                    ▼
           Query()で実行
                    │
                    ▼
           JobSteps.Refresh()
                    │
                    ▼
                [MigrationObject出力]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Copy-DbaAgentJobStep.ps1 | `public/Copy-DbaAgentJobStep.ps1` | ソース | メイン処理ロジック |
| Get-DbaAgentJob.ps1 | `public/Get-DbaAgentJob.ps1` | ソース | ジョブ取得用コマンド |
| Copy-DbaAgentJob.ps1 | `public/Copy-DbaAgentJob.ps1` | ソース | ジョブ全体のコピー（比較対象） |
| Connect-DbaInstance.ps1 | `public/Connect-DbaInstance.ps1` | ソース | SQL Server接続用コマンド |
