# 機能設計書 140-Get-DbaProductKey

## 概要

本ドキュメントは、dbatools PowerShellモジュールの`Get-DbaProductKey`コマンドレットに関する機能設計書です。このコマンドレットは、レジストリデータからSQL Serverのプロダクトキーを取得し、ライセンスコンプライアンスとインベントリ管理を支援する機能を提供します。

### 本機能の処理概要

**業務上の目的・背景**：SQL Serverライセンスのコンプライアンス監査、資産インベントリの作成、マイグレーション計画時のライセンス情報収集は、多くの組織で重要な業務です。本機能は、対象コンピュータ上のすべてのSQL Serverインスタンスについて、レジストリに保存されているDigitalProductIDエントリからプロダクトキーをデコードします。SQL Server 2005以降をサポートし、クラスターインスタンスにも対応しています。

**機能の利用シーン**：
- ライセンスコンプライアンス監査・レポート作成時
- マイグレーション計画時のライセンス情報収集
- 資産インベントリ管理時
- SQL Server環境の包括的なドキュメント作成時

**主要な処理内容**：
1. Get-DbaRegistryRootでSQL Serverインスタンスのレジストリパスを取得
2. 各インスタンスにSQL接続してバージョンとエディション情報を取得
3. レジストリからDigitalProductIDバイナリデータを取得
4. バイナリデータをプロダクトキー形式（XXXXX-XXXXX-XXXXX-XXXXX-XXXXX）にデコード
5. Expressエディションの場合は「SQL Server Express Edition」を返却

**関連システム・外部連携**：
- Windowsレジストリ（DigitalProductIDエントリ）
- SQL Server接続（SMO経由でバージョン/エディション取得）
- Get-DbaRegistryRoot（レジストリルート検索）
- Invoke-Command2（リモート実行）

**権限による制御**：対象コンピュータへのWindows管理者権限が必要です。リモートレジストリへのアクセス権限も必要です。SQL Serverへの接続権限も必要です。

## 関連画面

本機能はコマンドラインツールであり、画面機能マッピングに該当する関連画面はありません。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | PowerShellコマンドラインで実行 |

## 機能種別

データ取得 / ライセンス監査

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ComputerName | DbaInstanceParameter[] | Yes | プロダクトキーを取得するSQL Serverインスタンスまたはコンピュータ名 | パイプライン入力可、Mandatory、エイリアス: SqlInstance |
| SqlCredential | PSCredential | No | SQL Server接続用の資格情報 | - |
| Credential | PSCredential | No | Windowsリモートアクセス用の資格情報 | - |
| EnableException | switch | No | 例外処理を有効化 | - |

### 入力データソース

- Get-DbaRegistryRoot: SQL Serverインスタンスのレジストリパス
- SQL Server接続: バージョン、エディション情報
- Windowsレジストリ: DigitalProductID（バイナリ形式）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | string | SQL Serverをホストするコンピュータ名 |
| InstanceName | string | SQL Serverインスタンス名 |
| SqlInstance | string | 完全なインスタンス名（computer\instance形式） |
| Version | string | SQL Serverバージョン名（例: "SQL Server 2019", "SQL Server 2016"） |
| Edition | string | SQL Serverエディション（Enterprise, Standard, Express, Developer等） |
| Key | string | デコードされたプロダクトキー（XXXXX-XXXXX-XXXXX-XXXXX-XXXXX形式）。Expressエディションの場合は"SQL Server Express Edition"、読み取り/デコード失敗時はエラーメッセージ |

### 出力先

PowerShellパイプライン（PSCustomObject）

## 処理フロー

### 処理シーケンス

```
1. beginブロック: スクリプトブロック定義
   ├─ Unlock-SqlInstanceKey関数定義（キーデコード）
   └─ レジストリアクセススクリプトブロック定義

2. processブロック: 各コンピュータに対して処理
   ├─ Get-DbaRegistryRootでレジストリパス取得
   │
   └─ 各インスタンスに対して
         ├─ Connect-DbaInstance（MinimumVersion 9=SQL 2005）
         ├─ バージョン/エディション取得
         │
         ├─ [Express以外] Invoke-Command2でスクリプトブロック実行
         │     ├─ バージョンに応じたレジストリパス決定
         │     ├─ DigitalProductID取得
         │     └─ Unlock-SqlInstanceKeyでデコード
         │
         └─ PSCustomObject出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{各ComputerNameに対して}
    B --> C[Get-DbaRegistryRoot]
    C --> D{インスタンス取得成功?}
    D -->|No| E[Stop-Function]
    E --> B
    D -->|Yes| F{各instanceRegに対して}
    F --> G[Connect-DbaInstance]
    G --> H{接続成功?}
    H -->|No| I[Stop-Function]
    I --> F
    H -->|Yes| J{Expressエディション?}
    J -->|Yes| K[Key = "SQL Server Express Edition"]
    J -->|No| L[Invoke-Command2でキー取得]
    L --> M{取得成功?}
    M -->|No| N[エラーメッセージ設定]
    M -->|Yes| O[Unlock-SqlInstanceKeyでデコード]
    K --> P[PSCustomObject出力]
    N --> P
    O --> P
    P --> F
    F -->|完了| B
    B -->|完了| Q[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | Expressエディション | プロダクトキー不要のため「SQL Server Express Edition」を返却 | edition -like "*Express*" |
| BR-002 | バージョン別レジストリパス | SQL 2005は ProductID配下、SQL 2008は Setup\DigitalProductID、SQL 2012以降は Setup + ClientSetup | versionMajor に応じて |
| BR-003 | 最小バージョン | SQL Server 2005（バージョン9）以降のみサポート | 常時 |
| BR-004 | N-key対応 | Windows 8以降のN-keyフォーマット（特殊な「N」挿入）に対応 | isNKey = true |

### 計算ロジック

キーデコードアルゴリズム（Unlock-SqlInstanceKey）：
1. SQL 2012以降: バイナリ配列の0-66バイト使用、それ以外: 52-66バイト使用
2. 24文字のアルファベット（BCDFGHJKMPQRTVWXY234679）でエンコード
3. N-keyフラグチェック（binArray[14] / 0x6 & 0x1）
4. 25回のループで逆変換
5. 5桁ごとにハイフン挿入（XXXXX-XXXXX-XXXXX-XXXXX-XXXXX）

バージョン別レジストリパス：
- SQL 2005 (9): `{InstancePath}\ProductID\DigitalProductID*`
- SQL 2008 (10): `{InstancePath}\Setup\DigitalProductID`
- SQL 2012+ (11+): `{InstancePath}\Setup\DigitalProductID` または `{InstancePath}\ClientSetup\DigitalProductID`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| バージョン取得 | - | SMO | VersionMajor, Edition プロパティ取得 |

本機能は直接的なデータベーステーブル操作を行いません。SMO経由でサーバープロパティのみ参照します。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | レジストリアクセスエラー | Remote Registryサービス停止 | Stop-Function（処理継続） |
| - | インスタンス未検出 | レジストリにインスタンス情報なし | Stop-Function（処理継続） |
| - | SQL接続エラー | SQL Serverへの接続失敗 | Stop-Function (ConnectionError)（処理継続） |
| - | キー読み取りエラー | DigitalProductID取得失敗 | エラーメッセージをKeyに設定 |
| - | デコードエラー | キーのデコード失敗 | "Cannot decode product key."を返却 |

### リトライ仕様

リトライ処理は実装されていません。

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

データベース操作がないため、トランザクション管理は不要です。

## パフォーマンス要件

- 各インスタンスに対してSQL接続1回、レジストリアクセス1回
- 通常数秒以内で完了

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

- 対象コンピュータへのWindows管理者権限が必要
- Remote Registryサービスの起動が必要
- プロダクトキーは機密情報のため取り扱い注意
- 出力の保存・共有時はセキュリティポリシーに従う

## 備考

- SQL Server Expressエディションはプロダクトキー不要
- クラスター環境では各ノードから情報取得可能
- 仮想化環境のライセンス確認にも使用可能

---

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

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

### 推奨読解順序

#### Step 1: キーデコード関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Get-DbaProductKey.ps1 | `public/Get-DbaProductKey.ps1` | 72-119行目: Unlock-SqlInstanceKey関数 |

**読解のコツ**:
- 85行目: エンコード文字セット（24文字）
- 87-89行目: N-keyフラグ判定
- 93-102行目: デコードアルゴリズム
- 104-112行目: N-key処理
- 114行目: ハイフン挿入

#### Step 2: レジストリアクセスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Get-DbaProductKey.ps1 | `public/Get-DbaProductKey.ps1` | 120-169行目: スクリプトブロック内のレジストリアクセス |

**主要処理フロー**:
1. **124-132行目**: バージョン別レジストリパス決定
2. **133-136行目**: Expressエディションチェック
3. **140-151行目**: レジストリからDigitalProductID取得
4. **153-161行目**: キーデコード呼び出し

#### Step 3: メイン処理フローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Get-DbaProductKey.ps1 | `public/Get-DbaProductKey.ps1` | 174-211行目: processブロック |

**主要処理フロー**:
- **175-179行目**: Get-DbaRegistryRootでインスタンス情報取得
- **186-191行目**: Connect-DbaInstance（MinimumVersion 9）
- **196-199行目**: Invoke-Command2でスクリプトブロック実行
- **202-209行目**: PSCustomObject出力

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

```
Get-DbaProductKey
    │
    ├─ begin ブロック
    │      └─ スクリプトブロック定義
    │            └─ Unlock-SqlInstanceKey関数
    │
    └─ process ブロック
           │
           └─ foreach ($computer in $ComputerName)
                  │
                  ├─ Get-DbaRegistryRoot
                  │      └─ [失敗時] Stop-Function
                  │
                  └─ foreach ($instanceReg in $registryroot)
                         │
                         ├─ Connect-DbaInstance -MinimumVersion 9
                         │      └─ [失敗時] Stop-Function
                         │
                         ├─ Invoke-Command2 (スクリプトブロック)
                         │      │
                         │      ├─ バージョン判定
                         │      │     ├─ [9] ProductID配下検索
                         │      │     ├─ [10] Setup\DigitalProductID
                         │      │     └─ [11+] Setup + ClientSetup
                         │      │
                         │      ├─ [Express] "SQL Server Express Edition"
                         │      │
                         │      └─ [その他] レジストリ取得 + デコード
                         │            └─ Unlock-SqlInstanceKey
                         │
                         └─ PSCustomObject出力
```

### データフロー図

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

ComputerName ───────▶ Get-DbaRegistryRoot ──▶ インスタンス情報
                            │
                            ▼
                     Connect-DbaInstance ──▶ バージョン/エディション
                            │
                            ▼
                     [Express?] ──▶ "SQL Server Express Edition"
                            │
                     [その他]
                            │
                            ▼
                     レジストリアクセス
                            │
              DigitalProductID (バイナリ)
                            │
                            ▼
                     Unlock-SqlInstanceKey
                            │
                     プロダクトキー文字列
                            │
                            ▼
                     PSCustomObject ───────▶ パイプライン出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Get-DbaProductKey.ps1 | `public/Get-DbaProductKey.ps1` | ソース | メイン処理 |
| Get-DbaRegistryRoot.ps1 | `private/functions/Get-DbaRegistryRoot.ps1` | ソース | レジストリルート取得 |
| Connect-DbaInstance.ps1 | `public/Connect-DbaInstance.ps1` | ソース | SQL Server接続 |
| Invoke-Command2.ps1 | `private/functions/Invoke-Command2.ps1` | ソース | リモート実行 |
| Stop-Function.ps1 | `private/functions/flowcontrol/Stop-Function.ps1` | ソース | エラー処理 |
