Powershell/WMI 将堆叠驱动器设备 ID 映射到卷号

Powershell/WMI 将堆叠驱动器设备 ID 映射到卷号

现在我正在使用这两个 WMI 查询来获取有关机器上驱动器的信息:

get-wmiObject -Class Win32_LogicalDisk -Namespace root\CIMV2
-Computername $name


get-wmiObject -Class Win32_DiskDrive -Namespace root\CIMV2
-Computername $name

第一个给我指代驱动器号的 DeviceID,然后是有关这些驱动器的一些信息(包括卷序列号等)

第二个给我映射到的 DeviceID\\\\.\\PHYSICALDRIVE#和诸如序列号(似乎不同)分区、索引、scsi 端口/id 等信息。

我还看到了类似的东西Win32_DiskDriveToDiskPartition,它会提供诸如磁盘号、分区号和磁盘索引之类的内容。

我的问题是,是否存在可以查询的方法/通用值,以检查 DeviceID 是否Win32_DiskDrive被映射到任何地方的卷以及该卷(或那些卷)是什么?

我知道一定有办法,因为 Win32 对象太多了,我不确定要跟踪它们中的哪个值。任何帮助都将非常有帮助!理想情况下,我希望能够定义一个函数,该函数调用计算机名称并列出所有磁盘设备、所有卷,并指示哪个卷号位于哪个驱动器上。

答案1

Powershell/WMI 将堆叠驱动器设备 ID 映射到卷号

我的问题是,是否有可以查询的方法/通用值,以检查 Win32_DiskDrive 中的 DeviceID 是否在任何地方映射为卷,以及该卷(或那些卷)是什么?

似乎Win32_Volume 类是您需要使用的。它同时提供 DeviceID 和驱动器号值

PowerShell 语法示例 1

get-wmiObject -Class Win32_Volume -Namespace root\CIMV2 | Format-List -Property Name, DriveLetter, __Path, DeviceID

PowerShell 语法示例 2

get-wmiObject -Class Win32_Volume -Namespace root\CIMV2

我的问题是,是否有可以查询的方法/通用值,以检查 Win32_DiskDrive 中的 DeviceID 是否在任何地方映射为卷,以及该卷(或那些卷)是什么?

我知道一定有办法,因为 Win32 对象太多了,我不确定要跟踪它们中的哪个值。任何帮助都将非常有帮助!理想情况下,我希望能够定义一个函数,该函数调用计算机名称并列出所有磁盘设备、所有卷,并指示哪个卷号位于哪个驱动器上。

Technet 图库 - Powershell

(将下面的 PowerShell 脚本构建为一个函数。您可以在本地运行它,也可以在远程机器上运行它。请参阅超链接以获取来自源代码的完整详细信息。)

一旦构建了该函数,就可以简单地以几种不同的方式运行:

  1. Get-RemoteDiskInformation按 Enter 键获取本地磁盘和卷详细信息
  2. Get-RemoteDiskInformation -ComputerName <ComputerName>获取远程系统的磁盘和卷详细信息

PowerShell 函数逻辑

Function Get-RemoteDiskInformation
{
    <#
    .SYNOPSIS
       Get inventory data for specified computer systems.
    .DESCRIPTION
       Gather inventory data for one or more systems using wmi. Data proccessing utilizes multiple runspaces
       and supports custom timeout parameters in case of wmi problems. You can optionally include 
       drive, memory, and network information in the results. You can view verbose information on each 
       runspace thread in realtime with the -Verbose option.
    .PARAMETER ComputerName
       Specifies the target computer for data query.
    .PARAMETER ThrottleLimit
       Specifies the maximum number of systems to inventory simultaneously 
    .PARAMETER Timeout
       Specifies the maximum time in second command can run in background before terminating this thread.
    .PARAMETER ShowProgress
       Show progress bar information
    .PARAMETER PromptForCredential
       Prompt for remote system credential prior to processing request.
    .PARAMETER Credential
       Accept alternate credential (ignored if the localhost is processed)
    .EXAMPLE
       PS > Get-RemoteDiskInformation -ComputerName test1

       Description
       -----------
       Query and display disk related information about test1

    .EXAMPLE
       PS > $cred = Get-Credential
       PS > Get-RemoteDiskInformation -ComputerName Test1 -Credential $cred

    .NOTES
    Author:
    Zachary Loeber

    Version Info:
    1.1 - 01/04/2014
        - Added missing computername property to diskelements variable
    1.0 - 12/13/2013
        - Initial release (kind of, this bit of code is modified from a prior function I rolled into an all inclusive system information gathering
          function).
    .LINK 
        http://www.the-little-things.net 
    #>
    [CmdletBinding()]
    PARAM
    (
        [Parameter(ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [Alias('DNSHostName','PSComputerName')]
        [string[]]
        $ComputerName=$env:computername,

        [Parameter( HelpMessage="Refrain from applying drive space GB/MB/KB pretty formatting.")]
        [switch]
        $RawDriveData,

        [Parameter(HelpMessage="Maximum number of concurrent runspaces.")]
        [ValidateRange(1,65535)]
        [int32]
        $ThrottleLimit = 32,

        [Parameter(HelpMessage="Timeout before a runspaces stops trying to gather the information.")]
        [ValidateRange(1,65535)]
        [int32]
        $Timeout = 120,

        [Parameter(HelpMessage="Display progress of function.")]
        [switch]
        $ShowProgress,

        [Parameter(HelpMessage="Set this if you want the function to prompt for alternate credentials.")]
        [switch]
        $PromptForCredential,

        [Parameter(HelpMessage="Set this if you want to provide your own alternate credentials.")]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    BEGIN
    {
        # Gather possible local host names and IPs to prevent credential utilization in some cases
        Write-Verbose -Message 'Get-RemoteDiskInformation: Creating local hostname list'
        $IPAddresses = [net.dns]::GetHostAddresses($env:COMPUTERNAME) | Select-Object -ExpandProperty IpAddressToString
        $HostNames = $IPAddresses | ForEach-Object {
            try {
                [net.dns]::GetHostByAddress($_)
            } catch {
                # We do not care about errors here...
            }
        } | Select-Object -ExpandProperty HostName -Unique
        $LocalHost = @('', '.', 'localhost', $env:COMPUTERNAME, '::1', '127.0.0.1') + $IPAddresses + $HostNames

        Write-Verbose -Message 'Get-RemoteDiskInformation: Creating initial variables'
        $runspacetimers       = [HashTable]::Synchronized(@{})
        $runspaces            = New-Object -TypeName System.Collections.ArrayList
        $bgRunspaceCounter    = 0

        if ($PromptForCredential)
        {
            $Credential = Get-Credential
        }

        Write-Verbose -Message 'Get-RemoteDiskInformation: Creating Initial Session State'
        $iss = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
        foreach ($ExternalVariable in ('runspacetimers', 'Credential', 'LocalHost'))
        {
            Write-Verbose -Message "Get-RemoteDiskInformation: Adding variable $ExternalVariable to initial session state"
            $iss.Variables.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $ExternalVariable, (Get-Variable -Name $ExternalVariable -ValueOnly), ''))
        }

        Write-Verbose -Message 'Get-RemoteDiskInformation: Creating runspace pool'
        $rp = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(1, $ThrottleLimit, $iss, $Host)
        $rp.ApartmentState = 'STA'
        $rp.Open()

        # This is the actual code called for each computer
        Write-Verbose -Message 'Get-RemoteDiskInformation: Defining background runspaces scriptblock'
        $ScriptBlock = 
        {
            [CmdletBinding()]
            Param
            (
                [Parameter(Position=0)]
                [string]
                $ComputerName,

                [Parameter(Position=1)]
                [int]
                $bgRunspaceID,

                [Parameter(Position=2)]
                [switch]
                $RawDriveData
            )
            $runspacetimers.$bgRunspaceID = Get-Date

            try
            {
                Write-Verbose -Message ('Get-RemoteDiskInformation: Runspace {0}: Start' -f $ComputerName)
                $WMIHast = @{
                    ComputerName = $ComputerName
                    ErrorAction = 'Stop'
                }
                if (($LocalHost -notcontains $ComputerName) -and ($Credential -ne $null))
                {
                    $WMIHast.Credential = $Credential
                }

                Filter ConvertTo-KMG 
                {
                     <#
                     .Synopsis
                      Converts byte counts to Byte\KB\MB\GB\TB\PB format
                     .DESCRIPTION
                      Accepts an [int64] byte count, and converts to Byte\KB\MB\GB\TB\PB format
                      with decimal precision of 2
                     .EXAMPLE
                     3000 | convertto-kmg
                     #>

                     $bytecount = $_
                        switch ([math]::truncate([math]::log($bytecount,1024))) 
                        {
                            0 {"$bytecount Bytes"}
                            1 {"{0:n2} KB" -f ($bytecount / 1kb)}
                            2 {"{0:n2} MB" -f ($bytecount / 1mb)}
                            3 {"{0:n2} GB" -f ($bytecount / 1gb)}
                            4 {"{0:n2} TB" -f ($bytecount / 1tb)}
                            Default {"{0:n2} PB" -f ($bytecount / 1pb)}
                        }
                }

                Write-Verbose -Message ('Get-RemoteDiskInformation: Runspace {0}: Disk information' -f $ComputerName)
                $WMI_DiskMountProps   = @('Name','Label','Caption','Capacity','FreeSpace','Compressed','PageFilePresent','SerialNumber')

                # WMI data
                $wmi_diskdrives = Get-WmiObject @WMIHast -Class Win32_DiskDrive
                $wmi_mountpoints = Get-WmiObject @WMIHast -Class Win32_Volume -Filter "DriveType=3 AND DriveLetter IS NULL" | 
                                   Select $WMI_DiskMountProps

                $AllDisks = @()
                $DiskElements = @('ComputerName','Disk','Model','Partition','Description','PrimaryPartition','VolumeName','Drive','DiskSize','FreeSpace','UsedSpace','PercentFree','PercentUsed','DiskType','SerialNumber')
                foreach ($diskdrive in $wmi_diskdrives) 
                {
                    $partitionquery = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID=`"$($diskdrive.DeviceID.replace('\','\\'))`"} WHERE AssocClass = Win32_DiskDriveToDiskPartition"
                    $partitions = @(Get-WmiObject @WMIHast -Query $partitionquery)
                    foreach ($partition in $partitions)
                    {
                        $logicaldiskquery = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID=`"$($partition.DeviceID)`"} WHERE AssocClass = Win32_LogicalDiskToPartition"
                        $logicaldisks = @(Get-WmiObject @WMIHast -Query $logicaldiskquery)
                        foreach ($logicaldisk in $logicaldisks)
                        {
                            $PercentFree = [math]::round((($logicaldisk.FreeSpace/$logicaldisk.Size)*100), 2)
                            $UsedSpace = ($logicaldisk.Size - $logicaldisk.FreeSpace)
                            $diskprops = @{
                                           ComputerName = $ComputerName
                                           Disk = $diskdrive.Name
                                           Model = $diskdrive.Model
                                           Partition = $partition.Name
                                           Description = $partition.Description
                                           PrimaryPartition = $partition.PrimaryPartition
                                           VolumeName = $logicaldisk.VolumeName
                                           Drive = $logicaldisk.Name
                                           DiskSize = if ($RawDriveData) { $logicaldisk.Size } else { $logicaldisk.Size | ConvertTo-KMG }
                                           FreeSpace = if ($RawDriveData) { $logicaldisk.FreeSpace } else { $logicaldisk.FreeSpace | ConvertTo-KMG }
                                           UsedSpace = if ($RawDriveData) { $UsedSpace } else { $UsedSpace | ConvertTo-KMG }
                                           PercentFree = $PercentFree
                                           PercentUsed = [math]::round((100 - $PercentFree),2)
                                           DiskType = 'Partition'
                                           SerialNumber = $diskdrive.SerialNumber
                                         }
                            Write-Output (New-Object psobject -Property $diskprops | Select $DiskElements)
                        }
                    }
                }
                # Mountpoints are weird so we do them seperate.
                if ($wmi_mountpoints)
                {
                    foreach ($mountpoint in $wmi_mountpoints)
                    {
                        $PercentFree = [math]::round((($mountpoint.FreeSpace/$mountpoint.Capacity)*100), 2)
                        $UsedSpace = ($mountpoint.Capacity - $mountpoint.FreeSpace)
                        $diskprops = @{
                               ComputerName = $ComputerName
                               Disk = $mountpoint.Name
                               Model = ''
                               Partition = ''
                               Description = $mountpoint.Caption
                               PrimaryPartition = ''
                               VolumeName = ''
                               VolumeSerialNumber = ''
                               Drive = [Regex]::Match($mountpoint.Caption, "(^.:)").Value
                               DiskSize = if ($RawDriveData) { $mountpoint.Capacity } else { $mountpoint.Capacity | ConvertTo-KMG }
                               FreeSpace = if ($RawDriveData) { $mountpoint.FreeSpace } else { $mountpoint.FreeSpace | ConvertTo-KMG }
                               UsedSpace = if ($RawDriveData) { $UsedSpace } else { $UsedSpace | ConvertTo-KMG }
                               PercentFree = $PercentFree
                               PercentUsed = [math]::round((100 - $PercentFree),2)
                               DiskType = 'MountPoint'
                               SerialNumber = $mountpoint.SerialNumber
                             }
                        Write-Output (New-Object psobject -Property $diskprops  | Select $DiskElements)
                    }
                }
            }
            catch
            {
                Write-Warning -Message ('Get-RemoteDiskInformation: {0}: {1}' -f $ComputerName, $_.Exception.Message)
            }
            Write-Verbose -Message ('Get-RemoteDiskInformation: Runspace {0}: End' -f $ComputerName)
        }

        function Get-Result
        {
            [CmdletBinding()]
            Param 
            (
                [switch]$Wait
            )
            do
            {
                $More = $false
                foreach ($runspace in $runspaces)
                {
                    $StartTime = $runspacetimers[$runspace.ID]
                    if ($runspace.Handle.isCompleted)
                    {
                        Write-Verbose -Message ('Get-RemoteDiskInformation: Thread done for {0}' -f $runspace.IObject)
                        $runspace.PowerShell.EndInvoke($runspace.Handle)
                        $runspace.PowerShell.Dispose()
                        $runspace.PowerShell = $null
                        $runspace.Handle = $null
                    }
                    elseif ($runspace.Handle -ne $null)
                    {
                        $More = $true
                    }
                    if ($Timeout -and $StartTime)
                    {
                        if ((New-TimeSpan -Start $StartTime).TotalSeconds -ge $Timeout -and $runspace.PowerShell)
                        {
                            Write-Warning -Message ('Timeout {0}' -f $runspace.IObject)
                            $runspace.PowerShell.Dispose()
                            $runspace.PowerShell = $null
                            $runspace.Handle = $null
                        }
                    }
                }
                if ($More -and $PSBoundParameters['Wait'])
                {
                    Start-Sleep -Milliseconds 100
                }
                foreach ($threat in $runspaces.Clone())
                {
                    if ( -not $threat.handle)
                    {
                        Write-Verbose -Message ('Get-RemoteDiskInformation: Removing {0} from runspaces' -f $threat.IObject)
                        $runspaces.Remove($threat)
                    }
                }
                if ($ShowProgress)
                {
                    $ProgressSplatting = @{
                        Activity = 'Get-RemoteDiskInformation: Getting asset info'
                        Status = '{0} of {1} total threads done' -f ($bgRunspaceCounter - $runspaces.Count), $bgRunspaceCounter
                        PercentComplete = ($bgRunspaceCounter - $runspaces.Count) / $bgRunspaceCounter * 100
                    }
                    Write-Progress @ProgressSplatting
                }
            }
            while ($More -and $PSBoundParameters['Wait'])
        }
    }
    PROCESS
    {
        foreach ($Computer in $ComputerName)
        {
            $bgRunspaceCounter++
            $psCMD = [System.Management.Automation.PowerShell]::Create().AddScript($ScriptBlock)
            $null = $psCMD.AddParameter('bgRunspaceID',$bgRunspaceCounter)
            $null = $psCMD.AddParameter('ComputerName',$Computer)
            $null = $psCMD.AddParameter('RawDriveData',$RawDriveData)            
            $null = $psCMD.AddParameter('Verbose',$VerbosePreference) # Passthrough the hidden verbose option so write-verbose works within the runspaces
            $psCMD.RunspacePool = $rp

            Write-Verbose -Message ('Get-RemoteDiskInformation: Starting {0}' -f $Computer)
            [void]$runspaces.Add(@{
                Handle = $psCMD.BeginInvoke()
                PowerShell = $psCMD
                IObject = $Computer
                ID = $bgRunspaceCounter
                })
           Get-Result
        }
    }
    END
    {
        Get-Result -Wait
        if ($ShowProgress)
        {
            Write-Progress -Activity 'Get-RemoteDiskInformation: Getting asset info' -Status 'Done' -Completed
        }
        Write-Verbose -Message "Get-RemoteDiskInformation: Closing runspace pool"
        $rp.Close()
        $rp.Dispose()
    }
}

您可以通过一些测试和阅读来扩展此功能,以从其他 WMI 类和值中获取更多详细信息;下面是我发现的一些与您的查询相关的详细信息,作为该任务的起点。

Get-WMIObject -Class Win32_Volume | Select-Object -Property *
Get-WMIObject -Class Win32_DiskDrive | Select-Object -Property *
Get-WmiObject -Class Win32_DiskPartition | Select-Object -Property *
Get-WMIObject -Class Win32_LogicalDisk | Select-Object -Property *
Get-WMIObject -Class Win32_LogicalDiskToPartition | Select-Object -Property *

相关内容