Powershell和wmi,如何将逻辑磁盘/卷映射到硬盘,反之亦然?

时间:2011-01-27 22:15:26

标签: powershell wmi disk

Get-WmiObject -ComputerName $ip -Credential $credential -Class Win32_logicaldisk

这会让我看到“我的电脑”中的磁盘,例如。 C:,D:,E: 现在我如何获得相应的底层物理磁盘?

如果我运行以下命令

Get-WmiObject -ComputerName $ip -Credential $credential -Class win32_diskdrive

我得到磁盘0,磁盘1,磁盘2

那么如何找出哪个逻辑磁盘在哪个物理磁盘上?

另一个问题是如何找出卷号?如果我运行diskpart并执行“list volume”,我会得到以下输出

  Volume ###  Ltr  Label        Fs     Type        Size     Status     Info
  ----------  ---  -----------  -----  ----------  -------  ---------  --------
  Volume 2     C                NTFS   Partition     59 GB  Healthy    Boot
  ...

如何找出逻辑磁盘C:是第2卷?

最好的问候,Primoz。

6 个答案:

答案 0 :(得分:8)

试试这个

Get-WMIObject Win32_LogicalDisk | Foreach-Object {
    Get-WmiObject -Query "Associators of {Win32_LogicalDisk.DeviceID='$($_.DeviceID)'} WHERE ResultRole=Antecedent"
} | Format-Table

这为您提供了WIn32_logicalDisk的相关实例,其中Win32_LogicalDisk是关系中的依赖实体。因此,您将获得Win32_DiskDrive实例。

答案 1 :(得分:1)

这是我创建的完整脚本,用于列出逻辑磁盘,分区和分区偏移量,以检查磁盘对齐问题。 (来源:我的博客http://sev17.com/2009/02/disk-alignment-partitioning-the-good-the-bad-the-ok-and-the-not-so-ugly/

param ($computer)

$partitions = Get-WmiObject -computerName $computer Win32_DiskPartition

$partitions | foreach { Get-WmiObject -computerName $computer -query “ASSOCIATORS OF {Win32_DiskPartition.DeviceID=’$($_.DeviceID)’} WHERE AssocClass = Win32_LogicalDiskToPartition” |
add-member -membertype noteproperty PartitionName $_.Name -passthru |
add-member -membertype noteproperty Block $_.BlockSize -passthru |
add-member -membertype noteproperty StartingOffset $_.StartingOffset -passthru |
add-member -membertype noteproperty StartSector $($_.StartingOffset/$_.BlockSize) -passthru } |
Select SystemName, Name, PartitionName, Block, StartingOffset, StartSector

答案 2 :(得分:1)

如果您不关心 mountpoint卷,那么WMI关系的其他答案是好的,因为WMI没有可能直接将mountpoint卷与分区或磁盘相关联。

但是有一个注册表项可以帮助你弄清楚一些可以帮助你建立连接的信息,就像windows一样:

function getVolumeInformation{
    param($hostName, $credential)
    $volumeInformation = getVolumeInformation -computerName $hostName -credential $credential                   


    $WMIRegistryMountedDeviceInfo = WMIRegistryMountedDeviceInfo -computerName $hostName -Credential $credential
    foreach($volumeSerial in $volumeInformation.keys){                        
        if($WMIRegistryMountedDeviceInfo.containsKey($volumeSerial)){                        
            $volumeInformation[$volumeSerial]["diskPartitionStartingOffset"]=$WMIRegistryMountedDeviceInfo[$volumeSerial].diskPartitionStartingOffset
            $volumeInformation[$volumeSerial]["diskDriveSignature"]=$WMIRegistryMountedDeviceInfo[$volumeSerial].diskDriveSignature
            $volumeInformation[$volumeSerial]["wmiValueRegistry"]=$WMIRegistryMountedDeviceInfo[$volumeSerial].wmiValue
        }   
    }
    return $volumeInformation
}



function getWMIVolumeInformation{
    param($computerName, $credential)
    $diskToVolumeAssociation = @{}
    $regexGetVolumeSerial = ".*Volume{(.*)}.*"
    $wmiVolumes = $null
    $wmiVolumes = Get-WmiObject Win32_Volume -Credential $credential -ComputerName $computerName -filter "DriveType != 5" -ErrorVariable errorWMIVolume -ErrorAction SilentlyContinue

    $volumeInfo = @{}

    $wmiVolumes |   Foreach-Object {
        $wmiVolume = $_
        if($wmiVolume.DeviceID -match  $regexGetVolumeSerial){
            $wmiVolumeSerial = $Matches[1]
            $volumeInfo[$wmiVolumeSerial] = @{}
            $volumeInfo[$wmiVolumeSerial]["wmiInfo"] = $wmiVolume
            $volumeInfo[$wmiVolumeSerial]["volumeDirectoryName"] = $wmiVolume.Name
            $volumeInfo[$wmiVolumeSerial]["label"] = $wmiVolume.label
            $volumeInfo[$wmiVolumeSerial]["serial"] = $wmiVolumeSerial
            $volumeInfo[$wmiVolumeSerial]["capacity"] = $wmiVolume.Capacity
            $volumeInfo[$wmiVolumeSerial]["freeSpace"] = $wmiVolume.FreeSpace
        }
    }
    return $volumeInfo  


}
function WMIRegistryMountedDeviceInfo{
    param($computerName, $mycreds)
    $MountPointRegistryInformation = @{}

    $hklm = 2147483650
    $registryKeyMountedDevices = "SYSTEM\MountedDevices"
    $regexMountPoint = ".*{(.*)}.*"

    $wmi = get-wmiobject -list "StdRegProv" -namespace root\default -computername $computerName -credential $mycreds
    $wmiMountedDeviceKey = ($wmi.EnumValues($hklm,$registryKeyMountedDevices))

    foreach($mountedDeviceRegistryName in $wmiMountedDeviceKey.sNames){

        if($mountedDeviceRegistryName -match $regexMountPoint){
            $wmiValue = ($wmi.GetBinaryValue($hklm,$registryKeyMountedDevices,$mountedDeviceRegistryName))
            if($wmiValue.uValue.Count -eq 12){
                $diskDriveSignature = [bitconverter]::ToUInt32($wmiValue.uValue[0..3],0)
                $diskPartitionStartingOffset = [bitconverter]::ToUInt64($wmiValue.uValue[4..11],0)
                $MountPointRegistryInformation[$Matches[1]]=@{"serial"=$Matches[1];
                    "mountedDeviceRegistryName"=$mountedDeviceRegistryName;
                    "diskDriveSignature"=$diskDriveSignature;
                    "diskPartitionStartingOffset"=$diskPartitionStartingOffset;
                    "wmiValue"=$wmiValue.uValue}

            }
        }      
    }

   return $MountPointRegistryInformation
}

此代码应该为每个签名返回一个哈希表,其中包含与mountedDevice关联的磁盘的磁盘驱动器签名。它还返回DiskPartitionStartingOffset,它与与mountedDevice相关联的partition.StartingOffset相同。

如果你想自己编写代码,这个注册表SYSTEM \ MountedDevices值的前4个字节是磁盘驱动器签名,但要注意little-endian。接下来的8个字节是PartitionStartingOffset。

使用此信息,您可以使用WMI获取磁盘驱动器信息并将所有内容插入到一起,以便获得与您拥有的所有物理驱动器相关的所有卷,而不管它们是如何安装的。

这对跨区音量不起作用。

在那种注册表中玩非常小心

答案 3 :(得分:0)

检查Win32_LogicalDisktoPartition这将为您提供逻辑磁盘到Totecedent中该磁盘上的物理磁盘和分区的映射。只获取每个磁盘驱动器的标签

 gwmi win32_volume | select name,label

答案 4 :(得分:0)

这是另一种使用内核的替代方案。 Microsoft建议再次强调但它已经证明可以非常有效地捕获跨越的卷,挂载点和其他卷类型信息,以帮助关联磁盘和卷。

 $scriptBlockInvokeCommandKernel32 = {
    param([array]$arrayOfVolumeSerial)

    $cSharpCodeKernel32GetDisk = @"
        using System;
        using Microsoft.Win32.SafeHandles;
        using System.IO;
        using System.Runtime.InteropServices;


        public class GetDisk
        {
            private const uint IoctlVolumeGetVolumeDiskExtents = 0x560000;
            private const uint HASMOREDATA = 234;
            // 4 rounded to 8 + 8 + 8= 24
            [StructLayout(LayoutKind.Sequential)]
            public struct DiskExtent
            {
                public int DiskNumber;
                public Int64 StartingOffset;
                public Int64 ExtentLength;
            }

            //size 4 rounded to 8 + number of extends * 24
            [StructLayout(LayoutKind.Sequential)]
            public struct DiskExtents
            {
                public int numberOfExtents;
                public DiskExtent extents;
            }
            //4
            [StructLayout(LayoutKind.Sequential)]
            public struct DiskExtentsBeforeArray
            {
                public int numberOfExtents;
            }

            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern SafeFileHandle CreateFile(
                string lpFileName,
                [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess,
                [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
                IntPtr lpSecurityAttributes,
                [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
                [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
                IntPtr hTemplateFile
            );

            [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
            private static extern bool DeviceIoControl(
                SafeFileHandle hDevice,
                uint IoControlCode,
                [MarshalAs(UnmanagedType.AsAny)] [In] object InBuffer,
                uint nInBufferSize,
                ref DiskExtents OutBuffer,
                int nOutBufferSize,
                ref uint pBytesReturned,
                IntPtr Overlapped
            );

            [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
            private static extern bool DeviceIoControl(
                SafeFileHandle hDevice,
                uint IoControlCode,
                [MarshalAs(UnmanagedType.AsAny)] [In] object InBuffer,
                uint nInBufferSize,
                IntPtr outBuffer,
                int nOutBufferSize,
                ref uint pBytesReturned,
                IntPtr Overlapped
            );


            [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
            private static extern int GetLastError();

            public static DiskExtent[] GetPhysicalDriveString(string path)
            {
                DiskExtent[] diskExtent = null;
                path = path.TrimEnd('\\');
                if (!path.StartsWith(@"\\.\"))
                    path = @"\\.\" + path;

                SafeFileHandle safeFileHandle = CreateFile(path, FileAccess.Read, FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.Open, 0,
                IntPtr.Zero);
                if (safeFileHandle.IsInvalid)
                {
                    Exception e = Marshal.GetExceptionForHR(Marshal.GetLastWin32Error());
                }

                uint bytesReturned = new uint();
                DiskExtents VOLUME_DISK_EXTENTS = new DiskExtents();
                bool result = DeviceIoControl(
                    safeFileHandle,
                    IoctlVolumeGetVolumeDiskExtents,
                    IntPtr.Zero,
                    0,
                    ref VOLUME_DISK_EXTENTS,
                    Marshal.SizeOf(VOLUME_DISK_EXTENTS),
                    ref bytesReturned,
                    IntPtr.Zero);

                if (result)
                {
                    diskExtent = new DiskExtent[1];
                    diskExtent[0] = VOLUME_DISK_EXTENTS.extents; 
                }
                else
                {
                    int numberOfExtents = VOLUME_DISK_EXTENTS.numberOfExtents;
                    int lastError = GetLastError();

                    if (lastError == HASMOREDATA)
                    {
                        int size = 8 + 24 * numberOfExtents;
                        uint bytesReturned2 = new uint();

                        IntPtr blob = default(IntPtr);
                        blob = Marshal.AllocHGlobal(size);
                        bool resultMutipleDiskExtent = DeviceIoControl(
                            safeFileHandle,
                            IoctlVolumeGetVolumeDiskExtents,
                            IntPtr.Zero,
                            0,
                            blob,
                            (int)size,
                            ref bytesReturned2,
                            IntPtr.Zero
                        );

                        if (resultMutipleDiskExtent)
                        {
                            DiskExtentsBeforeArray lie = default(DiskExtentsBeforeArray);
                            lie = (DiskExtentsBeforeArray)Marshal.PtrToStructure(blob, typeof(DiskExtentsBeforeArray));
                            diskExtent = new DiskExtent[lie.numberOfExtents];
                            for (int i = 0; i <= lie.numberOfExtents - 1; i++)
                            {
                                IntPtr offset = new IntPtr(blob.ToInt64() + 8 + 24 * i);
                                diskExtent[i] = (DiskExtent)Marshal.PtrToStructure(offset, typeof(DiskExtent));
                            }

                        }
                    }
                    else{
                        throw new System.ComponentModel.Win32Exception();
                    }   
                }
                safeFileHandle.Close();
                return diskExtent;
            }
        } 
"@
    $resultOfOperation =@{}
    $volumeKernelInfo =@{} 
    $type = Add-Type -TypeDefinition $cSharpCodeKernel32GetDisk -ErrorAction Continue -ErrorVariable errorAddType -PassThru
    if($errorAddType){
        $resultOfOperation["error"]= ("error at CsharpBuild" + $errorAddType)
    }
    foreach($volumeSerial in $arrayOfVolumeSerial){
        $volumeString = "Volume{" + $volumeSerial + "}"
        $volumeKernelInfo[$volumeSerial] = [GetDisk]::GetPhysicalDriveString($volumeString)
    }
    $resultOfOperation["volumeKernelInfo"]=$volumeKernelInfo

    return $resultOfOperation
}

你可以用:

来调用它
$resultVolumeMappingFromKernel = Invoke-Command -ScriptBlock $scriptBlockInvokeCommandKernel32 -ComputerName $hostName -Credential $credential -ArgumentList (,$arrayOfVolumeSerial)

需要使用管理员帐户在您希望获取信息的远程计算机上运行。

答案 5 :(得分:0)

以下是查德·米勒(Chad Miller)的答案,修改后可与PowerShell Core配合使用,并使用正确的引号和撇号,从而使其实际上可在Linux / Windows上使用,而与术语设置(即是否为UTF-8)无关:

param ($ComputerName)

$partitions = Get-CimInstance -ComputerName $ComputerName Win32_DiskPartition

$partitions |
foreach `
{
  Get-CimInstance -ComputerName $ComputerName `
                  -Query "ASSOCIATORS OF `
                          {Win32_DiskPartition.DeviceID='$($_.DeviceID)'} `
                          WHERE AssocClass=Win32_LogicalDiskToPartition" |
  Add-Member -MemberType NoteProperty PartitionName $_.Name -PassThru |
  Add-Member -MemberType NoteProperty Block $_.BlockSize -PassThru |
  Add-Member -MemberType NoteProperty StartingOffset $_.StartingOffset -PassThru |
  Add-Member -MemberType NoteProperty StartSector ($_.StartingOffset/$_.BlockSize) `
             -PassThru
} |
Select SystemName, Name, PartitionName, Block, StartingOffset, StartSector |
Sort-Object -Property Name # Sort by Drive letter to improve quality of life
# Select code above starting to the left of the hash in this comment