この記事の対象読者
- HDD/SSDの健康状態を確認したいが、方法がわからない方
- CrystalDiskInfoをインストールしたものの、見方がわからない方
- S.M.A.R.T.情報の経時変化をログで追いたいエンジニア・システム管理者
- PCの故障を事前に予測して、データ損失を防ぎたい方
この記事で得られること
- CrystalDiskInfoの正体: 何ができるツールなのか、技術的背景を理解
- 画面の見方: 健康状態、温度、S.M.A.R.T.属性の読み解き方
- ログの確認方法: Smartフォルダの構造、グラフ機能、イベントログの活用
- 実践的な監視設定: 常駐、アラート、メール通知の設定方法
- トラブルシューティング: よくある問題と対処法
この記事で扱わないこと
- S.M.A.R.T.の内部仕様(ATA/NVMe規格の詳細)
- データ復旧の方法
- 他のディスク診断ツール(smartmontools等)との比較
1. CrystalDiskInfoとの出会い
「HDDが壊れて、大事なデータが全部消えた...」
エンジニアなら一度は聞いたことがある、あるいは自ら経験したことがあるかもしれない悲劇だ。私も例外ではない。数年前、前触れもなく外付けHDDが認識しなくなり、数年分の写真が消失した。
「なんで事前に気づけなかったんだろう?」
その答えが CrystalDiskInfo だった。
CrystalDiskInfoは、例えるなら 「ストレージの健康診断ツール」 だ。人間ドックで血液検査や心電図を見るように、HDD/SSDの内部状態を数値化して「正常」「注意」「異常」と教えてくれる。しかも無料で、日本製で、日本語対応だ。
実は、すべてのHDD/SSDには S.M.A.R.T.(Self-Monitoring, Analysis and Reporting Technology) という自己診断機能が搭載されている。ストレージは自分の健康状態を常に記録しているのだ。CrystalDiskInfoは、この「カルテ」を人間が読める形で表示してくれる。
ここまでで、CrystalDiskInfoがどんなものか、なんとなくイメージできただろうか。次は、この記事で使う用語を整理しておこう。
2. 前提知識の確認
本題に入る前に、この記事で登場する用語を確認する。
2.1 S.M.A.R.T.とは
S.M.A.R.T.(スマート)は、HDD/SSDに搭載された自己診断機能だ。ストレージが自ら以下のような情報を記録する。
| 記録される情報 | 説明 |
|---|---|
| 読み取りエラー率 | データ読み取り時のエラー発生頻度 |
| 代替処理済セクタ数 | 不良セクタを予備領域で代替した回数 |
| 電源投入回数 | 起動された回数 |
| 使用時間 | 累計稼働時間(通電時間) |
| 温度 | 現在の動作温度 |
2.2 属性値の読み方
S.M.A.R.T.情報には、各項目に対して以下の値が存在する。
| 値の種類 | 説明 |
|---|---|
| 現在値(Current) | 今の状態を示す正規化された値(通常100が最良、低いほど悪い) |
| 最悪値(Worst) | 過去に記録された最も悪い値 |
| しきい値(Threshold) | メーカーが定めた「故障」と判断する境界値 |
| 生の値(Raw Value) | 実際の測定データ(16進数で表示されることが多い) |
重要: 現在値がしきい値を下回ると「異常」と判定される。
2.3 健康状態の4段階
CrystalDiskInfoは、S.M.A.R.T.情報を総合して以下の4段階で判定する。
| 状態 | 色 | 意味 |
|---|---|---|
| 正常 | 青/緑 | 問題なし |
| 注意 | 黄 | 劣化の兆候あり(早めのバックアップ推奨) |
| 異常 | 赤 | 深刻な問題あり(即時バックアップ・交換推奨) |
| 不明 | 灰 | S.M.A.R.T.情報を取得できない |
2.4 Pre-fail属性とOld-age属性
S.M.A.R.T.属性には2種類のタイプがある。
| タイプ | 説明 |
|---|---|
| Pre-fail(故障予兆) | しきい値を下回ると故障が近いことを示す重要な属性 |
| Old-age(経年劣化) | 使用に伴う自然な劣化を示す属性 |
これらの用語が押さえられたら、CrystalDiskInfoの背景を見ていこう。
3. CrystalDiskInfoが生まれた背景
3.1 開発者と歴史
CrystalDiskInfoは、日本の開発者 hiyohiyo氏 によって開発されたオープンソースソフトウェアだ。MITライセンス で公開されており、誰でも無料で利用できる。
最初のバージョンは2008年頃にリリースされ、以来継続的にアップデートが行われている。2025年現在、バージョン9.7.xがリリースされており、NVMe SSDやUSB接続ドライブ、Intel/AMD RAIDにも対応している。
3.2 なぜCrystalDiskInfoが必要か
S.M.A.R.T.情報は、Windowsの標準機能では確認しづらい。コマンドプロンプトで wmic diskdrive get status を実行しても、「OK」か「Pred Fail」しか表示されない。詳細な属性値を見るには、専用ツールが必要だ。
CrystalDiskInfoの強みは以下の通り。
| 強み | 説明 |
|---|---|
| 日本語対応 | 属性名から設定まで完全日本語化 |
| USB対応 | 一部の外付けHDD/SSDでもS.M.A.R.T.を取得可能 |
| NVMe対応 | 最新のNVMe SSDにも対応(Windows 10以降) |
| グラフ機能 | S.M.A.R.T.値の経時変化を可視化 |
| 常駐監視 | バックグラウンドで監視し、異常時にアラート |
| ポータブル版 | インストール不要で持ち運び可能 |
3.3 公式サイトと信頼性
公式サイトは Crystal Dew World だ。同作者の CrystalDiskMark(ディスクベンチマークツール)も有名で、IT業界では定番のツールとなっている。
背景がわかったところで、基本的な仕組みを見ていこう。
4. 基本概念と仕組み
4.1 画面構成
CrystalDiskInfoを起動すると、以下のような画面が表示される。
┌─────────────────────────────────────────────────────────────┐
│ [メニューバー] ファイル 編集 機能 ディスク ヘルプ │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────┐ ファームウェア: XXXXX シリアル: YYYYY │
│ │ 健康状態 │ インターフェース: NVMe 転送モード: PCIe 4.0 │
│ │ 正常 │ 対応規格: NVMe 1.4 │
│ │ │ 対応機能: S.M.A.R.T., TRIM, VolatileWriteCache │
│ │ 37°C │ 総読込量: XXX GB 総書込量: YYY GB │
│ └─────────┘ 電源投入回数: ZZZ回 使用時間: AAAA時間 │
├─────────────────────────────────────────────────────────────┤
│ [S.M.A.R.T.情報一覧] │
│ ID 属性名 現在値 最悪値 しきい値 生の値 │
│ ─────────────────────────────────────────────────────────── │
│ 01 リードエラーレート 100 100 50 00000000 │
│ 05 代替処理済セクタ数 100 100 5 00000000 │
│ 09 使用時間 099 099 0 00001234 │
│ 0C 電源投入回数 100 100 0 00000567 │
│ C2 温度 063 055 0 00000025 │
│ ... │
└─────────────────────────────────────────────────────────────┘
4.2 特に注目すべきS.M.A.R.T.属性(HDD)
HDDで故障を予測する上で重要な属性は以下の5つだ(Backblaze社の研究より)。
| ID | 属性名 | 説明 | 危険サイン |
|---|---|---|---|
| 05 | 代替処理済セクタ数 | 不良セクタを予備領域で代替した数 | 生の値が1以上 |
| BB | 報告済み訂正不能エラー | 訂正できなかったエラーの数 | 生の値が1以上 |
| BC | コマンドタイムアウト | タイムアウトしたコマンドの数 | 生の値が増加傾向 |
| C5 | 代替処理保留中セクタ数 | 代替処理を待っている不良セクタ数 | 生の値が1以上 |
| C6 | 回復不能セクタ数 | 回復できなかったセクタ数 | 生の値が1以上 |
4.3 特に注目すべきS.M.A.R.T.属性(SSD)
SSDでは、以下の属性が重要だ。
| ID | 属性名 | 説明 | 危険サイン |
|---|---|---|---|
| 05 | 代替処理済セクタ数 | 不良ブロックを代替した数 | 急激な増加 |
| B1/AD | 残り寿命 | SSDの残り寿命(%) | 10%以下 |
| F1 | 総書き込み量(ホスト) | 書き込まれた総データ量 | TBW上限に近い |
| E9 | メディア消耗指標 | NANDの消耗度 | しきい値に近い |
4.4 NVMe SSDの場合
NVMe SSDは従来のS.M.A.R.T.とは異なる形式で情報を提供する。CrystalDiskInfoでは以下の項目が表示される。
| 項目 | 説明 |
|---|---|
| Critical Warning | 重大な警告フラグ |
| Temperature | 温度(複数センサー) |
| Available Spare | 予備領域の残り(%) |
| Percentage Used | 消耗度(100%以上になることもある) |
| Data Units Read/Written | 読み書きしたデータ量 |
| Power On Hours | 稼働時間 |
| Unsafe Shutdowns | 不正なシャットダウン回数 |
基本概念が理解できたところで、実際にインストールして使ってみよう。
5. 実践:CrystalDiskInfoの使い方
5.1 ダウンロードとインストール
CrystalDiskInfoには複数のエディションがある。
| エディション | 特徴 |
|---|---|
| Standard Edition | 通常版 |
| Shizuku Edition | キャラクター「水晶雫」版 |
| Kurei Kei Edition | カスタマイズ版 |
| Aoi Edition | キャラクター「蒼」版 |
機能は同じなので、好みで選んで良い。
ダウンロード手順:
- 公式サイト https://crystalmark.info/ にアクセス
- 「CrystalDiskInfo」をクリック
- 「Download」から以下を選択:
- ZIP版: インストール不要(ポータブル)
- インストーラー版: レジストリに設定を保存
5.2 環境別の設定ファイル
開発環境用(DiskInfo.ini - 開発者向け)
; DiskInfo.ini - 開発環境用
; 頻繁にチェック、詳細ログを有効化
[Setting]
Language=Japanese
AutoRefresh=1
RefreshInterval=10 ; 10分間隔でS.M.A.R.T.を更新
StartupWaitTime=30 ; 起動時30秒待機
AutoDetection=1 ; 新規ディスク自動検出
EventLog=1 ; Windowsイベントログに記録
AlertSound=1 ; 警報音有効
ResidentMinimize=0 ; 常駐時は非表示
; 温度しきい値(開発環境は低めに設定)
[Temperature]
HDD=45 ; HDD警告温度
SSD=55 ; SSD警告温度
; 健康状態判定(厳格)
[HealthStatus]
05=1 ; 代替処理済セクタ 1以上で注意
C5=1 ; 代替処理保留中セクタ 1以上で注意
C6=1 ; 回復不能セクタ 1以上で注意
本番環境用(DiskInfo.ini - サーバー向け)
; DiskInfo.ini - 本番サーバー向け
; メール通知重視、負荷を抑えた設定
[Setting]
Language=Japanese
AutoRefresh=1
RefreshInterval=60 ; 60分間隔(サーバー負荷軽減)
StartupWaitTime=120 ; 起動時120秒待機(RAIDコントローラ対応)
AutoDetection=0 ; 自動検出無効(予期せぬ負荷防止)
EventLog=1 ; イベントログ有効
AlertSound=0 ; サーバーなので音無効
AlertMail=1 ; メール通知有効
ResidentMinimize=1 ; 最小化で常駐
; 温度しきい値(データセンター想定)
[Temperature]
HDD=50
SSD=65
NVMe=70
; メール設定
[AlertMail]
Host=smtp.example.com
Port=587
SSL=STARTTLS
User=alert@example.com
To=admin@example.com
Subject=[CrystalDiskInfo] ストレージ異常検知
テスト環境用(DiskInfo.ini - 検証用)
; DiskInfo.ini - テスト環境用
; 最小限の設定、ログ無効
[Setting]
Language=Japanese
AutoRefresh=0 ; 自動更新無効(手動でチェック)
StartupWaitTime=0 ; 待機時間なし
AutoDetection=0 ; 自動検出無効
EventLog=0 ; イベントログ無効
AlertSound=0 ; 警報音無効
; 温度しきい値(緩め)
[Temperature]
HDD=55
SSD=70
5.3 ログファイルの場所と構造
CrystalDiskInfoのログは、インストールフォルダ(またはZIP展開フォルダ)内の Smart フォルダ に保存される。
CrystalDiskInfo/
├── DiskInfo32.exe
├── DiskInfo64.exe
├── DiskInfo.ini ← 設定ファイル
├── DiskInfo.txt ← /CopyExit オプションで出力されるテキスト
└── Smart/ ← S.M.A.R.T.ログフォルダ
├── [ディスク名+シリアル番号]/
│ └── Smart.ini ← S.M.A.R.T.履歴データ
├── [ディスク名+シリアル番号]/
│ └── Smart.ini
└── ...
Smart.iniの構造
各ディスクの Smart.ini には、以下の3つのセクションが含まれる。
; Smart.ini の構造例
[SAMSUNG_SSD_980_PRO_1TB_S5XXXXXXXXFIRST]
; 初回記録時のS.M.A.R.T.値
Date=2024/01/15 10:30:00
01=100,100,0,0000000000000000
05=100,100,10,0000000000000000
09=100,100,0,0000000000001234
; ...
[SAMSUNG_SSD_980_PRO_1TB_S5XXXXXXXX]
; 最新のS.M.A.R.T.値(グラフ用履歴データ)
Date=2025/02/01 09:00:00
01=100,100,0,0000000000000000
05=100,100,10,0000000000000000
09=098,098,0,0000000000005678
; ...
Date=2025/01/31 09:00:00
01=100,100,0,0000000000000000
; ...(過去の記録が続く)
[SAMSUNG_SSD_980_PRO_1TB_S5XXXXXXXXTHRESHOLD]
; しきい値(メーカー定義)
01=50
05=10
09=0
; ...
重要: グラフ機能は、このSmart.iniに蓄積されたデータを可視化している。CrystalDiskInfoが起動していない間はデータが記録されないため、継続的な監視には常駐機能を使う必要がある。
5.4 よくあるエラーと対処法
| 症状 | 原因 | 対処法 |
|---|---|---|
| 外付けHDDが認識しない | USB-SATAブリッジがS.M.A.R.T.を通さない | 機能→上級者向け機能→ATA_PASS_THROUGH を試す |
| NVMe SSDが表示されない | Windows 7/8ではNVMe非対応 | Windows 10以降にアップグレード |
| 健康状態が「不明」 | RAIDコントローラ経由 | Intel RAID/AMD RAIDXpert2対応を有効化 |
| グラフが表示されない | Smart.iniがない | CrystalDiskInfoを常駐させてデータを蓄積 |
| 温度が異常に高い | センサー値の誤読 | 別の温度監視ツールと比較(±3℃の誤差あり) |
| 「注意」だがPCは正常動作 | デフォルト判定が厳格 | 機能→健康状態設定で基準値を調整 |
5.5 グラフ機能の使い方
グラフ機能は、S.M.A.R.T.値の経時変化を可視化する強力な機能だ。
表示方法:
- メニュー → 機能 → グラフ
- 左上でディスクを選択
- 表示したい属性をチェック
グラフで確認できる項目:
- 温度の推移
- 代替処理済セクタ数の増加傾向
- 使用時間の累積
- 総書き込み量の推移(SSD)
#!/usr/bin/env python3
"""
CrystalDiskInfo Smart.iniパーサー
ログファイルを解析してCSVに変換する
使い方: python parse_smart_log.py /path/to/Smart.ini
"""
import re
import csv
import sys
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Optional
from dataclasses import dataclass
@dataclass
class SmartRecord:
"""S.M.A.R.T.レコード"""
timestamp: datetime
attributes: Dict[str, tuple] # {ID: (current, worst, threshold, raw)}
def parse_smart_ini(filepath: Path) -> List[SmartRecord]:
"""
Smart.iniファイルをパースしてレコードリストを返す
Args:
filepath: Smart.iniのパス
Returns:
SmartRecordのリスト
"""
records = []
current_record = None
with open(filepath, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
# セクションヘッダーをスキップ(FIRSTやTHRESHOLDは除外)
if line.startswith('[') and line.endswith(']'):
section = line[1:-1]
if 'FIRST' in section or 'THRESHOLD' in section:
current_record = None
continue
# 日付行
if line.startswith('Date='):
if current_record:
records.append(current_record)
date_str = line.split('=')[1]
try:
timestamp = datetime.strptime(date_str, '%Y/%m/%d %H:%M:%S')
current_record = SmartRecord(
timestamp=timestamp,
attributes={}
)
except ValueError:
current_record = None
continue
# 属性行(例: 05=100,100,10,0000000000000000)
if current_record and '=' in line:
match = re.match(r'^([0-9A-Fa-f]{2})=(\d+),(\d+),(\d+),([0-9A-Fa-f]+)$', line)
if match:
attr_id = match.group(1).upper()
current = int(match.group(2))
worst = int(match.group(3))
threshold = int(match.group(4))
raw = match.group(5)
current_record.attributes[attr_id] = (current, worst, threshold, raw)
if current_record:
records.append(current_record)
return records
def export_to_csv(records: List[SmartRecord], output_path: Path,
attr_ids: Optional[List[str]] = None):
"""
レコードをCSVに出力
Args:
records: SmartRecordのリスト
output_path: 出力CSVパス
attr_ids: 出力する属性ID(Noneならすべて)
"""
if not records:
print("レコードがありません")
return
# すべての属性IDを収集
all_attrs = set()
for record in records:
all_attrs.update(record.attributes.keys())
if attr_ids:
all_attrs = all_attrs.intersection(set(attr_ids))
all_attrs = sorted(all_attrs)
# CSVヘッダー
headers = ['Timestamp']
for attr in all_attrs:
headers.extend([f'{attr}_Current', f'{attr}_Raw'])
with open(output_path, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(headers)
for record in sorted(records, key=lambda x: x.timestamp):
row = [record.timestamp.isoformat()]
for attr in all_attrs:
if attr in record.attributes:
current, _, _, raw = record.attributes[attr]
row.extend([current, int(raw, 16)])
else:
row.extend(['', ''])
writer.writerow(row)
print(f"CSVを出力しました: {output_path}")
print(f"レコード数: {len(records)}")
print(f"属性数: {len(all_attrs)}")
def main():
if len(sys.argv) < 2:
print("使い方: python parse_smart_log.py /path/to/Smart.ini [output.csv]")
print("\n例:")
print(" python parse_smart_log.py ./Smart/SAMSUNG_SSD_980_PRO_1TB_XXXXX/Smart.ini")
sys.exit(1)
input_path = Path(sys.argv[1])
output_path = Path(sys.argv[2]) if len(sys.argv) > 2 else input_path.with_suffix('.csv')
if not input_path.exists():
print(f"ファイルが見つかりません: {input_path}")
sys.exit(1)
print(f"パース中: {input_path}")
records = parse_smart_ini(input_path)
# 重要な属性のみ出力
important_attrs = ['05', '09', '0C', 'C2', 'C5', 'C6', 'F1', 'B1']
export_to_csv(records, output_path, important_attrs)
if __name__ == "__main__":
main()
5.6 イベントログの確認方法
CrystalDiskInfoは、Windowsイベントログに異常を記録できる。
有効化方法:
- メニュー → 機能 → 警報機能 → イベントログ
イベントビューアーでの確認:
-
Win + R→eventvwr.msc - Windows ログ → Application
- ソース「CrystalDiskInfo」でフィルタ
記録されるイベントID:
| イベントID | レベル | 説明 |
|---|---|---|
| 601 | 警告 | 健康状態の悪化 |
| 602 | 警告 | 代替処理済セクタ数の増加 |
| 603 | 警告 | 再配置イベント数の増加 |
| 604 | 警告 | 代替処理保留中セクタ数の増加 |
| 605 | 警告 | 回復不能セクタ数の増加 |
| 606 | 警告 | 温度しきい値超過 |
5.7 環境診断スクリプト
#!/usr/bin/env python3
"""
CrystalDiskInfo環境診断スクリプト
インストール状態とログを確認する
実行方法: python check_cdi_env.py
"""
import os
import sys
from pathlib import Path
from datetime import datetime
def find_crystaldiskinfo() -> list:
"""CrystalDiskInfoのインストール場所を探す"""
possible_paths = [
# インストーラー版
Path(os.environ.get('PROGRAMFILES', '')) / 'CrystalDiskInfo',
Path(os.environ.get('PROGRAMFILES(X86)', '')) / 'CrystalDiskInfo',
# ポータブル版(よくある場所)
Path.home() / 'Downloads' / 'CrystalDiskInfo',
Path.home() / 'Desktop' / 'CrystalDiskInfo',
Path('C:/Tools/CrystalDiskInfo'),
]
found = []
for path in possible_paths:
if path.exists():
# DiskInfo*.exe が存在するか確認
exes = list(path.glob('DiskInfo*.exe'))
if exes:
found.append(path)
return found
def analyze_smart_logs(cdi_path: Path) -> dict:
"""Smartフォルダ内のログを分析"""
smart_path = cdi_path / 'Smart'
result = {
'smart_folder_exists': smart_path.exists(),
'drives': [],
'total_records': 0,
'oldest_record': None,
'newest_record': None
}
if not smart_path.exists():
return result
for drive_folder in smart_path.iterdir():
if drive_folder.is_dir():
smart_ini = drive_folder / 'Smart.ini'
if smart_ini.exists():
# ファイルサイズとレコード数を概算
size = smart_ini.stat().st_size
with open(smart_ini, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
date_count = content.count('Date=')
result['drives'].append({
'name': drive_folder.name,
'size_kb': size / 1024,
'record_count': date_count
})
result['total_records'] += date_count
return result
def check_diskinfo_ini(cdi_path: Path) -> dict:
"""DiskInfo.iniの設定を確認"""
ini_path = cdi_path / 'DiskInfo.ini'
result = {
'exists': ini_path.exists(),
'settings': {}
}
if not ini_path.exists():
return result
current_section = None
with open(ini_path, 'r', encoding='utf-8', errors='ignore') as f:
for line in f:
line = line.strip()
if line.startswith('[') and line.endswith(']'):
current_section = line[1:-1]
elif '=' in line and current_section:
key, value = line.split('=', 1)
result['settings'][f'{current_section}.{key}'] = value
return result
def main():
print("=" * 60)
print("CrystalDiskInfo 環境診断ツール")
print("=" * 60)
print()
# CrystalDiskInfoを探す
print("【インストール場所の検索】")
found_paths = find_crystaldiskinfo()
if not found_paths:
print(" CrystalDiskInfoが見つかりませんでした")
print(" 公式サイトからダウンロードしてください:")
print(" https://crystalmark.info/")
return
for path in found_paths:
print(f" 発見: {path}")
print()
# 各インストールを分析
for cdi_path in found_paths:
print(f"【{cdi_path}】")
# バージョン確認(ファイル名から推測)
exes = list(cdi_path.glob('DiskInfo*.exe'))
print(f" 実行ファイル: {[e.name for e in exes]}")
# 設定ファイル
ini_result = check_diskinfo_ini(cdi_path)
if ini_result['exists']:
print(f" 設定ファイル: あり")
if 'Setting.Language' in ini_result['settings']:
print(f" 言語: {ini_result['settings']['Setting.Language']}")
if 'Setting.AutoRefresh' in ini_result['settings']:
auto = "有効" if ini_result['settings']['Setting.AutoRefresh'] == '1' else "無効"
print(f" 自動更新: {auto}")
if 'Setting.EventLog' in ini_result['settings']:
evlog = "有効" if ini_result['settings']['Setting.EventLog'] == '1' else "無効"
print(f" イベントログ: {evlog}")
else:
print(f" 設定ファイル: なし(デフォルト設定で動作)")
# Smartログ
smart_result = analyze_smart_logs(cdi_path)
if smart_result['smart_folder_exists']:
print(f" Smartログフォルダ: あり")
print(f" 検出ドライブ数: {len(smart_result['drives'])}")
print(f" 総レコード数: {smart_result['total_records']}")
for drive in smart_result['drives']:
print(f" - {drive['name']}: {drive['record_count']}レコード ({drive['size_kb']:.1f}KB)")
else:
print(f" Smartログフォルダ: なし(まだログが蓄積されていません)")
print()
print("=" * 60)
print("【推奨アクション】")
if found_paths:
# 設定の推奨
print(" 1. 常駐機能を有効にしてログを蓄積する")
print(" メニュー → 機能 → 常駐")
print()
print(" 2. イベントログを有効にしてWindowsに記録する")
print(" メニュー → 機能 → 警報機能 → イベントログ")
print()
print(" 3. 定期的にグラフでS.M.A.R.T.値の推移を確認する")
print(" メニュー → 機能 → グラフ")
if __name__ == "__main__":
main()
5.8 Docker設定(WSL2環境でのテスト用)
注意: CrystalDiskInfoはWindowsネイティブアプリのため、Docker内では直接動作しない。以下はWSL2からWindowsのCrystalDiskInfoログを分析する場合の設定例。
# Dockerfile - CrystalDiskInfo ログ分析環境
FROM python:3.11-slim
WORKDIR /app
# 必要なパッケージをインストール
RUN pip install pandas matplotlib
COPY parse_smart_log.py .
COPY check_cdi_env.py .
# Windows側のCrystalDiskInfoログをマウントして使用
# docker run -v /mnt/c/Program\ Files/CrystalDiskInfo/Smart:/data/smart analyzer
VOLUME /data/smart
CMD ["python", "parse_smart_log.py"]
# docker-compose.yml
version: '3.8'
services:
cdi-analyzer:
build: .
volumes:
# WSL2からWindowsのパスをマウント
- /mnt/c/Program Files/CrystalDiskInfo/Smart:/data/smart:ro
command: >
python parse_smart_log.py
/data/smart/*/Smart.ini
実装方法がわかったので、次は具体的なユースケースを見ていこう。
6. ユースケース別ガイド
6.1 ユースケース1: 個人PCの定期チェック
想定読者: 自分のPCのストレージ状態を定期的に確認したい方
推奨設定:
- 常駐: 有効
- 更新間隔: 30分
- 警報音: 有効
サンプルコード(週次レポート生成):
#!/usr/bin/env python3
"""
個人PC向け: 週次ストレージ健康レポート生成
CrystalDiskInfoのログからレポートを作成
使い方: python weekly_report.py
"""
import os
from pathlib import Path
from datetime import datetime, timedelta
from typing import Dict, List
def generate_weekly_report(cdi_path: Path) -> str:
"""週次レポートを生成"""
report_lines = []
report_lines.append("=" * 60)
report_lines.append(f"ストレージ健康レポート - {datetime.now().strftime('%Y/%m/%d')}")
report_lines.append("=" * 60)
report_lines.append("")
smart_path = cdi_path / 'Smart'
if not smart_path.exists():
report_lines.append("Smartフォルダが見つかりません")
return "\n".join(report_lines)
for drive_folder in sorted(smart_path.iterdir()):
if not drive_folder.is_dir():
continue
smart_ini = drive_folder / 'Smart.ini'
if not smart_ini.exists():
continue
report_lines.append(f"【{drive_folder.name}】")
# 最新のS.M.A.R.T.データを取得
latest_data = get_latest_smart_data(smart_ini)
if latest_data:
report_lines.append(f" 最終更新: {latest_data.get('date', '不明')}")
# 重要な属性をチェック
critical_attrs = {
'05': '代替処理済セクタ数',
'C5': '代替処理保留中セクタ数',
'C6': '回復不能セクタ数',
'C2': '温度',
'09': '使用時間'
}
for attr_id, attr_name in critical_attrs.items():
if attr_id in latest_data.get('attributes', {}):
current, raw = latest_data['attributes'][attr_id]
status = "正常" if current > 50 else "注意"
# 特定の属性は生の値で判定
if attr_id in ['05', 'C5', 'C6']:
raw_int = int(raw, 16) if raw else 0
status = "正常" if raw_int == 0 else "注意"
report_lines.append(f" {attr_name}: {raw_int} ({status})")
elif attr_id == 'C2':
temp = int(raw, 16) if raw else 0
status = "正常" if temp < 50 else "注意"
report_lines.append(f" {attr_name}: {temp}°C ({status})")
elif attr_id == '09':
hours = int(raw, 16) if raw else 0
report_lines.append(f" {attr_name}: {hours}時間")
report_lines.append("")
report_lines.append("=" * 60)
report_lines.append("※ 「注意」がある場合は、早めのバックアップを推奨します")
return "\n".join(report_lines)
def get_latest_smart_data(smart_ini: Path) -> Dict:
"""最新のS.M.A.R.T.データを取得"""
result = {'date': None, 'attributes': {}}
with open(smart_ini, 'r', encoding='utf-8', errors='ignore') as f:
in_latest_section = False
for line in f:
line = line.strip()
# FIRSTやTHRESHOLDセクションはスキップ
if line.startswith('['):
in_latest_section = 'FIRST' not in line and 'THRESHOLD' not in line
continue
if not in_latest_section:
continue
if line.startswith('Date=') and result['date'] is None:
result['date'] = line.split('=')[1]
elif '=' in line and ',' in line:
parts = line.split('=')
if len(parts) == 2:
attr_id = parts[0]
values = parts[1].split(',')
if len(values) >= 4:
result['attributes'][attr_id] = (int(values[0]), values[3])
return result
def main():
# CrystalDiskInfoの場所を探す
possible_paths = [
Path(os.environ.get('PROGRAMFILES', '')) / 'CrystalDiskInfo',
Path(os.environ.get('PROGRAMFILES(X86)', '')) / 'CrystalDiskInfo',
Path.home() / 'Downloads' / 'CrystalDiskInfo',
]
cdi_path = None
for path in possible_paths:
if (path / 'Smart').exists():
cdi_path = path
break
if not cdi_path:
print("CrystalDiskInfoのSmartフォルダが見つかりません")
print("CrystalDiskInfoを起動してログを蓄積してください")
return
report = generate_weekly_report(cdi_path)
print(report)
# ファイルにも保存
output_path = Path.home() / 'Desktop' / f'storage_report_{datetime.now().strftime("%Y%m%d")}.txt'
with open(output_path, 'w', encoding='utf-8') as f:
f.write(report)
print(f"\nレポートを保存しました: {output_path}")
if __name__ == "__main__":
main()
6.2 ユースケース2: 複数PCの一括監視
想定読者: 社内PCやサーバーを管理するシステム管理者
推奨構成:
- 各PCにCrystalDiskInfoをインストール
- コマンドラインオプションで定期出力
- 中央サーバーでログを収集
サンプルコード(リモート収集スクリプト):
#!/usr/bin/env python3
"""
システム管理者向け: 複数PCからS.M.A.R.T.情報を収集
CrystalDiskInfoの /CopyExit オプションを活用
前提: 各PCにCrystalDiskInfo(ポータブル版)を配置済み
"""
import subprocess
import shutil
from pathlib import Path
from datetime import datetime
from typing import List
def collect_smart_info(pc_list: List[str], cdi_path: str, output_dir: Path):
"""
複数PCからS.M.A.R.T.情報を収集
Args:
pc_list: PCのホスト名/IPリスト
cdi_path: CrystalDiskInfoのUNCパス(例: \\\\PC01\\C$\\Tools\\CrystalDiskInfo)
output_dir: 収集先ディレクトリ
"""
output_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
results = []
for pc in pc_list:
print(f"収集中: {pc}")
try:
# リモートでCrystalDiskInfoを実行(/CopyExitオプション)
remote_path = f"\\\\{pc}\\{cdi_path.lstrip('\\\\')}"
exe_path = f"{remote_path}\\DiskInfo64.exe"
# PsExecなどでリモート実行(要管理者権限)
# subprocess.run(['psexec', f'\\\\{pc}', exe_path, '/CopyExit'], timeout=60)
# DiskInfo.txtをコピー
src = Path(f"{remote_path}\\DiskInfo.txt")
dst = output_dir / f"{pc}_{timestamp}.txt"
if src.exists():
shutil.copy(src, dst)
results.append({'pc': pc, 'status': 'success', 'file': dst})
else:
results.append({'pc': pc, 'status': 'no_output', 'file': None})
except Exception as e:
results.append({'pc': pc, 'status': 'error', 'error': str(e)})
# 結果サマリー
print("\n" + "=" * 60)
print("収集結果サマリー")
print("=" * 60)
success = [r for r in results if r['status'] == 'success']
failed = [r for r in results if r['status'] != 'success']
print(f"成功: {len(success)}台")
print(f"失敗: {len(failed)}台")
if failed:
print("\n失敗したPC:")
for r in failed:
print(f" {r['pc']}: {r.get('error', r['status'])}")
return results
def main():
# 監視対象PCリスト
pc_list = [
'PC001',
'PC002',
'PC003',
# ...
]
# CrystalDiskInfoの配置パス(各PCで共通)
cdi_path = "C$\\Tools\\CrystalDiskInfo"
# 収集先
output_dir = Path("./collected_smart_info")
collect_smart_info(pc_list, cdi_path, output_dir)
if __name__ == "__main__":
main()
6.3 ユースケース3: NASの定期健康チェック
想定読者: 自宅NASを運用している方、小規模オフィスのNAS管理者
注意: NASにはCrystalDiskInfoを直接インストールできないことが多い。以下はNASからHDDを取り外してチェックする、またはUSB接続でチェックする場合の手順。
#!/usr/bin/env python3
"""
NAS向け: HDDの定期チェック記録ツール
USB接続でNASのHDDをチェックした結果を記録・比較する
"""
import json
from pathlib import Path
from datetime import datetime
from typing import Dict, Optional
class NASHealthTracker:
"""NASのHDD健康状態を追跡"""
def __init__(self, data_file: Path):
self.data_file = data_file
self.data = self._load()
def _load(self) -> Dict:
"""データファイルを読み込む"""
if self.data_file.exists():
with open(self.data_file, 'r', encoding='utf-8') as f:
return json.load(f)
return {'drives': {}, 'checks': []}
def _save(self):
"""データファイルを保存"""
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump(self.data, f, ensure_ascii=False, indent=2)
def add_check(self, drive_serial: str, drive_model: str,
smart_data: Dict, notes: str = ""):
"""チェック結果を追加"""
check_record = {
'timestamp': datetime.now().isoformat(),
'serial': drive_serial,
'model': drive_model,
'smart': smart_data,
'notes': notes
}
self.data['checks'].append(check_record)
# ドライブ情報を更新
if drive_serial not in self.data['drives']:
self.data['drives'][drive_serial] = {
'model': drive_model,
'first_seen': datetime.now().isoformat(),
'check_count': 0
}
self.data['drives'][drive_serial]['check_count'] += 1
self.data['drives'][drive_serial]['last_check'] = datetime.now().isoformat()
self._save()
# 前回との比較
return self._compare_with_previous(drive_serial, smart_data)
def _compare_with_previous(self, drive_serial: str,
current_smart: Dict) -> Optional[Dict]:
"""前回のチェック結果と比較"""
# 同じドライブの過去のチェックを探す
previous_checks = [
c for c in self.data['checks'][:-1] # 最新を除く
if c['serial'] == drive_serial
]
if not previous_checks:
return None
previous = previous_checks[-1]
changes = {}
# 重要な属性の変化をチェック
critical_attrs = ['05', 'C5', 'C6', '09']
for attr in critical_attrs:
if attr in current_smart and attr in previous['smart']:
current_raw = current_smart[attr].get('raw', 0)
previous_raw = previous['smart'][attr].get('raw', 0)
if current_raw != previous_raw:
changes[attr] = {
'previous': previous_raw,
'current': current_raw,
'diff': current_raw - previous_raw
}
return changes if changes else None
def generate_report(self) -> str:
"""全ドライブのサマリーレポートを生成"""
lines = []
lines.append("=" * 60)
lines.append("NAS HDD健康状態サマリー")
lines.append(f"生成日時: {datetime.now().strftime('%Y/%m/%d %H:%M')}")
lines.append("=" * 60)
lines.append("")
for serial, info in self.data['drives'].items():
lines.append(f"【{info['model']}】")
lines.append(f" シリアル: {serial}")
lines.append(f" 初回チェック: {info['first_seen'][:10]}")
lines.append(f" 最終チェック: {info.get('last_check', '不明')[:10]}")
lines.append(f" チェック回数: {info['check_count']}回")
# 最新のS.M.A.R.T.データを表示
latest_check = next(
(c for c in reversed(self.data['checks'])
if c['serial'] == serial),
None
)
if latest_check:
smart = latest_check['smart']
if '05' in smart:
lines.append(f" 代替処理済セクタ: {smart['05'].get('raw', 0)}")
if '09' in smart:
hours = smart['09'].get('raw', 0)
years = hours / 8760
lines.append(f" 使用時間: {hours}時間 ({years:.1f}年)")
lines.append("")
return "\n".join(lines)
def main():
# 使用例
tracker = NASHealthTracker(Path('./nas_health_data.json'))
# CrystalDiskInfoから手動で読み取った値を入力
# (実際の運用では、DiskInfo.txtをパースする)
smart_data = {
'05': {'raw': 0, 'current': 100},
'C5': {'raw': 0, 'current': 100},
'C6': {'raw': 0, 'current': 100},
'09': {'raw': 45678, 'current': 95},
'C2': {'raw': 38, 'current': 62}
}
changes = tracker.add_check(
drive_serial='WD-XXXXXXXXXXXXX',
drive_model='WD Red Plus 4TB',
smart_data=smart_data,
notes='定期チェック'
)
if changes:
print("⚠️ 前回からの変化を検出:")
for attr, change in changes.items():
print(f" 属性 {attr}: {change['previous']} → {change['current']} (差分: {change['diff']})")
else:
print("✅ 前回から大きな変化なし")
print()
print(tracker.generate_report())
if __name__ == "__main__":
main()
ユースケースを把握できたところで、この先の学習パスを確認しよう。
7. 学習ロードマップ
この記事を読んだ後、次のステップとして以下をおすすめする。
初級者向け(まずはここから)
-
CrystalDiskInfoをインストールして自分のPCをチェック
- 公式サイトからダウンロード
- 健康状態が「正常」か確認
-
重要な5つの属性を覚える
- 05: 代替処理済セクタ数
- C5: 代替処理保留中セクタ数
- C6: 回復不能セクタ数
- C2: 温度
- 09: 使用時間
中級者向け(実践に進む)
-
常駐機能を有効にしてログを蓄積
- メニュー → 機能 → 常駐
- 1週間程度運用してグラフを確認
-
イベントログと連携
- メニュー → 機能 → 警報機能 → イベントログ
- Windowsタスクスケジューラで定期レポート生成
上級者向け(さらに深く)
-
S.M.A.R.T.の仕様を理解
-
smartmontoolsとの連携
- Linux/macOSでの監視
- Prometheus/Grafanaでの可視化
8. まとめ
この記事では、CrystalDiskInfoについて以下を解説した:
- CrystalDiskInfoの正体: S.M.A.R.T.情報を可視化する無料の健康診断ツール
- 画面の見方: 健康状態(正常/注意/異常/不明)、温度、属性値の意味
-
ログの場所:
インストールフォルダ/Smart/[ディスク名]/Smart.ini - グラフ機能: メニュー → 機能 → グラフ で経時変化を確認
- 監視設定: 常駐、イベントログ、メール通知の設定方法
私の所感
CrystalDiskInfoは、日本製のフリーソフトとして非常に完成度が高い。特に以下の点が素晴らしい。
- 日本語対応が完璧: 属性名まで日本語化されている
- USB外付けドライブ対応: 多くのツールが対応していない領域
- 継続的なアップデート: NVMe、RAID、新しいSSDコントローラへの対応が迅速
一方で注意点もある。
- 起動中しかログが蓄積されない: 常駐機能を使わないとグラフが歯抜けになる
- S.M.A.R.T.の限界: Googleの研究によると、故障の36%は事前兆候なしに発生する
- NAS直接対応不可: ネットワーク経由でのS.M.A.R.T.取得には対応していない
CrystalDiskInfoは「万能の予防ツール」ではないが、「気づける故障を気づかないまま見逃す」リスクを大幅に減らせる。最も重要なのは、定期的にチェックする習慣 と 常にバックアップを取る習慣 だ。ツールはあくまで補助であり、データを守るのは自分自身だということを忘れないでほしい。
参考文献
- CrystalDiskInfo - Crystal Dew World(公式サイト)
- S.M.A.R.T. 情報 - Crystal Dew World
- イベントログ - Crystal Dew World
- 上級者向け機能 - Crystal Dew World
- GitHub - hiyohiyo/CrystalDiskInfo
- Failure Trends in a Large Disk Drive Population - Google Research
- Hard Drive Stats - Backblaze
関連記事