VB.NET(System.Management)でWMIの Win32_DiskDrive を参照し、Availability(利用可能状態)を取得しようとすると、環境によっては常に Nothing/null になって悩みがちです。本記事では「それは不具合なのか?」「確認方法は?」「代替手段は?」を、PowerShellとVB.NETの実例つきで整理します。
起きている現象:Win32_DiskDrive.Availability が常に null になる
例えば次のようなVB.NETコードで、ディスクの Availability を読むと常に Nothing になってしまう、というケースです。
Dim searcher As New ManagementObjectSearcher(New SelectQuery("Win32_DiskDrive"))
For Each disk As ManagementObject In searcher.Get()
Dim av = disk("Availability").ToString() ' ← Availability が Nothing のとき例外になり得る
Next
WMIのクラスリファレンスには Availability が定義されているのに値が入らないため、「WMIが壊れている?」「取得方法が間違い?」と疑ってしまいます。しかし、結論から言うと 「その環境ではプロパティが実装されておらず、値が提供されていない」 ことが珍しくありません。
Availability とは何か:実は“ディスク専用”の状態ではない
Win32_DiskDrive.Availability は、ストレージ固有の健康状態(SMARTの異常など)を表すプロパティではなく、もともとはCIM(Common Information Model)側で定義されている 汎用のデバイス稼働状態 を示すための値です。言い換えると、ネットワークアダプターやプリンターなど“あらゆるデバイス”に共通の概念として用意されており、ディスクの現実的な運用状態(オンライン/オフライン、故障予兆など)を正確に反映する保証はありません。
さらに重要なのは、WMIでは「クラスに定義がある」=「必ず値が返る」ではない点です。プロパティは仕様上存在していても、OSのWMIプロバイダーやドライバーがその値を提供していなければ、結果は null になります。
Availability の代表的な値(参考)
Availabilityは数値(UInt16)で返る想定のプロパティです。代表的な値は次のように定義されます(ただし、ディスクで確実に返るとは限りません)。
| 値 | 意味(概念) | ディスクでの解釈の注意点 |
|---|---|---|
| 2 | Unknown | そもそも取得不能・未実装の可能性が高い |
| 3 | Running/Full Power | “回っている”ではなく“稼働扱い”程度の意味 |
| 8 | Off Line | ストレージのオンライン/オフラインと一致しない場合がある |
| 10 | Degraded | RAID/仮想化/ドライバー構成では当てにならないことがある |
| 19 | Not Ready | リムーバブルや省電力復帰などで揺れることがある |
この表は「値が返ってきた場合にどう読むか」の参考にはなりますが、現場では 「値が返ってこない(null)」が最頻出 です。つまり、Availabilityは“使えたらラッキー”くらいに扱うのが安全です。
なぜ null になるのか:よくある原因パターン
原因:WMIプロバイダーが値を提供していない(最も多い)
Win32_DiskDrive の情報は、OS内部のWMIプロバイダーが複数のソースから集めて返します。ところが、Availabilityはプロバイダー側で「埋める優先度が低い」または「そもそも埋められない」扱いになっていることがあり、その場合は null のまま返されます。アプリ側の工夫で埋められるものではありません。
原因:ストレージ構成(NVMe / USB / RAID / 仮想ディスク)による差
同じWindowsでも、接続方式やドライバー層によってWMIに露出する情報が変わります。例えば次のような構成では、Availabilityを含む一部の汎用プロパティが欠落しやすい傾向があります。
- NVMe(標準ドライバー / ベンダードライバー)
- USB接続の外付けディスクやカードリーダー
- RAIDコントローラー配下の物理ディスク
- 仮想化環境(Hyper-V/VMware等)の仮想ディスク
- Storage Spaces(記憶域スペース)
特に「物理ディスクの詳細状態」を知りたい場合、Win32_DiskDrive 自体が情報不足になることがあり、より新しいストレージ管理のクラス(後述)へ切り替える方が現実的です。
原因:権限不足・セキュリティ制約(ただしAvailabilityだけがnullの原因にはなりにくい)
ローカルPCで Win32_DiskDrive を読むだけなら、通常は一般ユーザーでも取得できることが多いです。ただし、環境(企業端末のポリシー、EDR、WMI制限)によっては一部プロパティがマスクされたり、列挙自体が失敗したりします。Availabilityだけがnullで、他のプロパティ(Model や DeviceID など)が正常に取れているなら、権限不足が主因である可能性は低めです。
まずやるべき確認:OS側で値が入っているかをPowerShellで見る
アプリのコードを疑う前に、同じマシンでOSがそのプロパティを提供しているかを確認します。ここで空なら、VB.NET側で頑張っても空のままです。
PowerShell(推奨:CIM版)で確認
Get-CimInstance Win32_DiskDrive |
Select-Object DeviceID, Model, Availability, Status, StatusInfo
PowerShell(互換:WMI版)で確認
Get-WmiObject Win32_DiskDrive |
Select-Object DeviceID, Model, Availability, Status, StatusInfo
ここで Availability が空欄(null)のままなら、WMIプロバイダーが値を提供していません。この場合、設計としてAvailabilityに依存しない のが正解です。
VB.NET側の安全な実装:Nothing を前提に扱う
元のコードのままだと、disk("Availability") が Nothing のときに ToString() で例外が発生します。Availabilityに限らず、WMIは「値が入らないプロパティ」が現実に存在するため、nullチェックは必須 です。
最小の修正:nullチェックを入れる
Dim searcher As New ManagementObjectSearcher(New SelectQuery("Win32_DiskDrive"))
For Each disk As ManagementObject In searcher.Get()
Dim availabilityObj = disk("Availability")
Dim availability As String =
If(availabilityObj IsNot Nothing AndAlso Not Convert.IsDBNull(availabilityObj),
availabilityObj.ToString(),
String.Empty)
Dim statusObj = disk("Status")
Dim status As String =
If(statusObj IsNot Nothing AndAlso Not Convert.IsDBNull(statusObj),
statusObj.ToString(),
String.Empty)
Console.WriteLine($"Device: {disk("DeviceID")} Availability: {availability} Status: {status}")
Next
この形にしておけば、Availabilityが空でも落ちずに処理を継続できます。WMIを扱うコードでは、まず「落ちないこと」を最優先にしてください。
実務向け:必要なプロパティだけSELECTし、型変換も安全にする
WMIは全プロパティ取得が意外と重く、また型も Object で返ってくるため、実務では「必要な列だけ取る」「変換関数を用意して例外を吸収する」構成が安定します。
Imports System.Management
Module WmiDiskSample
Sub Main()
Dim scope As New ManagementScope("\\.\root\cimv2")
scope.Connect()
Dim query As New ObjectQuery(
"SELECT DeviceID, Model, Availability, Status, StatusInfo FROM Win32_DiskDrive"
)
Using searcher As New ManagementObjectSearcher(scope, query)
For Each disk As ManagementObject In searcher.Get()
Dim deviceId = TryGetString(disk, "DeviceID")
Dim model = TryGetString(disk, "Model")
Dim availability = TryGetUShort(disk, "Availability") ' Null許容
Dim status = TryGetString(disk, "Status")
Dim statusInfo = TryGetUShort(disk, "StatusInfo")
Console.WriteLine(
$"DeviceID={deviceId}, Model={model}, " &
$"Availability={If(availability.HasValue, availability.Value.ToString(), "(null)")}, " &
$"Status={status}, StatusInfo={If(statusInfo.HasValue, statusInfo.Value.ToString(), "(null)")}"
)
Next
End Using
End Sub
Private Function TryGetString(mo As ManagementBaseObject, propName As String) As String
Dim v = mo(propName)
If v Is Nothing OrElse Convert.IsDBNull(v) Then Return ""
Return v.ToString()
End Function
Private Function TryGetUShort(mo As ManagementBaseObject, propName As String) As UShort?
Dim v = mo(propName)
If v Is Nothing OrElse Convert.IsDBNull(v) Then Return Nothing
Try
Return Convert.ToUInt16(v)
Catch
Return Nothing
End Try
End Function
End Module
ポイントは次の通りです。
- SELECTで列を絞る:余計なプロパティを取らないことで高速化・安定化
- NullとDBNullの両方を扱う:環境差でどちらが返るか揺れることがある
- 数値はNullableで持つ:Availabilityは数値のはずなので、空なら
Nothingとして表現
「Availabilityの代わりに何を見るべきか」目的別の現実解
Availabilityが空でも困らないように、目的に応じて参照先を切り替えます。ディスク状態の取得は「何が知りたいか」で最適解が変わります。
| 知りたいこと | おすすめ | 理由 | 注意点 |
|---|---|---|---|
| ざっくり正常か(監視の入口) | Win32_DiskDrive.Status | 多くの環境で文字列が入る(OK/Errorなど) | “OK”でも故障予兆はあり得る |
| オンライン/オフライン、読み取り専用など運用状態 | ストレージ管理(MSFT_Disk / MSFT_PhysicalDisk) | Windowsのストレージ管理に近い概念で取得できる | 古いOSでは使えない/情報が揃わないことがある |
| 故障予兆(SMART) | MSStorageDriver_FailurePredictStatus など | “予兆あり/なし”が取れる可能性がある | ベンダー・接続方式により取れないことがある |
| メーカー固有の詳細診断 | ベンダーツール/管理API | 最も正確で情報量が多い | 配布・運用・ライセンス面の制約が出やすい |
代替案:Status を使う(まずはこれが一番手堅い)
Win32_DiskDrive.Status は文字列で、環境によって OK / Error / Unknown などが返ります。Availabilityのように完全に空になり続けるケースは比較的少なく、「監視の入口」として使いやすいプロパティです。
Dim status As String = TryGetString(disk, "Status")
If status.Equals("OK", StringComparison.OrdinalIgnoreCase) Then
' ひとまず正常扱い
Else
' Unknown/Error などはログに残して追加調査へ
End If
ただし、Statusは“診断の確定”ではありません。SMART異常の手前や一時的なI/O遅延などは反映されないこともあるため、ミッションクリティカルな監視では次の層(ストレージ管理やSMART)も併用します。
代替案:ストレージ管理(MSFT_*)で運用状態を取る
Windows 8 / Windows Server 2012以降の環境では、WMI(root\\cimv2)とは別に、ストレージ管理用の名前空間 root\\Microsoft\\Windows\\Storage が使えることがあります。ここには、実運用に近いプロパティ(オンライン/オフライン、健康状態、操作状態)が用意されているため、Availabilityより実用的です。
まずPowerShellで確認するなら、次が分かりやすいです。
Get-PhysicalDisk | Select FriendlyName, MediaType, OperationalStatus, HealthStatus, Size
Get-Disk | Select Number, FriendlyName, IsOffline, IsReadOnly, OperationalStatus, HealthStatus
VB.NETからもWMIとして参照できます。名前空間を変えて検索します。
Dim scope As New ManagementScope("\\.\root\Microsoft\Windows\Storage")
scope.Connect()
Dim query As New ObjectQuery("SELECT Number, FriendlyName, IsOffline, IsReadOnly, OperationalStatus, HealthStatus FROM MSFT_Disk")
Using searcher As New ManagementObjectSearcher(scope, query)
For Each d As ManagementObject In searcher.Get()
Console.WriteLine(
$"Number={TryGetString(d, "Number")} " &
$"Name={TryGetString(d, "FriendlyName")} " &
$"IsOffline={TryGetString(d, "IsOffline")} " &
$"IsReadOnly={TryGetString(d, "IsReadOnly")} " &
$"HealthStatus={TryGetString(d, "HealthStatus")}"
)
Next
End Using
ストレージ管理側のプロパティは、OSの「ディスクの管理」や「サーバーマネージャー」の概念に近く、Availabilityよりも実務で判断しやすい傾向があります。
代替案:SMART(故障予兆)をWMIで拾う
「Availabilityが取れない」問題の背景には、そもそもAvailabilityが“故障予兆”を表す設計ではない、という点もあります。ディスクの故障監視に寄せたいなら、SMART系のクラスを検討した方が目的に合います。
PowerShell例(環境によって取得できない場合もあります)。
Get-WmiObject -Namespace root\wmi -Class MSStorageDriver_FailurePredictStatus |
Select-Object InstanceName, PredictFailure, Reason
見どころは PredictFailure(故障予兆の有無)です。trueなら早急な交換検討に入る、falseでも“絶対安全”ではない、といった運用が一般的です。
SMARTはベンダーや接続方式で取得可否が変わりやすく、USBケース越しでは取れない、仮想環境では見えない、RAID配下ではコントローラ側の管理が必要、といった制約があります。Availabilityが空になるのと同様に、「取れないことを前提に設計する」姿勢が重要です。
実務で困らない設計:ステータス判定を“多層化”する
ディスクの状態確認をAvailability一発で済ませようとすると、環境差で破綻しがちです。おすすめは、目的に合わせて情報源をレイヤー化し、取れたものから判断する設計です。
| レイヤー | 情報源 | 得意なこと | 取れないとき |
|---|---|---|---|
| 基本 | Win32_DiskDrive(Statusなど) | 互換性が高い・まず一覧が取れる | Unknown/空は「不明」として次へ |
| 運用 | MSFT_Disk, MSFT_PhysicalDisk | オンライン/オフライン、健康状態が分かることが多い | 古いOSや構成では未対応 → SMARTへ |
| 予兆 | SMART(MSStorageDriver_*) | 故障予兆の検出(取れれば強い) | 取れない構成はベンダーツールへ |
| 確定診断 | ベンダーツール/管理コンソール | 最も正確・ログ/温度/寿命なども見える | 運用制約があるため代替手段も残す |
このように「Availabilityが取れたら使う」ではなく、Availabilityは最初から当てにしない ほうが、結果的に堅牢です。
トラブルシューティング:Availabilityがnullでも“異常”とは限らない
Availabilityがnullだからといって、すぐに「WMIリポジトリが壊れている」「Windowsが異常」と結論付けるのは早計です。まずは次の切り分けをおすすめします。
切り分けチェックリスト
- 他のプロパティは取れているか:
DeviceID,Model,InterfaceType,Sizeなどが取れるならWMI自体は動いている可能性が高い - PowerShellでもAvailabilityが空か:空ならプロバイダー未実装の可能性が高い
- 同一OSでも別マシンで差が出るか:差が出るならドライバー/ストレージ構成依存の可能性
- 管理者で実行して変化するか:変化するなら権限やセキュリティの影響を疑う
- 仮想環境か:仮想ディスクは物理状態を持たないため、汎用プロパティが空になりやすい
よくある質問
Availabilityがnullなら「ディスクが使えない」という意味?
いいえ。nullは「使えない」ではなく「値が提供されていない」 と考えるのが自然です。実際、OSが通常通り起動し、I/OもできているのにAvailabilityだけ空、というケースは普通に起きます。
Availabilityをどうしても数値で欲しい。代替の数値は?
「数値の状態コードが欲しい」という目的なら、StatusInfo や OperationalStatus といったプロパティを検討します。ただしこれらも環境差があります。最終的には、“欲しい情報の粒度”に合ったクラスへ移る(例:MSFT_PhysicalDisk)方が失敗しにくいです。
WMIの取得を高速化したい
高速化の基本は、次の3つです。
- SELECTで列を絞る(必要なプロパティだけ)
- ループ内で例外を出さない(nullチェック・変換関数)
- 必要ならフィルターをかける(例:
WHERE InterfaceType='USB'など)
特にWMIは「プロパティを参照した瞬間に裏で追加問い合わせが走る」ような挙動になることもあるため、最初から取得対象を絞る設計が効きます。
まとめ:Availabilityは“仕様として存在するが、実務では空になりがち”
Win32_DiskDrive.Availabilityは定義されていても、環境によっては値が提供されずnullが返る- PowerShell(
Get-CimInstance/Get-WmiObject)でOS側の値を先に確認すると切り分けが速い - VB.NET側は null前提 の実装(
ToString()直呼びを避ける)にする - 状態把握の目的に合わせて、
Status/ストレージ管理(MSFT_*)/SMARTなどへ切り替える

コメント