如何根据磁盘路径确定数据存储?

时间:2016-04-14 17:41:25

标签: powershell powercli

任何vmware powershell的人都在那里?我希望有人可以帮助我。有没有一种简单的方法可以向我显示服务器上连接磁盘的驱动器标签,以及该磁盘所在的数据存储区?例如,我们有一个带有挂载点的SQL Server,名为“SQL01 \ Tlog”,现在我该如何找到磁盘所在的数据存储? 此命令显示每个磁盘的路径: (get-vm Computername).Guest.Disks 此命令显示服务器上的数据存储: get-vm Computername |获取的数据存储 我该怎么做才能看到路径和数据存储区一起?

1 个答案:

答案 0 :(得分:0)

过去我必须以可靠的方式将VM的虚拟磁盘与操作系统的磁盘相匹配。假设VM配置中的第一个磁盘是OS中的第一个磁盘是不安全的。下面的方法尝试首先根据序列号匹配磁盘。如果失败,它还会尝试匹配SCSI目标ID。给定一台计算机,其主机名和VM名称为$ CN ......

#define the computer & VM name
$CN = 'mycomputer'

#get OS disk information
$GWOsplat = `
  @{computername = $CN
  class = 'win32_diskdrive'
  erroraction = [system.management.automation.actionpreference]::stop}
$OSdisk = get-WMIobject @GWOsplat

#get VM disk information
$GVsplat = `
  @{viewtype = ([VMware.VIM.virtualmachine])
  filter = @{name="^$CN`$"}
  property = @('name','config.hardware.device')
  erroraction = [system.management.automation.actionpreference]::stop}
$VM = get-view @GVsplat
$VMdisk = $VM.config.hardware.device | where-object {$_.deviceinfo.label -like 'hard disk*'}

#get the number of SCSI controllers
$controllercount = ($VMdisk.controllerkey | group-object | measure-object).count

#iterate through VM disks
foreach($VMD in $VMdisk)
{
  #get VM disk serial number and SCSI target ID
  $VMDSN = $VMD.backing.UUID -replace '-',''
  $VMDSID = $VMD.unitnumber

  #iterate through operating system disks
  foreach($OSD in $OSdisk)
  {
    #get OS disk serial number and SCSI target ID
    $OSDSN = $OSD.serialnumber
    $OSDSID = $OSD.SCSItargetID
    if(($VMDSN -eq $OSDSN) -or (($controllercount -eq 1) -and ($VMDSID -eq $OSDSID)))
    {
      #matching OSdisk found

      #get datastore
      $DS = get-datastore -ID $VMD.backing.datastore

      #get partitions within OSdisk
      $GWOsplat = `
        @{computername = $CN
        query = "associators of {win32_diskdrive.deviceID='$($OSD.deviceID)'} WHERE resultrole=dependent"
        erroraction = [system.management.automation.actionpreference]::stop}
      $partition = get-WMIobject @GWOsplat

      #get logicaldisks within partitions
      foreach($P in $partition)
      {
        $GWOsplat = `
          @{computername = $CN
          query = "associators of {win32_diskpartition.deviceID='$($P.deviceID)'} WHERE resultrole=dependent"
          erroraction = [system.management.automation.actionpreference]::stop}
        $logicaldisk = get-WMIobject @GWOsplat

        #output custom object mapping drive letter to datastore
        foreach($LD in $logicaldisk)
        {
          [PScustomobject] `
            @{computername = $CN
            datastore = $DS
            drive = $LD.deviceID}
        }
      }
      break
    }
  }
}

如果只有一个SCSI控制器,我只尝试SCSI目标ID匹配的原因是我找不到一种可靠的方法来匹配操作系统中的SCSI控制器和VM的SCSI控制器。它应该是一个非常小的缺点,因为大多数磁盘将匹配序列号,并且大多数VM没有多个SCSI控制器。

编辑1

下面是2个功能,“group-volumedisk”和“group-VMOSdisk”。我没有完全评论他们,但他们确实有一些评论,而且他们相当简单。

group-VMOSdisk使用group-volumedisk来获取计算机的win32_volume实例到其win32_diskdrive实例的映射。 group-VMOSdisk主要完成本文第一部分的内容。

function group-volumedisk
{
  [cmdletbinding()]
  param
  (
    [parameter(valuefrompipeline=$true,valuefrompipelinebypropertyname=$true)]
    [alias('CN')]
    [system.string[]]$computername
  )
  begin
  {
    new-variable -option constant -name localhost -value ([system.environment]::machinename)
    new-variable -option constant -name dbgpfx -value "$localhost`: $($myinvocation.mycommand):"
    new-variable -option constant -name dispprop -value @('computername','volume','diskdrive')
    new-variable -option constant -name SB -value `
    {
      begin
      {
        add-type -typedefinition @"
          namespace GDFVNS
          {
            using Microsoft.Win32.SafeHandles;
            using System.Runtime.InteropServices;

            [StructLayout(LayoutKind.Sequential)]
            public struct DiskExtent
            {
              public int DiskNumber;
              public System.Int64 StartingOffset;
              public System.Int64 ExtentLength;
            };

            [StructLayout(LayoutKind.Sequential)]
            public struct DiskExtents
            {
              public int numberOfExtents;
              public DiskExtent first;
            };

            public class GDFVname
            {
              public const uint IoctlVolumeGetVolumeDiskExtents = 0x560000;


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

              [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
              public static extern bool DeviceIoControl(
              SafeFileHandle hDevice,
              uint IoControlCode,
              [MarshalAs(UnmanagedType.AsAny)] [In] object InBuffer,
              uint nInBufferSize,
              ref DiskExtents OutBuffer,
              int nOutBufferSize,
              ref uint pBytesReturned,
              System.IntPtr Overlapped);
            }
          }
"@
      }
      end
      {
        $volume = get-WMIobject -class win32_volume -filter "drivetype = 3"
        foreach($V in $volume)
        {
          # get the volume's path and format it properly
          $path = $V.deviceID
          $path = $path.trimstart('\?')
          $path = $path.trimend('\')
          if($path -notlike '\.\*')
          {
            $path = "\\.\$path"
          }
          "$dbgpfx path ($path)" | write-verbose

          #get a handle to the volume
          $handle = [GDFVNS.GDFVname]::createfile($path,[system.IO.fileaccess]::read,[system.IO.fileshare]::read -bor [system.IO.fileshare]::write,[system.intptr]::zero,[system.IO.filemode]::open,0,[system.intptr]::zero)
          "handle ($($handle | out-string))" | write-verbose
          if($handle.isinvalid)
          {
            $lastAPIerr = [system.runtime.interopservices.marshal]::getlastwin32error()
            "createfile call failed ($lastAPIerr)" | write-error
            continue
          }

          #get disk extents of the volume pointed to by $handle
          $returnbytes = new-object -typename system.Uint32
          $DE = new-object -typename GDFVNS.diskextents
          $result = [GDFVNS.GDFVname]::DeviceIoControl($handle,[GDFVNS.GDFVname]::IoctlVolumeGetVolumeDiskExtents,[system.intptr]::zero,0,[ref]$DE,[system.runtime.interopservices.marshal]::sizeof($DE),[ref]$returnbytes,[system.intptr]::zero)
          "result ($result)" |  write-verbose
          if($result -eq 0)
          {
            $lastAPIerr = [system.runtime.interopservices.marshal]::getlastwin32error()
            "DeviceIoControl call failed ($lastAPIerr)" | write-error
            continue
          }

          #parse the deviceID of the disk and get its win32_diskdrive
          $deviceID = "\\.\PHYSICALDRIVE$($DE.first.DiskNumber)" -replace '\\','\\'
          $diskdrive = get-WMIobject -class win32_diskdrive -filter "deviceID = '$deviceID'"

          #output custom object mapping the win32_volume to its parent win32_diskdrive
          new-object -typename system.management.automation.PSobject -property `
            @{computername = $V.PScomputername
            volume = $V
            diskdrive = $diskdrive}
        }
      }
    }
  }
  process
  {
    foreach($CN in $computername)
    {
      $ICsplat = `
        @{computername = $CN
        scriptblock = $SB
        erroraction = [system.management.automation.actionpreference]::stop}
      try
      {
        invoke-command @ICsplat | select-object -property $dispprop
      }
      catch
      {
        "invoke-command failed`n$_" | write-error
        continue
      }
    }
  }
}
function group-VMOSdisk
{
  [cmdletbinding()]
  param
  (
    [parameter(valuefrompipeline=$true)]
    [alias('CN')]
    [system.string[]]$computername
  )
  begin
  {
    new-variable -option constant -name localhost -value ([system.environment]::machinename)
    new-variable -option constant -name dbgpfx -value "$localhost`: $($myinvocation.mycommand):"
  }
  process
  {
    foreach($CN in $computername)
    {
      #get OS disks
      $GWOsplat = `
        @{computername = $CN
        class = 'win32_diskdrive'
        erroraction = [system.management.automation.actionpreference]::stop}
      $OSdisk = get-WMIobject @GWOsplat

      #get mapping of volumes to disks
      $voldiskmap = $CN | group-volumedisk

      #get VM disks
      $GVsplat = `
        @{viewtype = ([VMware.VIM.virtualmachine])
        filter = @{name="^$CN$"}
        erroraction = [system.management.automation.actionpreference]::stop}
      $VM = get-view @GVsplat
      $VMdisk = $VM.config.hardware.device | where-object {$_.deviceinfo.label -like 'hard disk*'}

      #get SCSI controller count
      $controllercount = ($VMdisk.controllerkey | group-object | measure-object).count

      #iterate through VMdisks
      foreach($VMD in $VMdisk)
      {
        #get the VMdisk serial number and SCSI target ID
        $VMDSN = $VMD.backing.UUID -replace '-',''
        $VMDSID = $VMD.unitnumber
        foreach($OSD in $OSdisk)
        {
          #get the OSdisk serial number and SCSI target ID
          $OSDSN = $OSD.serialnumber
          $OSDSID = $OSD.SCSItargetID
          if(($VMDSN -eq $OSDSN) -or (($controllercount -eq 1) -and ($VMDSID -eq $OSDSID)))
          {
            #matching OSdisk found

            #get datastore
            $DS = get-datastore -ID $VMD.backing.datastore

            #get volumes within this OSdisk
            $volume = ($voldiskmap | where-object {$_.diskdrive.deviceID -eq $OSD.deviceID}).volume

            #output custom object mapping volume to datastore
            foreach($V in $volume)
            {
              [PScustomobject] `
                @{computername = $CN
                datastore = $DS
                volume = $V.name}
            }
            break
          }
        }
      }
    }
  }
}

连接到vSphere服务器,然后将$ CN管道传输到group-VMOSdisk。

group-volumedisk改编自:http://www.powershelladmin.com/wiki/PowerShell_Get-MountPointData_Cmdlet