# 機能設計書 630-Find-DbaOrphanedFile

## 概要

本ドキュメントは、dbatools PowerShellモジュールの`Find-DbaOrphanedFile`コマンドレットに関する機能設計書である。このコマンドレットは、ディスク上に存在するがSQL Serverデータベースにアタッチされていない孤立したデータベースファイルを検出する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：データベースの削除、デタッチ、失敗したリストア操作などにより、ディスク上に不要なデータベースファイル（.mdf、.ldf、.ndf）が残ることがある。これらの孤立ファイルはディスク容量を消費し続けるため、定期的なクリーンアップが必要である。この機能により、DBAは孤立ファイルを効率的に特定し、ストレージの最適化を行える。

**機能の利用シーン**：
- 定期的なストレージクリーンアップ
- データベース削除後の残留ファイル確認
- ディスク容量不足時の原因調査
- 環境監査とコンプライアンス確認

**主要な処理内容**：
1. 対象SQL Serverインスタンスへの接続確立
2. sys.master_files（SQL 2005+）またはsysaltfiles（SQL 2000）からアタッチ済みファイル一覧取得
3. xp_dirtreeを使用してファイルシステム上のファイル一覧取得
4. デフォルトデータ/ログパス、既存データベースのパスを検索対象に追加
5. ファイルシステム上のファイルとアタッチ済みファイルを比較
6. 孤立ファイル（差分）をリストアップ
7. ローカルパスまたはUNCパスで結果出力

**関連システム・外部連携**：
- SQL Server Management Objects (SMO)
- xp_dirtree拡張ストアドプロシージャ
- ファイルシステム

**権限による制御**：sysadmin権限が必要。SQL Server 2000以上が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLIコマンド | 主画面 | PowerShellコンソールからの実行 |

## 機能種別

監査 / クリーンアップ支援

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| SqlInstance | DbaInstanceParameter[] | Yes | 対象SQL Serverインスタンス | ValueFromPipeline |
| SqlCredential | PSCredential | No | SQL Server接続用資格情報 | - |
| Path | string[] | No | 追加の検索パス | - |
| FileType | string[] | No | 追加のファイル拡張子（デフォルト: mdf, ldf, ndf） | - |
| LocalOnly | switch | No | ローカルパスのみ出力 | LocalOnlyパラメータセット |
| RemoteOnly | switch | No | UNCパスのみ出力 | RemoteOnlyパラメータセット |
| Recurse | switch | No | サブディレクトリも検索 | - |
| EnableException | switch | No | 例外処理モード切替 | - |

### 入力データソース

- PowerShellコマンドラインからのパラメータ入力

## 出力仕様

### 出力データ（デフォルト）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | string | コンピュータ名 |
| InstanceName | string | インスタンス名 |
| SqlInstance | string | 完全インスタンス名 |
| Server | string | サーバー名 |
| Filename | string | ローカルファイルパス |
| RemoteFilename | string | UNCファイルパス |

### 出力データ（LocalOnly）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Filename | string | ローカルファイルパスのみ |

### 出力データ（RemoteOnly）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| RemoteFilename | string | UNCファイルパスのみ |

### 出力先

PowerShellパイプライン（PSCustomObject or string）

## 処理フロー

### 処理シーケンス

```
1. begin ブロック
   └─ 1.1 ヘルパー関数定義（Get-SQLDirTreeQuery, Get-SqlFileStructure, Format-Path）
   └─ 1.2 システムファイル除外リスト定義
   └─ 1.3 ファイルタイプにデフォルト拡張子追加
2. process ブロック（各インスタンスごと）
   └─ 2.1 Connect-DbaInstanceで接続
   └─ 2.2 Get-SqlFileStructureでアタッチ済みファイル取得
   └─ 2.3 SQLパス一覧構築（既存ファイルの親ディレクトリ、デフォルトパス）
   └─ 2.4 Get-SQLDirTreeQueryでクエリ構築
   └─ 2.5 xp_dirtree実行でファイルシステムファイル取得
   └─ 2.6 アタッチ済みファイルと比較
   └─ 2.7 孤立ファイルを出力
3. end ブロック
   └─ 孤立ファイルなしの場合はメッセージ出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ヘルパー関数定義]
    B --> C[foreach instance]
    C --> D[Connect-DbaInstance]
    D --> E{接続成功?}
    E -->|No| F[Stop-Function]
    F --> C
    E -->|Yes| G[Get-SqlFileStructure]
    G --> H[アタッチ済みファイル取得]
    H --> I[SQLパス一覧構築]
    I --> J[Get-SQLDirTreeQuery]
    J --> K[xp_dirtree実行]
    K --> L[ファイルシステムファイル取得]
    L --> M[アタッチ済みファイルと比較]
    M --> N[foreach 孤立ファイル]
    N --> O{システムファイル?}
    O -->|Yes| N
    O -->|No| P{LocalOnly?}
    P -->|Yes| Q[Filename出力]
    P -->|No| R{RemoteOnly?}
    R -->|Yes| S[RemoteFilename出力]
    R -->|No| T[PSCustomObject出力]
    Q --> N
    S --> N
    T --> N
    N --> C
    C --> U[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | デフォルト拡張子 | mdf, ldf, ndfがデフォルトで検索対象 | 常時 |
| BR-002 | システムファイル除外 | distmdl, mssqlsystemresource等は除外 | 常時 |
| BR-003 | パス自動検出 | デフォルトパス、既存DBのパスを自動検索 | 常時 |
| BR-004 | xp_dirtree使用 | リモートサーバーのファイル列挙にxp_dirtreeを使用 | 常時 |
| BR-005 | バージョン対応 | SQL 2000はsysaltfiles、SQL 2005+はsys.master_filesを使用 | バージョンによる |
| BR-006 | CTEサポート | SQL 2005+ではCTEを使用したパス構築、SQL 2000では単純クエリ | バージョンによる |

### 計算ロジック

- UNCパス変換: Join-AdminUnc関数でローカルパスをUNC形式に変換
- パス正規化: Format-Path関数で特殊文字を除去

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ファイル一覧取得 | sys.master_files/sysaltfiles | SELECT | アタッチ済みファイル取得 |
| ディレクトリ列挙 | xp_dirtree | EXEC | ファイルシステム列挙 |

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

#### sys.master_files（SQL 2005+）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | physical_name | 全ファイルパス | アタッチ済み判定用 |

#### sysaltfiles（SQL 2000）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | filename | 全ファイルパス | アタッチ済み判定用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Stop-Function | 接続失敗 | 接続情報、権限を確認 |
| - | Warning | サービスレベル情報取得失敗 | ComputerManagement WMI確認 |

### リトライ仕様

リトライ機能なし

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

読み取り専用操作のため、トランザクション管理は不要。

## パフォーマンス要件

- xp_dirtreeの実行時間はファイル数に依存
- Recurseオプション使用時はサブディレクトリ全体を検索するため時間増加
- 大量のディレクトリがある環境では注意

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

- sysadmin権限が必要
- xp_dirtree実行権限が必要
- 検出結果には機密情報を含む可能性があるファイルパスが含まれる

## 備考

- SQL Server 2000以上が必要
- Paul Randalのブログ記事に基づくFILESTREAM対応
- Full-Text Catalogs（SQL 2005以下）にも対応
- Linux/macOS環境ではパス処理が異なる

---

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

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

### 推奨読解順序

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

出力オブジェクトとxp_dirtree結果の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Find-DbaOrphanedFile.ps1 | `public/Find-DbaOrphanedFile.ps1` | .OUTPUTS セクション - 3種類の出力形式 |

**読解のコツ**: 出力形式はLocalOnly/RemoteOnly/デフォルトの3パターン。デフォルトではPSCustomObjectで両方のパスを含む。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Find-DbaOrphanedFile.ps1 | `public/Find-DbaOrphanedFile.ps1` | ヘルパー関数とbeginブロック |

**主要処理フロー**:
1. **114-126行目**: パラメータ定義（ParameterSetName: LocalOnly/RemoteOnly）
2. **128-325行目**: beginブロック - ヘルパー関数定義
3. **327-427行目**: processブロック - メイン処理

#### Step 3: 各処理層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Find-DbaOrphanedFile.ps1 | `public/Find-DbaOrphanedFile.ps1` | ヘルパー関数の詳細 |

**主要処理フロー**:
- **129-276行目**: Get-SQLDirTreeQuery関数（xp_dirtreeクエリ構築）
- **278-310行目**: Get-SqlFileStructure関数（アタッチ済みファイル取得）
- **312-319行目**: Format-Path関数（パス正規化）
- **321-324行目**: システムファイル除外リスト
- **342-343行目**: Get-SqlFileStructure呼び出し
- **362行目**: Get-SQLDirTreeQuery呼び出し
- **363-368行目**: xp_dirtree実行
- **391-424行目**: 孤立ファイル判定と出力

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

```
Find-DbaOrphanedFile
    │
    ├─ [begin] ヘルパー関数定義
    │      ├─ Get-SQLDirTreeQuery (クエリ構築)
    │      ├─ Get-SqlFileStructure (アタッチ済みファイル)
    │      └─ Format-Path (パス正規化)
    │
    ├─ Connect-DbaInstance (SQL接続)
    │
    ├─ Get-SqlFileStructure
    │      └─ sys.master_files / sysaltfiles
    │
    ├─ Get-SqlDefaultPaths (デフォルトパス)
    │
    ├─ Get-SQLDirTreeQuery
    │      └─ xp_dirtree用クエリ構築
    │
    ├─ ExecuteWithResults (xp_dirtree実行)
    │
    ├─ 比較ロジック
    │      └─ アタッチ済み vs ファイルシステム
    │
    └─ Join-AdminUnc (UNCパス変換)
```

### データフロー図

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

SqlInstance ────────────────▶ Connect-DbaInstance
                                   │
                                   ▼
                            Get-SqlFileStructure
                            (sys.master_files)
                                   │
                                   ▼
                            アタッチ済みファイル一覧
                                   │
Path (追加パス) ───────────────────▶
                                   │
                                   ▼
                            Get-SQLDirTreeQuery
                            (xp_dirtree)
                                   │
                                   ▼
                            ファイルシステム一覧
                                   │
                                   ▼
                            比較 ─────────────────▶ 孤立ファイル
                            (差分抽出)             (ローカル/UNC)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Find-DbaOrphanedFile.ps1 | `public/Find-DbaOrphanedFile.ps1` | ソース | メインコマンドレット |
| Get-SqlDefaultPaths.ps1 | `internal/functions/Get-SqlDefaultPaths.ps1` | ソース | デフォルトパス取得 |
| Join-AdminUnc.ps1 | `internal/functions/Join-AdminUnc.ps1` | ソース | UNCパス変換 |
