system_noida
Enthusiast
Enthusiast

Script to add disk on multiple VMs and sharing with other VMs.

Hi All,

I am building a 6 node cluster. I have 6 VMs acting as cluster node. I have to add 10 disk on 1 VM and then I need to shared that disk among other 5 Node vms. Like I add 10 new HDD on Node 1 and once disk created then I am adding the same disk which I created on Node 1 with Other 5 nodes so that the disk can be shared for MS cluster.

I am adding all the disk on Scsi controller 1 which config set as VMParavirtual and Bus Sharing as Physical.

Can some one please help me with a code where I can automate it using a input file which will be having VM names.

0 Kudos
17 Replies
ObjectifDubai
Enthusiast
Enthusiast

Hi,

A few months ago I researched to write a script that allowed me to configure the vms of a SQL cluster by mapping the RDMs to the SCSI controllers 1,2 and 3

I tried below to put you the Important elements

 

Step 1 :

I have a file containing the following information regarding RDMs

 

 

/vmfs/devices/disks/naa.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe160
/vmfs/devices/disks/naa.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe161
/vmfs/devices/disks/naa.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe162
/vmfs/devices/disks/naa.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe163

 

 

 

 

 

Beginning of the Script :

 

 

 

#Traitement des arguments de ligne de commande
param( 
[parameter(Mandatory=$true)][string]$server ,  
[parameter(Mandatory=$false)][string]$user,
[parameter(Mandatory=$false)][string]$password,
[Parameter(Mandatory=$true)][string]$vmprincipal, # Name of the vm to which you added the RDMs
[Parameter(Mandatory=$true)][string[]]$vmsecondaire, # Name of other VMs to which you want to map the RDMs
[Parameter(Mandatory=$true)][string]$datastore, # name of the datastore on which you want to position the RDM pointers
[Parameter(Mandatory=$true)][string]$pathRDM # path of the file containing the list of RDMs
)

 

 

 

I didn't put the vCenter connection string below, but don't forget to add it using the Server, User and password parameters

 

 

if( ($($vmprincipal) -match "[*]+") -or  ($($vmsecondaire) -match "[*]+") ){
    Write-host "The use of the character * in the name of a vm is prohibited"
    exit;
}


# We build one Array with the name of all Vms
$nameVMs+=$vmprincipal.replace(' ' , '')

foreach($element in $vmsecondaire){
    $nameVMs+=$element.replace(' ' , '')
    
}


# We build one Array with the list of RDMs to attach
foreach($element in (get-content -Path $pathRDM )){
	
    $listRDM+=$element.replace(' ' , '')

}


# --------------------------------------------------------------------------------
#
#  We start by stopping the vms that are started
#
get-vm -Name $nameVMs | %{

    if($_.PowerState -eq "PoweredOn"){
           if($_.ExtensionData.Guest.ToolsRunningStatus -eq "guestToolsRunning"){       
                # If the tools are started
                $_ | Shutdown-VMGuest -Confirm:$false

            }else{
                $_ | stop-vm -Confirm:$false
            }
        
        }
}



# We are waiting for the shutdown of the VMs
$continue=$true
while($continue){

    if((get-vm -name $nameVMs | select PowerState) -match "PoweredOn"){
        Start-sleep 2;
        write-host "." -NoNewline
    }else{
        $continue=$false
    }
}


#
#
# --------------------------------------------------------------------------------------------------------------------------
#
# 1 - We delete the old Disks on the SCSI Controllers SCSI 1,2 et 3
# We only keep on the vms the disks on controller 0 --> where the System disk is located

foreach($nameVM in $nameVMs){

    Get-HardDisk -VM $nameVM | %{

        if( ($_ | Get-ScsiController).ExtensionData.busNumber -gt 0){
               $_ | Remove-HardDisk -DeletePermanently -Confirm:$false  
        }
    }
}



#
#
# --------------------------------------------------------------------------------------------------------------------------
#
# 2 - we remove the old SCSI controllers 1,2 and 3
# https://www.reddit.com/r/PowerShell/comments/8svpp7/powercli_remove_a_scsi_controller/
# https://communities.vmware.com/t5/VMware-PowerCLI-Discussions/Remove-SCSIController/td-p/439789
#
# Normally when deleting disks the unused SCSI controllers will also be deleted!!!!
#

foreach($nameVM in $nameVMs){
        
        $nbControllerScsi=(Get-ScsiController -VM $nameVM).count
        Write-Host "     --> Nombre de controller Scsi : $($nbControllerScsi)"  

        foreach ($a_ScsiController in (get-vm -name $nameVM | Get-ScsiController | WHERE{$_.ExtensionData.BusNumber -gt 0 }))
        {  
                 
            $VM = $a_ScsiController.Parent.ExtensionData 
            '{0} - Removing Paravirtual SCSIController, Bus Number: {1}' -f $VM.Name,$BusNumber | Write-Verbose

            $storagespec = New-Object VMware.Vim.VirtualMachineConfigSpec
                   
            $removeSCSIDevice = New-Object VMware.Vim.VirtualDeviceConfigSpec
            $removeSCSIDevice.operation = "remove"
            $removeSCSIDevice.device = $a_ScsiController.ExtensionData
            $storageSpec.deviceChange = $removeSCSIDevice

            $shouldText = '{0}, VM {1}' -f $a_ScsiController.Name,$a_ScsiController.Parent.Name

            $a_ScsiController.Parent.ExtensionData.ReconfigVM($storageSpec)    
        }
}




#
#
# --------------------------------------------------------------------------------------------------------------------------
#
# 3 - We create the SCSI Controllers 1,2 et 3
#
$ControllerType='ParaVirtualSCSIController'         #'ParaVirtualSCSIController','VirtualBusLogicController','VirtualLsiLogicController','VirtualLsiLogicSASController'
$SharedBus='physicalSharing'                        #'noSharing', 'physicalSharing', 'virtualSharing
foreach($nameVM in $nameVMs){

        $vm=Get-View -Id (get-vm -name $nameVM).Id
       
        foreach($BusNumber in 1..3){

            $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
            $spec.DeviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec[] (1)
            $spec.DeviceChange[0] = New-Object VMware.Vim.VirtualDeviceConfigSpec
            $spec.DeviceChange[0].Device = New-Object VMware.Vim.$ControllerType
            $spec.DeviceChange[0].Device.SharedBus = $SharedBus 
        
            $spec.DeviceChange[0].Device.DeviceInfo = New-Object VMware.Vim.Description
            $spec.DeviceChange[0].Device.DeviceInfo.Summary = 'New SCSI controller'
            $spec.DeviceChange[0].Device.DeviceInfo.Label = 'New SCSI controller'
        
            $spec.DeviceChange[0].Device.BusNumber = $BusNumber
            $spec.DeviceChange[0].Operation = 'add'
            
            LogAndShow -text "Ajout Controller $($BusNumber) - $($ControllerType) - $($SharedBus)"  -color $msg_color_info
            [void]$vm.ReconfigVM_Task($spec)
            Start-Sleep -Seconds 3

        }


}



#
#
# --------------------------------------------------------------------------------------------------------------------------
#
# 4 - Added RDMs to the first Vm
# By distributing the RDMs on controllers 1,2 and 3

$scsci=0
foreach($element in $listRDM){

							
	$numController=($scsci%3)+1
	$Controller="SCSI Controller $numController"
        

	    get-vm -name $vmprincipal  | New-HardDisk -Controller "$($Controller)" -DiskType RawPhysical -DeviceName "$($element)" -Datastore "$($datastore)"

    $scsci=$scsci+1
		
}




#
#
# --------------------------------------------------------------------------------
#
# 5 - we add the disks to the other VMs by relying on the 1st VM. This allows us to mount the RDMs on the same SCSI Port
 
Get-VM -name $vmprincipal | Get-HardDisk | %{

    $scsibusnumber=(Get-ScsiController -HardDisk $_).ExtensionData.BusNumber

    if($scsibusnumber -gt 0){
        $unitnumber = $_.ExtensionData.UnitNumber
        $datastorepath = $_.FileName
     
        
        foreach($nameVM in $vmsecondaire){

            $vm = Get-VM -Name $nameVM
            
            # Does the SCSI Controller exist?
            $controller = Get-ScsiController -VM $vm.name | where{$_.ExtensionData.BusNumber -eq $scsibusnumber}
        
            # Add the VMDK

            $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
            $device = New-Object VMware.Vim.VirtualDisk
            $device.Backing = New-Object VMware.Vim.VirtualDiskRawDiskMappingVer1BackingInfo
            $device.Backing.Filename = $datastorepath
            $device.UnitNumber = $unitnumber
            $device.Backing.DiskMode = 'independent_persistent'
            $device.ControllerKey = $controller.ExtensionData.Key
            $device.Key = -10
            $devChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
            $devChange[0].Device = $device
            $devChange[0].Operation = 'add'
            $spec.DeviceChange += $devChange
            $vm.ExtensionData.ReconfigVM($spec)
            
        }

    }


}




#
# 6 - Start VMs  
#
#

get-vm -name $nameVMs | %{
    $_ |Start-VM
}


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0 Kudos
system_noida
Enthusiast
Enthusiast

Hi ,

 

I am using below simple code to add the disk and then to share with other cluster node server.

This below code is I am using to add disk. But here I wanted to put a input file which will be having all the node so that it can create the disk as mention in the code to all nodes.

 

Connect-VIServer vcenter01.local
$VM = get-vm -name node1

New-HardDisk -VM $VM -CapacityGB 50 -Datastore "Datastore1" -StorageFormat EagerZeroedThick -Controller "SCSI Controller 1"
New-HardDisk -VM $VM -CapacityGB 50 -Datastore "Datastore1" -StorageFormat EagerZeroedThick -Controller "SCSI Controller 1"
New-HardDisk -VM $VM -CapacityGB 80 -Datastore "Datastore1" -StorageFormat EagerZeroedThick -Controller "SCSI Controller 1"
New-HardDisk -VM $VM -CapacityGB 20 -Datastore "Datastore1" -StorageFormat EagerZeroedThick -Controller "SCSI Controller 1"
New-HardDisk -VM $VM -CapacityGB 20 -Datastore "Datastore1" -StorageFormat EagerZeroedThick -Controller "SCSI Controller 1"

 

This 2nd code I am using to sharing the disk which were created using 1st code to other nodes so that the disk can be shared for SQL cluster. Here I have to change the server name every time like node2, node3, node4, node5, and I am looking the code to pick up server name from a input file 

 

Connect-VIServer vcenter01.local
$VM = get-vm -name node2

New-HardDisk -VM $VM -DiskPath "[Datastore1] node1/node_1.vmdk" -Controller "SCSI Controller 1"
New-HardDisk -VM $VM -DiskPath "[Datastore1] node1/node_2.vmdk" -Controller "SCSI Controller 1"
New-HardDisk -VM $VM -DiskPath "[Datastore1] node1/node_3.vmdk" -Controller "SCSI Controller 1"
New-HardDisk -VM $VM -DiskPath "[Datastore1] node1/node_4.vmdk" -Controller "SCSI Controller 1"
New-HardDisk -VM $VM -DiskPath "[Datastore1] node1/node_5.vmdk" -Controller "SCSI Controller 1"

 

 

 

0 Kudos
system_noida
Enthusiast
Enthusiast

I tried to modify the code to input a file with server name. but its not stopping after creating the mention disk, its looping again and creating the mention disk again and again. Pls can any one help what wrong I am doing here.

 

$vms = Get-Content F:\JK\Add-Disk-Script\servers.txt

foreach($VMname in $vms)

{

Get-VM $vms | New-HardDisk -CapacityGB 1 -Datastore "Datastore1" -StorageFormat EagerZeroedThick -Controller "SCSI Controller 1"
Get-VM $vms | New-HardDisk -CapacityGB 1.1 -Datastore "Datastore1" -StorageFormat EagerZeroedThick -Controller "SCSI Controller 1"
Get-VM $vms | New-HardDisk -CapacityGB 1.2 -Datastore "Datastore1" -StorageFormat EagerZeroedThick -Controller "SCSI Controller 1"


}

0 Kudos
ObjectifDubai
Enthusiast
Enthusiast

Hi, 

I thought I understood that you wanted to set up a Microsoft Cluster Services (MSCS, WSFC), am I wrong?
Because in this case, if you want to make a cluster with more than one machine, you have to go through the RDMs or the VVOLS. For vvols this is what I think I understand from the documentation.

https://docs.vmware.com/en/VMware-vSphere/6.7/vsphere-esxi-vcenter-server-67-setup-mscs.pdf

 

ObjectifDubai_0-1648890214872.png

 

ObjectifDubai_0-1648890733841.png

 

 

 

Otherwise, In the article below we also talk about vmdk sharing but in a vSan infrastructure for "RAC Oracle" or Redhat clusters

https://blogs.vmware.com/virtualblocks/2019/12/19/eager-zeroed-thick-requirement-multi-writer-disks-... 

 

 

 

 

 

 

0 Kudos
ObjectifDubai
Enthusiast
Enthusiast

Hi, 

Your code does not loop to infinity, but with each iteration you try to add the disks to all the vms

Because you make a "Get-VM $vms"

instead of a "Get-vm $VMname"

0 Kudos
system_noida
Enthusiast
Enthusiast

Hi,

Yes I am using vvol for ms cluster. I tried to add get-vm $VMName and ran the code again. It is adding only 1 disk on vm and through this error. please can you help.

system_noida_0-1648909489214.png

 

Tags (1)
0 Kudos
ObjectifDubai
Enthusiast
Enthusiast

Some tracks:
- Have you configured the SCSI cards correctly?

https://blogs.vmware.com/virtualblocks/2018/05/31/scsi-3-vvols/


- When we create a Microsoft cluster with several vm, For the 1st VM we create disk volumes, for the other vms we mount an already existing disk so the procedure is not the same. In addition, a shared disk in a Microsoft cluster must be positioned on all vms on the same controller and the same port.

--> Are your vms on? If yes, stop your vms to add the shared volumes

 

 

0 Kudos
system_noida
Enthusiast
Enthusiast

yes, I have configure the scsi controller correctly on all nodes. I have only put 1 node in the input file. If I put 1 disk create code i.e New-HardDisk ..... then there is no error , but when i am putting multiple code to create more than one disk then its giving that error. I suspect that this error show when there is already a task is running on the vm and you are trying to run another task. Like its already busy creating 1 disk but the powercli pushing the code to create other disk also. This is what I suspect. May be some kind of wait code can help here. like the code should create disk one by on after completing first. any though and help pls

0 Kudos
ObjectifDubai
Enthusiast
Enthusiast

Hi, 

No, because adding a disk is not done asynchronously, the New-HardDisk cmdlet only returns you once the action is complete.

Are your vms already on vvol?

Could you put a screenshot of the configuration in vSphere of one of your SCSI controllers and of the disk that was added by the PowerCli command?

0 Kudos
system_noida
Enthusiast
Enthusiast

Hi,

Here is the screen shot below. I ran the below code again and got this error while the code add 2nd and 3rd HDD.

system_noida_2-1648982068462.png

 

 

 

new Hard disk added screen shot

system_noida_0-1648981823979.png

ISCI Controller setting

system_noida_1-1648981863820.png

 

 

0 Kudos
ObjectifDubai
Enthusiast
Enthusiast

hi,

To see if we have more information, could you add to your new-harddisk command the -verbose option

On the other hand, when we read the errors we understand that the error also appears on the addition of the 1st disk

ObjectifDubai
Enthusiast
Enthusiast

Hello,

Could you change the SCSI Bus Sharing of your controller by placing it on "Virtual", I think you will no longer have any errors.

I think you are trying to add a classic virtual disk to a controller that expects a physical-type volume, which results in an error.

 

system_noida
Enthusiast
Enthusiast

Hi ,

It was an issue with the powershell ISE windows. I did closed it and open again and ran the same code and this time there is no error and all disk created successful. Even I have not changed the SCSI controller setting to Virtual, It is still Physical.

 

Thank you very much for helping me on this 🙂

 

0 Kudos
system_noida
Enthusiast
Enthusiast

Hi,

So now the adding disk using the code is working fine. now I wanted to add the partition and drive letter remotely on the nodes using the powershell. I found a code on google and I have modified it as per my requirement. using the below code I wanted to achieve this ....

1. Get the nodes from a input file
2. Find out the offline disk and make them online.
3. Find the online RAW disk and initialize them using GPT partition.
4. Create a partition of disk 1 with a volume level and assign a drive latter
5. Create all required folders into the drive created point #3, I will be using those folder as mount point wit other disks.
6. Cretae the partition for the other disk and use the folders as mount point with no drive letter and assign the full folder path as volume label

Till point#5 the code is working fine. but when it come to point#6 to create partition of other disk and make them as mount point, I am getting the below error. Please can someone help me here to achieve what I am looking for.

 

#1. Get the nodes from a input file

$vms = Get-Content "F:\Jeetu\Add-Disk-Script\servers.txt"

foreach ($VMname in $vms) {}

#2. Find out the offline disk and make them online.
Invoke-Command -ComputerName $VMname -ScriptBlock { get-disk | where operationalstatus -eq Offline | Set-Disk -IsOffline:$false }

#3. Find the online RAW disk and initialize them using GPT partition.
Invoke-Command -ComputerName $VMname -ScriptBlock { get-disk | where PartitionStyle -eq RAW | Initialize-Disk -PartitionStyle GPT }

#4. Create a partition of disk 1 with a volume level and assign a drive latter. Check Disk Number Manually.

Invoke-Command -ComputerName $VMname -ScriptBlock { New-Partition -DiskNumber 2 -UseMaximumSize }
Invoke-Command -ComputerName $VMname -ScriptBlock { Get-Partition –Disknumber 2 –PartitionNumber 2 | Format-Volume –FileSystem NTFS –NewFileSystemLabel TESTSQLDB001 –Confirm:$false }
Invoke-Command -ComputerName $VMname -ScriptBlock { Get-Partition -DiskNumber 2 -PartitionNumber 2 | Set-Partition -NewDriveLetter L }

#5. Create all required folders into the drive created point, I will be using those folder as mount point with other disks.
Invoke-Command -ComputerName $VMname -ScriptBlock { mkdir L:\TESTSQLDB001 }
Invoke-Command -ComputerName $VMname -ScriptBlock { mkdir L:\TESTSQLDB001\Data }
Invoke-Command -ComputerName $VMname -ScriptBlock { mkdir L:\TESTSQLDB001\Backup }

#6. Cretae the partition for the other disk and use the folders as mount point with no drive letter and assign the full folder path as volume label
Invoke-Command -ComputerName $VMname -ScriptBlock { New-Partition -DiskNumber 3 -UseMaximumSize }
Invoke-Command -ComputerName $VMname -ScriptBlock { Add-PartitionAccessPath -DiskNumber 3 -PartitionNumber 3 –AccessPath L:\TESTSQLDB001\Data }
Invoke-Command -ComputerName $VMname -ScriptBlock { Get-Partition –Disknumber 3 –PartitionNumber 3 | Format-Volume –FileSystem NTFS –NewFileSystemLabel "L:\TESTSQLDB001\Data" –Confirm:$false }
Invoke-Command -ComputerName $VMname -ScriptBlock { Get-Partition -DiskNumber 3 -PartitionNumber 3 | Set-Partition -NoDefaultDriveLetter:$True }

Invoke-Command -ComputerName $VMname -ScriptBlock { New-Partition -DiskNumber 4 -UseMaximumSize }
Invoke-Command -ComputerName $VMname -ScriptBlock { Add-PartitionAccessPath -DiskNumber 4 -PartitionNumber 4 –AccessPath "L:\TESTSQLDB001\Backup" }
Invoke-Command -ComputerName $VMname -ScriptBlock { Get-Partition –Disknumber 4 –PartitionNumber 4 | Format-Volume –FileSystem NTFS –NewFileSystemLabel "L:\TESTSQLDB001\Backup" –Confirm:$false }
Invoke-Command -ComputerName $VMname -ScriptBlock { Get-Partition -DiskNumber 4 -PartitionNumber 4 | Set-Partition -NoDefaultDriveLetter:$True }


}

 

system_noida_0-1649058529210.png

 

0 Kudos
system_noida
Enthusiast
Enthusiast

Its fixed. I was putting wrong partition number . I should put partition number as 2 . After i changed it to 2 , its working now.

Is there any way I can reduce the changing of disk number everywhere pls? Partition number will remain 2 on each disk , but I have to change the disk number each point. any way to reduce it pls

0 Kudos
system_noida
Enthusiast
Enthusiast

please can someone help with the code to reduce the putting the disk number each place with my above code I am using to create the partition and mount point inside a node remotely.

Tags (1)
0 Kudos
system_noida
Enthusiast
Enthusiast

Hi @luc @LucD .  Please would you be able to help me here on my above requirement .

0 Kudos