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

问题描述 投票:4回答:6
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。

powershell wmi disk
6个回答
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
投票

这是我创建的完整脚本,用于列出逻辑磁盘,分区和分区偏移量,以检查磁盘对齐问题。 (来源:我的博客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

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获取磁盘驱动器信息并将所有内容连接在一起,以便获得与您拥有的所有物理驱动器相关的所有卷,而不管它们是如何安装的。

这对跨区卷不起作用。

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


0
投票

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

 gwmi win32_volume | select name,label

0
投票

这是使用内核的另一种选择。微软建议它反过来,但它已经证明非常有效地捕获跨越的卷,挂载点和其他卷类型信息,以帮助关联磁盘和卷。

 $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)

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


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
© www.soinside.com 2019 - 2024. All rights reserved.