WMI Win32_DiskDrive Availabilityがnullになる原因と対処法|VB.NET(System.Management)でディスク状態を確認

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)で返る想定のプロパティです。代表的な値は次のように定義されます(ただし、ディスクで確実に返るとは限りません)。

値意味(概念)ディスクでの解釈の注意点
2Unknownそもそも取得不能・未実装の可能性が高い
3Running/Full Power“回っている”ではなく“稼働扱い”程度の意味
8Off Lineストレージのオンライン/オフラインと一致しない場合がある
10DegradedRAID/仮想化/ドライバー構成では当てにならないことがある
19Not 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などへ切り替える

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次