Hi,
I've written the script below but it works fine except it doesn't create the RDM mapping file.
If I comment out the following lines it works fine.
$fileMgr.DeleteDatastoreFile_Task($name, $datacenter)
$spec.deviceChange[0].fileOperation = "create"
Here's the code below
Function Replace-VM-RDM {
param($vmname, $scsiid, $rdmname, $filename)
<#
Convert the SCSI address in to Vmware format
#>
$scsicontroller=$null
$scsiid_split=$null
$scsiid_split=$scsiid.split(":")
$scsicontroller=($scsiid_split[0])
# VMware SCSI controller ID in gui is one number higher than the actual controller id
$scsicontroller=[int]$scsicontroller+1
# Vmware expects a conntroller id with 4 chars
$scsicontroller=($scsicontroller.ToString())+"000"
$scsicontroller
# SCSI LUN
$scsilun=$null
# VMware SCSI LUN ID in gui is one number higher than the actual lun id
$scsilun=[int]($scsiid_split[1])#+1
###
$vm = Get-VM -Name "$vmname" | Get-View
IF (!($filename)){
$RDMFile=$rdmname.split(" ")[0]+"_RDM.vmdk"
$filename=(($vm.Config.Files.VmPathName).Replace("$vmname.vmx","$RDMFile"))
}
$esx = Get-View $vm.Runtime.Host
<#
Get CanonicalName for RDM LUN
#>
$rdmCanonicalName=$null
$rdmCanonicalName=(($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).CanonicalName)
$rdmDevicePath=(($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).DevicePath)
foreach($dev in $vm.Config.Hardware.Device){
if(($dev.gettype()).Name -eq "VirtualDisk"){
if(($dev.Backing.CompatibilityMode -eq "physicalMode") -or
($dev.Backing.CompatibilityMode -eq "virtualMode")){
if (($dev.ControllerKey -eq "$scsicontroller") -and ($dev.UnitNumber -eq "$scsilun")) {
# Remove Harddisk
$hd=get-harddisk $vm.name | where {$_.Filename -eq $dev.Backing.FileName}
$hd | remove-harddisk -confirm:$false
Write-Host "Filename: "$dev.backing.fileName
Write-Host "Disk Mode: "$dev.backing.diskMode
$dev.backing.deviceName
$dev.backing.lunUuid
$DevKey=$dev.key
$CapacityInKB=$dev.CapacityInKB
$fileMgr = Get-View (Get-View ServiceInstance).Content.fileManager
$datacenter = (Get-View (Get-VM $VMname | Get-Datacenter).ID).get_MoRef()
foreach($disk in $vm.LayoutEx.Disk){
if($disk.Key -eq $dev.Key){
foreach($chain in $disk.Chain){
foreach($file in $chain.FileKey){
$name = $vm.LayoutEx.File[$file].Name
$fileMgr.DeleteDatastoreFile_Task($name, $datacenter)
}
}
continue
}
}
}
}
Elseif (($dev.ControllerKey -eq "$scsicontroller") -and ($dev.UnitNumber -eq "$scsilun")) {Write-Host "Selected SCSI Address [$scsiid] is not a RDM"}
}
}
#$hd1 = New-HardDisk -VM $vmname -DeviceName $rdmDevicePath -DiskType RawPhysical # this line works
$spec=$null
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.deviceChange = @()
$spec.deviceChange += New-Object VMware.Vim.VirtualDeviceConfigSpec
$spec.deviceChange[0].device = New-Object VMware.Vim.VirtualDisk
$spec.devicechange[0].device.capacityInKB=$CapacityInKB
$spec.deviceChange[0].device.backing = New-Object VMware.Vim.VirtualDiskRawDiskMappingVer1BackingInfo
$spec.deviceChange[0].device.backing.fileName=$filename
$spec.deviceChange[0].device.backing.compatibilityMode ="physicalMode"
$spec.deviceChange[0].device.backing.diskMode = ""
$spec.deviceChange[0].device.backing.lunUuid=(($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).Uuid)
$spec.deviceChange[0].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
$spec.deviceChange[0].device.connectable.startConnected = $true
$spec.deviceChange[0].device.connectable.allowGuestControl = $false
$spec.deviceChange[0].device.connectable.connected = $true
# Take next unused device key for HD
$spec.deviceChange[0].device.key = $DevKey + 1
# The UnitNUmber SCSIID 7 is reserved for the Controller - so skip to 8.
if ($scsilun -eq 6) {$scsilun = $scsilun + 1}
# Take next unit number for HD
$spec.deviceChange[0].device.unitnumber = $scsilun
# SCSI controller device key
$spec.deviceChange[0].device.controllerKey = $scsicontroller
# Create vmdk file
$spec.deviceChange[0].fileOperation = "create"
$spec.deviceChange[0].operation = "add"
$vm = Get-View (Get-VM $VMname).ID
$vm.ReconfigVM_Task($spec)
}
Replace-VM-RDM $vmname $scsiid $rdmname $filename
I got it working, it just needed re-ordering and then the Devicename was wrong.
Here's the working script.
Function Replace-VM-RDM {
param($vmname, $scsiid, $rdmname, $filename)
<#
Convert the SCSI address in to Vmware format
#>
$scsicontroller=$null
$scsiid_split=$null
$scsiid_split=$scsiid.split(":")
$scsicontroller=($scsiid_split[0])
# VMware SCSI controller ID in gui is one number higher than the actual controller id
$scsicontroller=[int]$scsicontroller+1
# Vmware expects a conntroller id with 4 chars
$scsicontroller=($scsicontroller.ToString())+"000"
$scsicontroller
# SCSI LUN
$scsilun=$null
# VMware SCSI LUN ID in gui is one number higher than the actual lun id
$scsilun=[int]($scsiid_split[1])#+1
###
$vm = Get-VM -Name "$vmname" | Get-View
IF (!($filename)){
$RDMFile=$rdmname.split(" ")[0]+"_RDM.vmdk"
$filename=(($vm.Config.Files.VmPathName).Replace("$vmname.vmx","$RDMFile"))
}
$esx = Get-View $vm.Runtime.Host
<#
Get CanonicalName for RDM LUN
#>
$rdmCanonicalName=$null
$rdmCanonicalName=(($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).CanonicalName)
$rdmDevicePath=(($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).DevicePath)
foreach($dev in $vm.Config.Hardware.Device){
if(($dev.gettype()).Name -eq "VirtualDisk"){
if(($dev.Backing.CompatibilityMode -eq "physicalMode") -or
($dev.Backing.CompatibilityMode -eq "virtualMode")){
if (($dev.ControllerKey -eq "$scsicontroller") -and ($dev.UnitNumber -eq "$scsilun")) {
# Remove Harddisk
$hd=get-harddisk $vm.name | where {$_.Filename -eq $dev.Backing.FileName}
$hd | remove-harddisk -confirm:$false -DeletePermanently
Write-Host "Filename: "$dev.backing.fileName
Write-Host "Disk Mode: "$dev.backing.diskMode
$dev.backing.deviceName
$dev.backing.lunUuid
$DevKey=$dev.key
$CapacityInKB=$dev.CapacityInKB
<#$fileMgr = Get-View (Get-View ServiceInstance).Content.fileManager
$datacenter = (Get-View (Get-VM $VMname | Get-Datacenter).ID).get_MoRef()
foreach($disk in $vm.LayoutEx.Disk){
if($disk.Key -eq $dev.Key){
foreach($chain in $disk.Chain){
foreach($file in $chain.FileKey){
$name = $vm.LayoutEx.File[$file].Name
$fileMgr.DeleteDatastoreFile_Task($name, $datacenter)
}
}
continue
}
}#>
}
}
Elseif (($dev.ControllerKey -eq "$scsicontroller") -and ($dev.UnitNumber -eq "$scsilun")) {Write-Host "Selected SCSI Address [$scsiid] is not a RDM"}
}
}
#$hd1 = New-HardDisk -VM $vmname -DeviceName $rdmDevicePath -DiskType RawPhysical # this line works
$spec=$null
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec[] (1)
$spec.deviceChange[0] = New-Object VMware.Vim.VirtualDeviceConfigSpec
# Create vmdk file
$spec.deviceChange[0].fileOperation = "create"
$spec.deviceChange[0].operation = "add"
$spec.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec[] (1)
$spec.deviceChange[0] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$spec.deviceChange[0].operation = "add"
$spec.deviceChange[0].fileOperation = "create"
$spec.deviceChange[0].device = New-Object VMware.Vim.VirtualDisk
$spec.deviceChange[0].device.key = -100
$spec.deviceChange[0].device.backing = New-Object VMware.Vim.VirtualDiskRawDiskMappingVer1BackingInfo
$spec.deviceChange[0].device.backing.fileName = "$filename"
$spec.deviceChange[0].device.backing.deviceName = (($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).DevicePath)
$spec.deviceChange[0].device.backing.compatibilityMode = "physicalMode"
$spec.deviceChange[0].device.backing.diskMode = ""
$spec.deviceChange[0].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
$spec.deviceChange[0].device.connectable.startConnected = $true
$spec.deviceChange[0].device.connectable.allowGuestControl = $false
$spec.deviceChange[0].device.connectable.connected = $true
# SCSI controller device key
$spec.deviceChange[0].device.controllerKey = [int]$scsicontroller
# The UnitNUmber SCSIID 7 is reserved for the Controller - so skip to 8.
if ($scsilun -eq 6) {$scsilun = $scsilun + 1}
# Take next unit number for HD
$spec.deviceChange[0].device.unitnumber = [int]$scsilun
$spec.deviceChange[0].device.capacityInKB = [int]$CapacityInKB
$vm = Get-View (Get-VM $VMname).ID
$vm.ReconfigVM($spec)
}
Replace-VM-RDM $vmname $scsiid $rdmname $filename
Some questions:
Can you try those changes and see if that makes your function behave like you intend it to do ?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks for the response,
This script is only part one of the script that I'm writing, in the end it will do the following
1. Remove-RDM from TMPVM, this is a VM that is online at my DR site and is used a file dump location
2. Delete RDM vmdk header file
3. Remove broken RDM from SQL Cluster node
4. Create RDM vmdk header file and attach to SQL Cluster node using correct SCSI ID
At the moment i just need it to do step 1,2,4 but mounting on the same VM.
I'm doing this as SRM doesn't like mounting the vmdk that is setup on the TMPVM , even though i suspend the TMPVM thus freeing up the lock. I ended up needed to manually do it via the GUI and that works fine.
I've added the DeletePermanently switch to Remove-Hardisk and removed the _task from $vm.ReconfigVM. The difference now it that it throws the error to the powershell window instead of the vi client task window.
Below is the error that is being reported.
Exception calling "ReconfigVM" with "1" argument(s): "Incompatible device backing specified for device '0'."
At line:92 char:19
+ $vm.ReconfigVM <<<< ($spec)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
That error was there, but you didn't see it because the method call was done in the background.
Did you get rid of the DeleteDatastoreFile call as well, now that you have the Remove-Harddisk ammended with the DeletePermanently switch ?
As a matter of fact you can get rid of the call(s) to the ReconfigVM method as well, by using a New-Harddisk cmdlet.
With the DeviceName and the ScsiController parameters you can replace all the functionality from the ReconfigVM method call.
Most, if not all, of your code can be replaced by a call to Remove-Harddisk and New-Harddisk.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Yes, i did originally start using the Remove-Hardisk and New-Hardisk, but the New-Harddisk wouldn't let me select a different scsi id, as it was always using the next available one.
This is why I ended up writing the script.
Here's the script at the moment
Function Replace-VM-RDM {
param($vmname, $scsiid, $rdmname, $filename)
<#
Convert the SCSI address in to Vmware format
#>
$scsicontroller=$null
$scsiid_split=$null
$scsiid_split=$scsiid.split(":")
$scsicontroller=($scsiid_split[0])
# VMware SCSI controller ID in gui is one number higher than the actual controller id
$scsicontroller=[int]$scsicontroller+1
# Vmware expects a conntroller id with 4 chars
$scsicontroller=($scsicontroller.ToString())+"000"
$scsicontroller
# SCSI LUN
$scsilun=$null
# VMware SCSI LUN ID in gui is one number higher than the actual lun id
$scsilun=[int]($scsiid_split[1])#+1
###
$vm = Get-VM -Name "$vmname" | Get-View
IF (!($filename)){
$RDMFile=$rdmname.split(" ")[0]+"_RDM.vmdk"
$filename=(($vm.Config.Files.VmPathName).Replace("$vmname.vmx","$RDMFile"))
}
$esx = Get-View $vm.Runtime.Host
<#
Get CanonicalName for RDM LUN
#>
$rdmCanonicalName=$null
$rdmCanonicalName=(($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).CanonicalName)
$rdmDevicePath=(($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).DevicePath)
foreach($dev in $vm.Config.Hardware.Device){
if(($dev.gettype()).Name -eq "VirtualDisk"){
if(($dev.Backing.CompatibilityMode -eq "physicalMode") -or
($dev.Backing.CompatibilityMode -eq "virtualMode")){
if (($dev.ControllerKey -eq "$scsicontroller") -and ($dev.UnitNumber -eq "$scsilun")) {
# Remove Harddisk
$hd=get-harddisk $vm.name | where {$_.Filename -eq $dev.Backing.FileName}
$hd | remove-harddisk -confirm:$false -DeletePermanently
Write-Host "Filename: "$dev.backing.fileName
Write-Host "Disk Mode: "$dev.backing.diskMode
$dev.backing.deviceName
$dev.backing.lunUuid
$DevKey=$dev.key
$CapacityInKB=$dev.CapacityInKB
<#$fileMgr = Get-View (Get-View ServiceInstance).Content.fileManager
$datacenter = (Get-View (Get-VM $VMname | Get-Datacenter).ID).get_MoRef()
foreach($disk in $vm.LayoutEx.Disk){
if($disk.Key -eq $dev.Key){
foreach($chain in $disk.Chain){
foreach($file in $chain.FileKey){
$name = $vm.LayoutEx.File[$file].Name
$fileMgr.DeleteDatastoreFile_Task($name, $datacenter)
}
}
continue
}
}#>
}
}
Elseif (($dev.ControllerKey -eq "$scsicontroller") -and ($dev.UnitNumber -eq "$scsilun")) {Write-Host "Selected SCSI Address [$scsiid] is not a RDM"}
}
}
#$hd1 = New-HardDisk -VM $vmname -DeviceName $rdmDevicePath -DiskType RawPhysical # this line works
$spec=$null
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.deviceChange = @()
$spec.deviceChange += New-Object VMware.Vim.VirtualDeviceConfigSpec
$spec.deviceChange[0].device = New-Object VMware.Vim.VirtualDisk
$spec.devicechange[0].device.capacityInKB=$CapacityInKB
$spec.deviceChange[0].device.backing = New-Object VMware.Vim.VirtualDiskRawDiskMappingVer1BackingInfo
$spec.deviceChange[0].device.backing.fileName=$filename
$spec.deviceChange[0].device.backing.compatibilityMode ="physicalMode"
$spec.deviceChange[0].device.backing.diskMode = ""
$spec.deviceChange[0].device.backing.lunUuid=(($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).Uuid)
$spec.deviceChange[0].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
$spec.deviceChange[0].device.connectable.startConnected = $true
$spec.deviceChange[0].device.connectable.allowGuestControl = $false
$spec.deviceChange[0].device.connectable.connected = $true
# Take next unused device key for HD
$spec.deviceChange[0].device.key = $DevKey + 1
# The UnitNUmber SCSIID 7 is reserved for the Controller - so skip to 8.
if ($scsilun -eq 6) {$scsilun = $scsilun + 1}
# Take next unit number for HD
$spec.deviceChange[0].device.unitnumber = $scsilun
# SCSI controller device key
$spec.deviceChange[0].device.controllerKey = $scsicontroller
# Create vmdk file
$spec.deviceChange[0].fileOperation = "create"
$spec.deviceChange[0].operation = "add"
$vm = Get-View (Get-VM $VMname).ID
$vm.ReconfigVM($spec)
}
Replace-VM-RDM $vmname $scsiid $rdmname $filename
I got it working, it just needed re-ordering and then the Devicename was wrong.
Here's the working script.
Function Replace-VM-RDM {
param($vmname, $scsiid, $rdmname, $filename)
<#
Convert the SCSI address in to Vmware format
#>
$scsicontroller=$null
$scsiid_split=$null
$scsiid_split=$scsiid.split(":")
$scsicontroller=($scsiid_split[0])
# VMware SCSI controller ID in gui is one number higher than the actual controller id
$scsicontroller=[int]$scsicontroller+1
# Vmware expects a conntroller id with 4 chars
$scsicontroller=($scsicontroller.ToString())+"000"
$scsicontroller
# SCSI LUN
$scsilun=$null
# VMware SCSI LUN ID in gui is one number higher than the actual lun id
$scsilun=[int]($scsiid_split[1])#+1
###
$vm = Get-VM -Name "$vmname" | Get-View
IF (!($filename)){
$RDMFile=$rdmname.split(" ")[0]+"_RDM.vmdk"
$filename=(($vm.Config.Files.VmPathName).Replace("$vmname.vmx","$RDMFile"))
}
$esx = Get-View $vm.Runtime.Host
<#
Get CanonicalName for RDM LUN
#>
$rdmCanonicalName=$null
$rdmCanonicalName=(($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).CanonicalName)
$rdmDevicePath=(($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).DevicePath)
foreach($dev in $vm.Config.Hardware.Device){
if(($dev.gettype()).Name -eq "VirtualDisk"){
if(($dev.Backing.CompatibilityMode -eq "physicalMode") -or
($dev.Backing.CompatibilityMode -eq "virtualMode")){
if (($dev.ControllerKey -eq "$scsicontroller") -and ($dev.UnitNumber -eq "$scsilun")) {
# Remove Harddisk
$hd=get-harddisk $vm.name | where {$_.Filename -eq $dev.Backing.FileName}
$hd | remove-harddisk -confirm:$false -DeletePermanently
Write-Host "Filename: "$dev.backing.fileName
Write-Host "Disk Mode: "$dev.backing.diskMode
$dev.backing.deviceName
$dev.backing.lunUuid
$DevKey=$dev.key
$CapacityInKB=$dev.CapacityInKB
<#$fileMgr = Get-View (Get-View ServiceInstance).Content.fileManager
$datacenter = (Get-View (Get-VM $VMname | Get-Datacenter).ID).get_MoRef()
foreach($disk in $vm.LayoutEx.Disk){
if($disk.Key -eq $dev.Key){
foreach($chain in $disk.Chain){
foreach($file in $chain.FileKey){
$name = $vm.LayoutEx.File[$file].Name
$fileMgr.DeleteDatastoreFile_Task($name, $datacenter)
}
}
continue
}
}#>
}
}
Elseif (($dev.ControllerKey -eq "$scsicontroller") -and ($dev.UnitNumber -eq "$scsilun")) {Write-Host "Selected SCSI Address [$scsiid] is not a RDM"}
}
}
#$hd1 = New-HardDisk -VM $vmname -DeviceName $rdmDevicePath -DiskType RawPhysical # this line works
$spec=$null
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec[] (1)
$spec.deviceChange[0] = New-Object VMware.Vim.VirtualDeviceConfigSpec
# Create vmdk file
$spec.deviceChange[0].fileOperation = "create"
$spec.deviceChange[0].operation = "add"
$spec.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec[] (1)
$spec.deviceChange[0] = New-Object VMware.Vim.VirtualDeviceConfigSpec
$spec.deviceChange[0].operation = "add"
$spec.deviceChange[0].fileOperation = "create"
$spec.deviceChange[0].device = New-Object VMware.Vim.VirtualDisk
$spec.deviceChange[0].device.key = -100
$spec.deviceChange[0].device.backing = New-Object VMware.Vim.VirtualDiskRawDiskMappingVer1BackingInfo
$spec.deviceChange[0].device.backing.fileName = "$filename"
$spec.deviceChange[0].device.backing.deviceName = (($esx.Config.StorageDevice.ScsiLun | where {$_.DisplayName -eq $rdmname}).DevicePath)
$spec.deviceChange[0].device.backing.compatibilityMode = "physicalMode"
$spec.deviceChange[0].device.backing.diskMode = ""
$spec.deviceChange[0].device.connectable = New-Object VMware.Vim.VirtualDeviceConnectInfo
$spec.deviceChange[0].device.connectable.startConnected = $true
$spec.deviceChange[0].device.connectable.allowGuestControl = $false
$spec.deviceChange[0].device.connectable.connected = $true
# SCSI controller device key
$spec.deviceChange[0].device.controllerKey = [int]$scsicontroller
# The UnitNUmber SCSIID 7 is reserved for the Controller - so skip to 8.
if ($scsilun -eq 6) {$scsilun = $scsilun + 1}
# Take next unit number for HD
$spec.deviceChange[0].device.unitnumber = [int]$scsilun
$spec.deviceChange[0].device.capacityInKB = [int]$CapacityInKB
$vm = Get-View (Get-VM $VMname).ID
$vm.ReconfigVM($spec)
}
Replace-VM-RDM $vmname $scsiid $rdmname $filename
Great
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference