将Windows磁盘与VMWare VMDK文件匹配

时间:2020-01-09 10:46:49  来源:igfitidea点击:

扩大VMWare虚拟机的磁盘大小或者删除磁盘时,有时很难理解哪个VMware虚拟磁盘与特定的Windows VM磁盘匹配。如果磁盘很少,并且它们的大小不同,则很容易找到所需的磁盘。但是,如果为虚拟机创建了多个相同大小的VMDK(或者RDM)磁盘或者多个虚拟SCSI控制器,该怎么办?如何避免错误并选择Windows管理员要求我们扩展(或者收缩)的磁盘?

在本文中,很好地了解了如何在VMWare VM上匹配Windows磁盘和虚拟磁盘(VMDK)。

如何在Windows和VMWare中获取SCSI设备号?

打开磁盘管理控制台(

diskmgmt.msc

)(在我们的示例中为Windows Server 2015)。 SCSI控制器名称和SCSI设备号未显示在磁盘列表中。要获取SCSI设备号,请右键单击磁盘,然后选择"属性"。如我们所见,有关VMWare虚拟磁盘SCSI磁盘设备的设备端口的信息显示在"常规"选项卡的"位置"字段中。

  • 位置160 = SCSI总线控制器0
  • 目标ID1 =设备SCSI ID为1

加入我们所看到的数据,并获得SCSI磁盘地址:SCSI(0:1)

然后在VMWare vSphere Client中打开虚拟机属性。查找具有与我们获得的ID相同的虚拟设备节点号的磁盘。在我们的示例中,它是" SCSI(0:1)"硬盘2.

如果在虚拟机上配置了具有不同SCSI控制器的多个虚拟磁盘(我们最多可以将4个SCSI控制器(每个磁盘有16个磁盘)添加到虚拟机),那么手动查找SCSI设备号将是非常困难的。另外请注意,Windows和VMWare中的SCSI控制器编号可能会有所不同。

如何使用PowerShell通过UUID /序列号将Windows磁盘与VMDK匹配?

将VMWare虚拟磁盘映射到来宾VM中的磁盘的另一种方法是比较其唯一的磁盘ID。在VMWare中,此属性称为" UUID"(唯一ID),在Windows中,此属性称为"序列号"。让我们看看如何使用PowerShell获取虚拟磁盘的UUID和序列号。

默认情况下,所有VMWare VM都有磁盘

EnableUUID=TRUE

参数已启用。这意味着来宾操作系统必须看到虚拟磁盘ID。

要获取有关Windows中磁盘的信息,可以使用存储模块cmdlet或者WMI查询。由于我们仍然有一些运行Windows Server 2008 R2的VM没有存储模块,因此我们将使用WMI。

要获取SCSI控制器号,其上的SCSI设备号,虚拟磁盘的序列号(SerialNumber/UUID),Windows中的磁盘大小和磁盘号,请运行以下PowerShell命令:

$DiskInfo = foreach ($disk in Get-WmiObject Win32_DiskDrive) {
    [pscustomobject]@{
    "DeviceID"=$disk.DeviceID;
    "Caption"=$disk.Caption;
    "Capacity (GB)"=[math]::Round($disk.size/1GB,0);  
    "SerialNumber" =$disk.SerialNumber
    "SCSIControllerNum"=$disk.scsiport;
    "SCSIDeviceNum"=$disk.scsitargetid;   
    }
}
$DiskInfo|ft

在我们的示例中,Windows检测到了三个磁盘:

  • PHYSICALDRIVE0:SCSI端口0,SCSI目标0,串行6000c2939b157427dadbace321ed4973
  • PHYSICALDRIVE1:SCSI端口0,SCSI目标1,串行6000c2950ee961954909938642bb03b4
  • PHYSICALDRIVE1:SCSI端口4,SCSI目标10,序列号6000c2995fc3c4928d6650596bb02cef

然后,让我们尝试获取在VMWare虚拟机的设置中指定的磁盘的SCSI控制器编号和UUID。要查看VM设置,请使用PowerCLI控制台。

Import-Module VMware.VimAutomation.Core -ErrorAction SilentlyContinue
connect-viserver ber-vmware1 

$vmName="ber-man01"
$vmHardDisks = Get-VM -Name $vmName | Get-HardDisk 
$vmDatacenterView = Get-VM -Name $vmName | Get-Datacenter | Get-View 
$virtualDiskManager = Get-View -Id VirtualDiskManager-virtualDiskManager 

$vmresults = @()  
foreach ($vmHardDisk in $vmHardDisks)  
{  
  $string = $vmHardDisk.Filename
  $vmHardDiskUuid = ($vmHardDisk.ExtensionData.Backing.Uuid | ForEach-Object {$_.replace(' ','').replace('-','')})
  $vmresult = "" | Select-Object vmHardDiskDatastore,vmHardDiskVmdk,vmHardDiskName,vmHardDiskSize,vmHardDiskUuid
  $vmresult.vmHardDiskDatastore = $vmHardDisk.filename.split(']')[0].split('[')[1]  
  $vmresult.vmHardDiskVmdk = $vmHardDisk.filename.split(']')[1].trim()  
  $vmresult.vmHardDiskName = $vmHardDisk.Name
  $vmresult.vmHardDiskSize = $vmHardDisk.CapacityGB
  $vmresult.vmHardDiskUuid = $vmHardDiskUuid    
  $vmresults += $vmresult  
}
$vmresults | ft

该脚本将连接到vCenter(或者ESXi)服务器,并获取指定VM的磁盘列表。结果必须包含数据存储名称,VMDK文件路径,磁盘号,磁盘大小和UUID。

然后,我们可以通过其UUID手动将在来宾Windows操作系统中看到的磁盘与VMWare虚拟磁盘进行匹配。

如果我们在VM的来宾OS中具有管理员权限,则可以使用更方便的PowerShell脚本来匹配Windows磁盘和VMWare VMDK文件。该脚本通过网络连接来宾Windows操作系统,收集有关其本地磁盘的信息,并将其与VMWare VMDK匹配。

这是PowerShell脚本的完整代码:

Import-Module VMware.VimAutomation.Core -ErrorAction SilentlyContinue
connect-viserver ber-vmware1
$vmName = "ber-man01"
$WinHostName = "ber-mansrv01.theitroad.local"
#Get the list of disks of a VMWare virtual machine
$vmDisks = Get-VM -Name $vmName | Get-HardDisk 
$vmDatacenterView = Get-VM -Name $vmName | Get-Datacenter | Get-View 
$virtualDiskManager = Get-View -Id VirtualDiskManager-virtualDiskManager 
# Enter the administrator credentials to access the guest Windows
$cred = if ($cred){$cred}else{Get-Credential}  
# Getting the list of Windows disks and partitions using WMI
$winDisk  = Get-WmiObject -Class Win32_DiskDrive -ComputerName $WinHostName -Credential $cred
$diskToDriveVolume = Get-WmiObject Win32_DiskDrive -ComputerName $WinHostName -Credential $cred| % {
  $disk = $_
  $partitions = "ASSOCIATORS OF " +
                "{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " +
                "WHERE AssocClass = Win32_DiskDriveToDiskPartition"
  Get-WmiObject -Query $partitions -ComputerName $WinHostName -Credential $cred| % {
    $partition = $_
    $drives = "ASSOCIATORS OF " +
              "{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " +
              "WHERE AssocClass = Win32_LogicalDiskToPartition"
    Get-WmiObject -Query $drives  -ComputerName $WinHostName -Credential $cred| % {
      New-Object -Type PSCustomObject -Property @{
        Disk        = $disk.DeviceID
        DriveLetter = $_.DeviceID
        VolumeName  = $_.VolumeName
       }
    }
  }
}
 #Getting a disk serial number 
foreach ($disk in $winDisk)  
{  
  $disk | Add-Member -MemberType NoteProperty -Name AltSerialNumber -Value $null 
  $diskSerialNumber = $disk.SerialNumber  
  if ($disk.Model -notmatch 'VMware Virtual disk SCSI Disk Device')  
  {  
    if ($diskSerialNumber -match '^\S{12}$'){$diskSerialNumber = ($diskSerialNumber | foreach {[byte[]]$bytes = $_.ToCharArray(); $bytes | foreach {$_.ToString('x2')} }  ) -join ''}  
    $disk.AltSerialNumber = $diskSerialNumber 
  }  
}  
#Searching all VM disks and matching them with Windows disks by their SerialNumber/UUID
$diskMaps = @()  
foreach ($vmDisk in $vmDisks)  
{  
  $vmDiskUuid = $virtualDiskManager.queryvirtualdiskuuid($vmDisk.Filename, $vmDatacenterView.MoRef) | foreach {$_.replace(' ','').replace('-','')}  
  $windowsDisk = $winDisk | where {$_.SerialNumber -eq $vmDiskUuid}  
  if (-not $windowsDisk){$windowsDisk = $winDisk | where {$_.AltSerialNumber -eq $vmDisk.ScsiCanonicalName.substring(12,24)}}  
  $curDiskMap = "" | select  vmDiskDatastore, vmDiskVmdk, vmDiskName, windowsDiskIndex,  vmDiskUuid, windowsDeviceID, drives, volumes  
  $curDiskMap.vmDiskDatastore = $vmDisk.filename.split(']')[0].split('[')[1]  
  $curDiskMap.vmDiskVmdk = $vmDisk.filename.split(']')[1].trim()  
  $curDiskMap.vmDiskName = $vmDisk.Name  
  $curDiskMap.windowsDiskIndex = if ($windowsDisk){$windowsDisk.Index}else{"FAILED TO MATCH"}  
  $curDiskMap.vmDiskUuid = $vmDiskUuid  
  $curDiskMap.windowsDeviceID = if ($windowsDisk){$windowsDisk.DeviceID}else{"FAILED TO MATCH"}  
  $driveVolumes = $diskToDriveVolume | where {$_.Disk -eq $windowsDisk.DeviceID}
  $curDiskMap.drives = $driveVolumes.DriveLetter
  $curDiskMap.volumes = $driveVolumes.VolumeName
  $diskMaps += $curDiskMap
}  
$diskMaps = $diskMaps | sort {[int]$_.vmDiskName.split(' ')[2]}  
$diskMaps | ft

该脚本还返回有关Windows中驱动器号和卷标的信息。

现在,我们可以轻松找到与给定虚拟vmdk磁盘匹配的Windows磁盘。

如果Windows中的虚拟磁盘是通过安装点连接的,则输出中将没有有关分配的驱动器号和卷标的信息。