Windows – How to identify a volume in WMI from a volume name reported in the event log

diskmanagementpowershellwindowswindows-server-2008-r2wmi

I have a Windows 2008R2 server that's reporting the following error:

The file system structure on the disk is corrupt and unusable. Please
run the chkdsk utility on the volume \Device\HarddiskVolume2.

Using Powershell and WMI how do I identify which volume this is when querying Win32_Volume.

For example if I do:

Get-WmiObject Win32_Volume

I get a list of all the volumes on the server, however none of the Win32_Volume class properties use (what appears be) this "friendly" name – \Device\HarddiskVolume2. I can see there's a DeviceID property which returns a value like this:

DeviceID    : \\?\Volume{4bc3df2a-65c7-11e0-9c33-806e6f6e6963}\

There's also a Name property but that's just the drive letter assigned to the volume. None of the other properties have a value remotely resembling what is reported in the event log.

I know I could parse the output from fltmc volumes or DISKPART to get this information, but there must be a way to obtain this using WMI in a PowerShell script.

I have also looked at the Win32_DiskDrive, Win32_DiskPartition and Win32_LogicalDisk classes but there is no mention of property values resembling \Device\HarddiskVolume2.

Best Answer

Take a look at this code: http://poshcode.org/4768 it seems to do the conversions you need to see what you want, you might be able to tweak it to fit your needs, let me know if you need help with that but I think you can figure out on your own.

function Get-DevicePath
{
<#
.SYNOPSIS

    Returns the device paths for each volume.

    Author: Matthew Graeber (@mattifestation)
    License: BSD 3-Clause

.DESCRIPTION

    Get-DevicePath returns the corresponding device path for each drive letter. This is useful for converting device paths to drive letters.

.EXAMPLE

    Get-DevicePath

    DevicePath              DriveLetter
    ----------              -----------
    \Device\HarddiskVolume2 D:
    \Device\HarddiskVolume4 C:

.OUTPUTS

    PSObject[]

    For each mount point, a PSObject is returned representing the drive letter and device path.
#>

    # Utilize P/Invoke in order to call QueryDosDevice. I prefer using 
    # reflection over Add-Type since it doesn't require compiling C# code.
    $DynAssembly = New-Object System.Reflection.AssemblyName('SysUtils')
    $AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)
    $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('SysUtils', $False)

    # Define [Kernel32]::QueryDosDevice method
    $TypeBuilder = $ModuleBuilder.DefineType('Kernel32', 'Public, Class')
    $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('QueryDosDevice', 'kernel32.dll', ([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static), [Reflection.CallingConventions]::Standard, [UInt32], [Type[]]@([String], [Text.StringBuilder], [UInt32]), [Runtime.InteropServices.CallingConvention]::Winapi, [Runtime.InteropServices.CharSet]::Auto)
    $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
    $SetLastError = [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
    $SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('kernel32.dll'), [Reflection.FieldInfo[]]@($SetLastError), @($true))
    $PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)
    $Kernel32 = $TypeBuilder.CreateType()

    $Max = 65536
    $StringBuilder = New-Object System.Text.StringBuilder($Max)

    Get-WmiObject Win32_Volume | ? { $_.DriveLetter } | % {
        $ReturnLength = $Kernel32::QueryDosDevice($_.DriveLetter, $StringBuilder, $Max)

        if ($ReturnLength)
        {
            $DriveMapping = @{
                DriveLetter = $_.DriveLetter
                DevicePath = $StringBuilder.ToString()
            }

            New-Object PSObject -Property $DriveMapping
        }
    }
}