PowerCLI

 View Only
  • 1.  Adding Existing Disk to the VM

    Posted 24 days ago

    Hi,

    We need to migrate 4 VM's from the old datastore to the new datastore. These 4 servers have 36 disk each many of which (except the os disk) are shared multi write disk shared between the VM's from the LUNs. These LUNs are not used for any other VM's.

    Is there a way to remove all the disk from all 3 secondary servers before doing the migration to the new LUN and then add these disks back to all the 3 VM's in the same order?

    Any help in relation to this is greatly appreciated.

    Thank You.



  • 2.  RE: Adding Existing Disk to the VM

    Posted 24 days ago

    Here is a script I had created for configuring a SQL cluster on Windows. It can be adapted to meet your requirements. Are you referring specifically to RDM disks?

    #---------------------------------------------------------------------------------------------------------------------------
    # Nom du Script : RDM Management Script
    # Version       : 2.0
    # Description   : Script pour gérer les RDM (Raw Device Mapping) sur des machines virtuelles VMware
    #                 - Arrête les VMs
    #                 - Configure les contrôleurs SCSI
    #                 - Attache les RDM à une VM principale
    #                 - Réplique la configuration sur des VMs secondaires
    #                 - Redémarre les VMs
    #
    # Prérequis     : - PowerCLI installé
    #                 - Accès au vCenter
    #                 - Fichiers de paramètres (T_PARAM.ps1 et T_FUNCTION.ps1)
    #---------------------------------------------------------------------------------------------------------------------------

    # Définition des paramètres obligatoires et optionnels pour le script
    param( 
        [parameter(Mandatory=$true)][string]$server ,                  # Nom du serveur vCenter
        [parameter(Mandatory=$false)][string]$user,                     # Utilisateur vCenter (optionnel)
        [parameter(Mandatory=$false)][string]$password,                 # Mot de passe vCenter (optionnel)
        [Parameter(Mandatory=$true)][string]$vmprincipal,              # VM principale qui recevra les RDM
        [Parameter(Mandatory=$true)][string[]]$vmsecondaire,           # Liste des VMs secondaires qui recevront les mêmes RDM
        [Parameter(Mandatory=$true)][string]$datastore,                # Datastore où seront stockés les pointeurs vers le  RDM
        [Parameter(Mandatory=$true)][string]$pathRDM                   # Chemin vers le fichier contenant la liste des RDM
    )

    # Variables pour le suivi du temps d'exécution
    $datedebut = Get-Date
    $pathprgname = $MyInvocation.InvocationName
    $myrep = Split-Path $MyInvocation.MyCommand.Path -ErrorAction SilentlyContinue 

    # Chargement des fichiers de paramètres et de fonctions externes
    try {
        # Chargement des fichiers de configuration
        . ("$myrep\T_PARAM\T_PARAM.ps1")      # Contient les variables globales et paramètres
        . ("$myrep\T_PARAM\T_FUNCTION.ps1")   # Contient les fonctions communes

        # Configuration du logging
        $myprgse = $MyInvocation.MyCommand.Name.split(".")[0]
        $mylog = "$myreplog\$myprgse-$mydate-$mytime.log"
        write-host  "Chargement des Fichiers de Fonctions et Parametre : OK" 
    } catch {
        write-host  "Erreur Pendant le Chargement des Fichiers de Fonctions et Parametre --> NOK" 
        exit 1
    }

    # Vérification de la présence de caractères wildcard dans les noms de VM
    if( ($vmprincipal -match "[*]+") -or ($vmsecondaire -match "[*]+") ){
        write-host  "l'Utilisation du caractere * dans le nom d'une vm est interdit" 
        exit 1
    }

    # Création du tableau contenant toutes les VMs à traiter
    $nameVMs = @($vmprincipal.Trim())
    $nameVMs += $vmsecondaire | ForEach-Object { $_.Trim() }

    # Lecture et validation du fichier contenant la liste des RDM
    try {
        # Vérification de l'existence du fichier
        if (!(Test-Path $pathRDM)) {
            throw "Le fichier RDM n'existe pas: $pathRDM"
        }
        # Lecture du fichier en ignorant les lignes vides
        $listRDM = Get-Content -Path $pathRDM | Where-Object { $_ -match '\S' } | ForEach-Object { $_.Trim() }
        if ($listRDM.Count -eq 0) {
            throw "Le fichier RDM est vide"
        }
    } catch {
        write-host "Erreur avec le fichier RDM: $_"
        exit 1
    }

    # Connexion au serveur vCenter
    try {
        write-host "Connexion au vCenter $server" 
        connexionVcenter -server $server -user $user -password $password
        
        # Vérification de la connexion
        $connection = Get-View ServiceInstance
        if (!$connection) {
            throw "Échec de connexion au vCenter"
        }
    } catch {
        write-host "Erreur de connexion au vCenter: $_"
        exit 1
    }

    # Arrêt des machines virtuelles
    write-host "Arrêt des machines PoweredOn" 
    Get-VM -Name $nameVMs | ForEach-Object {
        if ($_.PowerState -eq "PoweredOn") {
            try {
                # Vérification si VMware Tools est installé et en cours d'exécution
                if ($_.ExtensionData.Guest.ToolsRunningStatus -eq "guestToolsRunning") {
                    write-host "    --> Arrêt gracieux de la VM $($_.name)" 
                    $_ | Shutdown-VMGuest -Confirm:$false
                } else {
                    # Si pas de VMware Tools, arrêt forcé
                    write-host "    --> Arrêt forcé de la VM $($_.name) (pas de VMware Tools)"
                    $_ | Stop-VM -Confirm:$false
                }
            } catch {
                write-host "Erreur lors de l'arrêt de $($_.name): $_"
            }
        } else {
            write-host  "    --> la vm $($_.name) est déjà arrêtée"
        }
    }

    # Attente de l'arrêt complet des VMs avec timeout
    $timeout = 300 # 5 minutes
    $timer = [Diagnostics.Stopwatch]::StartNew()
    while ((Get-VM -Name $nameVMs | Where-Object {$_.PowerState -eq "PoweredOn"}) -and $timer.Elapsed.TotalSeconds -lt $timeout) {
        Write-Progress -Activity "Attente de l'arrêt des VMs" -Status "Temps écoulé: $($timer.Elapsed.Minutes)m $($timer.Elapsed.Seconds)s"
        Start-Sleep -Seconds 2
    }
    if ($timer.Elapsed.TotalSeconds -ge $timeout) {
        write-host  "Timeout atteint en attendant l'arrêt des VMs"
        exit 1
    }

    # Suppression des disques existants sur les contrôleurs SCSI 1,2,3
    write-host  "1 - Suppression des anciens disques sur les controller SCSI 1,2 et 3" 
    foreach($nameVM in $nameVMs) {
        try {
            write-host  "Suppression des disques de la VM $nameVM" 
            # Récupération et suppression des disques sur les contrôleurs SCSI > 0
            Get-HardDisk -VM $nameVM | ForEach-Object {
                if (($_ | Get-ScsiController).ExtensionData.busNumber -gt 0) {
                    write-host  "     --> Suppression du disque $_" 
                    $_ | Remove-HardDisk -DeletePermanently -Confirm:$false
                }
            }
        } catch {
            write-host  "Erreur lors de la suppression des disques pour $nameVM : $_"
        }
    }

    # Création des nouveaux contrôleurs SCSI
    write-host  "3 - Création des controller SCSI 1,2 et 3" 
    foreach($nameVM in $nameVMs) {
        try {
            $vm = Get-View -Id (Get-VM -Name $nameVM).Id
            
            # Création des 3 contrôleurs SCSI
            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.ParaVirtualSCSIController
                $spec.DeviceChange[0].Device.SharedBus = 'physicalSharing'
                
                # Configuration des informations du contrôleur
                $spec.DeviceChange[0].Device.DeviceInfo = New-Object VMware.Vim.Description
                $spec.DeviceChange[0].Device.DeviceInfo.Label = "SCSI Controller $BusNumber"
                $spec.DeviceChange[0].Device.DeviceInfo.Summary = "SCSI Controller $BusNumber"
                
                $spec.DeviceChange[0].Device.BusNumber = $BusNumber
                $spec.DeviceChange[0].Operation = 'add'
                
                write-host  "Ajout Controller $BusNumber pour $nameVM" 
                $task = $vm.ReconfigVM_Task($spec)
                
                # Attente de la fin de la tâche
                while ((Get-Task -Id $task.ToString()).State -eq "Running") {
                    Start-Sleep -Seconds 1
                }
                
                if ((Get-Task -Id $task.ToString()).State -eq "Error") {
                    throw "Erreur lors de la création du contrôleur SCSI $BusNumber"
                }
            }
        } catch {
            write-host  "Erreur lors de la création des contrôleurs pour $nameVM : $_"
            continue
        }
    }

    # Ajout des RDM à la VM principale
    write-host  "4 - Ajout des RDM à la VM principale $vmprincipal" 
    foreach($element in $listRDM) {
        try {
            # Distribution des RDM sur les 3 contrôleurs SCSI de manière équilibrée
            $numController = ([array]::IndexOf($listRDM, $element) % 3) + 1
            $Controller = "SCSI Controller $numController"
            
            write-host  "    Ajout ---> Controller $Controller - RDM $element" 
            Get-VM -Name $vmprincipal | New-HardDisk -Controller $Controller -DiskType RawPhysical -DeviceName $element -Datastore $datastore
        } catch {
            write-host  "Erreur lors de l'ajout du RDM $element : $_"
        }
    }

    # Réplication des RDM sur les VMs secondaires
    write-host  "5 - Ajout des disques RDM aux VMs Secondaires" 
    Get-VM -Name $vmprincipal | Get-HardDisk | ForEach-Object {
        try {
            $scsibusnumber = (Get-ScsiController -HardDisk $_).ExtensionData.BusNumber
            if ($scsibusnumber -gt 0) {
                $unitnumber = $_.ExtensionData.UnitNumber
                $datastorepath = $_.FileName
                
                # Ajout du même RDM à chaque VM secondaire
                foreach($nameVM in $vmsecondaire) {
                    try {
                        $vm = Get-VM -Name $nameVM
                        $controller = Get-ScsiController -VM $vm.name | Where-Object {$_.ExtensionData.BusNumber -eq $scsibusnumber}
                        
                        # Configuration du disque RDM
                        $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)
                        
                        write-host  "   VM $vm ---> controller $scsibusnumber - Port $unitnumber - Datastore $datastorepath" 
                    } catch {
                        write-host  "Erreur lors de l'ajout du disque à $nameVM : $_"
                    }
                }
            }
        } catch {
            write-host  "Erreur lors du traitement du disque : $_"
        }
    }

    # Redémarrage des VMs
    write-host  "6 - Démarrage des VMs" 
    foreach ($vm in $nameVMs) {
        try {
            write-host  "    --> Démarrage de la VM $vm" 
            Start-VM -VM $vm -ErrorAction Stop
        } catch {
            write-host  "Erreur lors du démarrage de $vm : $_"
        }
    }

    # Calcul du temps d'exécution pour le rapport
    $datefin = Get-Date
    $difference = $datefin - $datedebut

    # Ajout des informations d'exécution au rapport
    $body += "-----------------------------------------------------------------------------------------------------------------------<br/>"
    $body += "Serveur : $myserver.$mydomain<br/>"
    $body += "Programme : $pathprgname<br/>"
    $body += "Execution : $([math]::Round($difference.TotalSeconds,3)) Sec (debut : $($datedebut.ToString('dd/MM/yyyy HH:mm:ss')) fin : $($datefin.ToString('dd/MM/yyyy HH:mm:ss')))<br/>"
    $body += "-----------------------------------------------------------------------------------------------------------------------<br/>"

    # Envoi du rapport par email
    sendMail -body $body

    # Nettoyage : déconnexion du vCenter
    Disconnect-VIServer -Server $server -Confirm:$false

    ######### -------------------------------------------------------------------------------------------------------------------------------------------------------

    This PowerCLI script automates the management of Raw Device Mapping (RDM) disks in a VMware vSphere environment. It simplifies the RDM setup by attaching them to a primary VM and replicating the configuration across one or more secondary VMs.

    Main Features:

    1. Connects to the vCenter Server (using provided server, user, and password).

    2. Gracefully or forcefully powers off the target VMs depending on VMware Tools availability.

    3. Removes any existing RDM disks attached to SCSI controllers 1, 2, and 3.

    4. Creates three additional SCSI controllers (bus numbers 1 to 3) on each VM.

    5. Adds the specified physical RDMs to the primary VM, evenly distributed across the controllers.

    6. Clones the RDM configuration onto each secondary VM, matching controller and unit placement.

    7. Restarts all involved VMs after configuration is complete.

    8. Generates an HTML execution report including runtime metrics and sends it via email.

    9. Properly disconnects from the vCenter server at the end of execution.

    Required Files:

    • T_PARAM.ps1: contains global variables (e.g., logging paths, settings).

    • T_FUNCTION.ps1: contains utility functions (e.g., vCenter connection, mail sending).

    • A plain text file ($pathRDM) listing the full paths to RDM devices (one per line).

    Prerequisites:

    • PowerCLI must be installed.

    • vCenter credentials with sufficient rights to stop/start VMs and reconfigure hardware.

    • All target VMs must already exist in the vCenter.

    • The RDM path file must be properly filled and accessible.

    Restrictions:

    • Wildcards (*) are not allowed in VM names.

    • RDMs are added in RawPhysical mode with independent_persistent disk mode.

    • RDMs are automatically distributed across SCSI controllers 1 to 3.

    • Secondary VMs will receive the exact same RDMs on the same SCSI bus and unit.

    Script Parameters:

    Parameter Description
    -server vCenter server hostname or IP
    -user (Optional) vCenter username
    -password (Optional) vCenter password
    -vmprincipal Name of the primary VM to receive the RDMs
    -vmsecondaire Array of secondary VM names to replicate RDMs to
    -datastore Datastore used to store the RDM pointer files
    -pathRDM Path to the text file listing the RDM devices

    -------------------------------------------
    Message d'origine:
    Envoyé: Jul 01, 2025 12:20 PM
    Depuis: Nitin Singh
    Sujet: Adding Existing Disk to the VM

    Hi,

    We need to migrate 4 VM's from the old datastore to the new datastore. These 4 servers have 36 disk each many of which (except the os disk) are shared multi write disk shared between the VM's from the LUNs. These LUNs are not used for any other VM's.

    Is there a way to remove all the disk from all 3 secondary servers before doing the migration to the new LUN and then add these disks back to all the 3 VM's in the same order?

    Any help in relation to this is greatly appreciated.

    Thank You.



  • 3.  RE: Adding Existing Disk to the VM

    Posted 18 days ago

    Required Files:

    • T_PARAM.ps1: contains global variables (e.g., logging paths, settings).

    • T_FUNCTION.ps1: contains utility functions (e.g., vCenter connection, mail sending).

    • A plain text file ($pathRDM) listing the full paths to RDM devices (one per line).

      Thanks for the sharing, can you share a sample for those files, will be great 




  • 4.  RE: Adding Existing Disk to the VM

    Posted 18 days ago

    I'm going on vacation soon, but if needed, I can help you modify the script to meet your requirements.


    In the directory containing the script, you will find three subdirectories:

    Data folder: contains the file listeRDM.txt

    log folder: used for writing log files

    T_PARAM folder: contains the files T_FUNCTIONS.ps1 and T_PARAM.ps1

    Below, you will find the content of the various files as well as the updated script. In the initial version I sent you, I had replaced the LogAndShow function with a simple Write-Host.

    -------------------------------------------
    Message d'origine:
    Envoyé: Jul 01, 2025 12:20 PM
    Depuis: Nitin Singh
    Sujet: Adding Existing Disk to the VM

    Hi,

    We need to migrate 4 VM's from the old datastore to the new datastore. These 4 servers have 36 disk each many of which (except the os disk) are shared multi write disk shared between the VM's from the LUNs. These LUNs are not used for any other VM's.

    Is there a way to remove all the disk from all 3 secondary servers before doing the migration to the new LUN and then add these disks back to all the 3 VM's in the same order?

    Any help in relation to this is greatly appreciated.

    Thank You.

    Attachment(s)

    txt
    listeRDM.txt   241 B 1 version
    ps1
    configureVMClusterSQL.ps1   12 KB 1 version
    ps1
    T_PARAM.ps1   2 KB 1 version
    ps1
    T_FUNCTION.ps1   5 KB 1 version


  • 5.  RE: Adding Existing Disk to the VM

    Posted 18 days ago
    -------------------------------------------
    Message d'origine:
    Envoyé: Jul 07, 2025 10:45 AM
    Depuis: ObjectifDubai
    Sujet: Adding Existing Disk to the VM

    I'm going on vacation soon, but if needed, I can help you modify the script to meet your requirements.


    In the directory containing the script, you will find three subdirectories:

    Data folder: contains the file listeRDM.txt

    log folder: used for writing log files

    T_PARAM folder: contains the files T_FUNCTIONS.ps1 and T_PARAM.ps1

    Below, you will find the content of the various files as well as the updated script. In the initial version I sent you, I had replaced the LogAndShow function with a simple Write-Host.

    -------------------------------------------
    Message d'origine:
    Envoyé: Jul 01, 2025 12:20 PM
    Depuis: Nitin Singh
    Sujet: Adding Existing Disk to the VM

    Hi,

    We need to migrate 4 VM's from the old datastore to the new datastore. These 4 servers have 36 disk each many of which (except the os disk) are shared multi write disk shared between the VM's from the LUNs. These LUNs are not used for any other VM's.

    Is there a way to remove all the disk from all 3 secondary servers before doing the migration to the new LUN and then add these disks back to all the 3 VM's in the same order?

    Any help in relation to this is greatly appreciated.

    Thank You.



  • 6.  RE: Adding Existing Disk to the VM

    Posted 18 days ago

    Thanks and appreciated, nice work