VMware Cloud Community
lukeglazebrook
Enthusiast
Enthusiast

Help tweaking a script to deploy/recover to a specific datastore cluster rather than just a specific datastore

I butchered a script which was originally created to clone VMs to a specific folder and datastore and remove a time stamp at the end of the VM name.  I'm now trying to rework it so it recovers the clones back to a production datastore cluster rather than just a specific datastore.  It does literally everything I need it to with one exception, I don't seem to be able to successfully tweak it to recover back to a datastore cluster as opposed to just a specific datastore.  Everything I try results in dismal failure I wonder if someone can suggest a tweaked version for me so I can try and understand where I went wrong?

# ==============================================================================================

# NAME: RecoverVMs

#

# AUTHOR: Luke Glazebrook

# DATE  : 09/10/2015

#

# COMMENT: Recovers cloned VMs and uses passed param to specify which cycle of VMs to restore,

#   and removes the -$CYRPYYMMDD ammendment at the end of the VM name.    

#

#

# * Software Dependencies: *

# - Microsoft PowerShell *

# - VMWare PowerCLI *

# ==============================================================================================

# Parameters

# ==============================================================================================

# The below parameter supplied by Control-M refers to cycle and recovery point prefix,

# the date can be added automatically however this functionality has been disabled.

# Date stamp supplied parameter e.g VM1-20151212

param ([string]$CYRPYYMMDD)

# ==============================================================================================

# Functions

# ==============================================================================================

#Function to allow you to check if a command is loaded

Function Check-Command($cmdname)

{

    return [bool](Get-Command -Name $cmdname -ErrorAction SilentlyContinue)

}

# ==============================================================================================

# Varibles

# ==============================================================================================

# Add the vmware snapin for powershell

# Add-PSSnapin VMware.VimAutomation.Core

# Add the vmware snapin for powershell (stops you seeing the error messages)

if (Check-Command "Connect-VIServer")

{

  Write-Host "Automation Tool already loaded"

}

else

{

  #If not already loaded load the snapin

  Write-Host "Loading Automation Tools"

  Add-PSSnapin VMware.VimAutomation.Core

}

# backup = true appends date; false creates a clone with the same name.

$backup = "True"

# debug - true : will not clone vm; FALSE will clone the vm.

$debug = "FALSE"

# Target Datastore

$targetdatastore = "LS-H249-DS1-320GB"

#Refers to the percentage of free space for the DS space check

$freePerc = 5

# Target location - existing folder in vcenter structure, where the clones will be place

$targetlocation = "ProdFolder"

# Set date

$datestart = (get-date -uformat %Y%m%d)

# Name a logfile to capture results.

$logfile = $datestart + "_VMClones_bulk.txt"

#

write-output "New Log ($datestart) - ($logfile)" >> $logfile

# Gets the list of VMs from the file associated with this script

$VmFileList = Get-Content VmsToCloneList.list

#

$ds = Get-Datastore -Name $targetdatastore

#Email varibles

$From = "vCenter@lbase.homeip.net"

$To = "luke@lbase.homeip.net"

$Cc = "luke@lbase.homeip.net"

#$Attachment = "C:\temp\Some random file.txt"

$Subject = "!! TEST DMAT Report TEST !!"

$BodySuccess = "The DMAT VMs have been sucessfully recovered to the specified destination datastore and inventory organisational folder within vSphere"

$BodyFailure1 = "The combined provisioned VMDK usage of the VM's exceeds the capacity of the destination datastore, exiting with code 1"

$BodyFailure2 = "There is insufficient space on the target datastore, increase Space to continue, Exiting with code 2"

$BodyFailure3 = "A VM by the name specified cant be found perhaps it does not exists? Exiting with code 3"

$SMTPServer = "192.168.0.101"

$SMTPPort = "25"

# Establish Connection

Connect-VIServer -Server 127.0.0.1 -User administrator@lbase -Password omega1

# ==============================================================================================

# Deletes current working test VMs in preperation for the recovery of the backup clones

# ==============================================================================================

foreach($vm in $VmFileList){

$active = Get-VM $vm

if($active.PowerState -eq "PoweredOn"){

Stop-VM -VM $vm -Confirm:$false

Start-Sleep -Seconds 10

Remove-VM -VM $vm -DeleteFromDisk -Confirm:$false -RunAsync}

else

{Remove-VM -VM $vm -DeleteFromDisk -Confirm:$false -RunAsync}

}

# ==============================================================================================

# Gets the VM total ProvisionedSpaceGB for all VM's in the list. 

# Additionally ensures whitespaces and hashes are ignored effectively

# creating a clean list which calculates/creates the varible required for validation check 1

# ==============================================================================================

 

$vmCleanedList = New-Object system.Collections.ArrayList

# Loop through our VM file List and clean is up, check for incorrectly specified VM's

ForEach ($vmname in $VmFileList)

{

  if ([string]::IsNullOrWhiteSpace($vmname) -or $vmname.StartsWith("#"))

  {

  write-host("Invalid machine name - $vmname")

  }

  else

  {

  #Should trim vmname to ensure we have no spaces front or end

  $vm = Get-VM $vmname

  $vmCleanedList.Add($vmname)

  $TotalRequiredGB += $vm.ProvisionedSpaceGB

  }

  Write-Host "Total Required = $TotalRequiredGB"

}

# ==============================================================================================

# Validation checks Prior to starting the clone script

# ==============================================================================================

# Validation check 1, Checks if the combined provisioned VMDK usage of the VM's exceeds the capacity of the destination datastore?

if(($ds.FreeSpaceGB -gt $TotalRequiredGB))

{

  Write-Host "Continue with your script"

}

else

{

  Write-Host "There is insufficient space on the target datastore. Please increase Space to continue"

  Write-Output "There is insufficient space on the target datastore. Please increase Space to continue" >> $logfile

  Write-Host "Exiting with code 1"

  Write-Output "Exiting with code 1" >> $logfile

  Send-MailMessage -From $From -to $To -Cc $Cc -Subject $Subject `

  -Body $BodyFailure1 -SmtpServer $SMTPServer -port $SMTPPort

  exit 1

}

$ds = Get-Datastore -Name $targetdatastore

# Validation check 2, do you have X % free datatstorespace?

if(($ds.FreeSpaceGB/$ds.CapacityGB*100) -ge $freePerc)

{

    Write-Host "Continue with your script"

}

else

{

    Write-Host "There is less than X% space free on the datastore. Please increase Space to continue" 

    Write-Output "There is less than X% space free on the datastore. Please increase Space to continue" >> $logfile

    Write-Host "Exiting with code 2"

    Write-Output "Exiting with code 2" >> $logfile

  Send-MailMessage -From $From -to $To -Cc $Cc -Subject $Subject `

  -Body $BodyFailure2 -SmtpServer $SMTPServer -port $SMTPPort

    exit 2

}

#Hack + duplication of effort

#$VmListFile = Get-Content VmsToCloneList.list | Select-Object -Skip 3

ForEach ($vmname in $vmCleanedList)

            {

                        # The VM Object

  $RemoveCYRPYYMMDD = $vmname + "-" + $CYRPYYMMDD

                        $vm = Get-VM -Name $RemoveCYRPYYMMDD

                        # Target Host - use the same host as the current VM ( this is faster than cloning across hosts ).

                        $targethost = $vm.vmhost.name

                        # Target VM Name - name if BACKUP is FALSE

                        $vmtarget = $vmname

                        #

                        $datastore = get-datastore $targetdatastore -vmhost $targethost

# ==============================================================================================

# Begin the actual cloning script

# ==============================================================================================

                        if ($vm -ne $null)

                                    {

                                                Write-Host "A VM named $VM exists. Starting clone"

                                                Write-output "A VM named $VM exists. Starting clone"  >> $logfile

                                    }

                        else

                                    {

                                                Write-Host "A VM by the name specified cant be found perhaps it does not exists?"

                                                Write-Output "A VM by the name specified cant be found perhaps it does not exists?" >> $logfile

                                                Write-Host "Exiting with code 3"

                                                Write-Output "Exiting with code 3" >> $logfile

  Send-MailMessage -From $From -to $To -Cc $Cc -Subject $Subject `

  -Body $BodyFailure3 -SmtpServer $SMTPServer -port $SMTPPort

                                                exit 3

                                    }

                        if ($backup -eq "TRUE") 

                                    {

                                                # Clone the VM to backup_vmname_todaysdate

                                                $vmtarget #= $vmtarget + "-" + $CYRPYYMMDD #+ "-" + $datestart

                                    }

                        # nice colors if you are watching the script run

                        write-host -foregroundcolor green "Cloning $vm to $vmtarget"

                        write-output -foregroundcolor green "Cloning $vm to $vmtarget" >> $logfile

                        new-vm -name $vmtarget -vm $vm -vmhost $targethost -datastore $datastore -Location $targetlocation -DiskStorageFormat thin

  Send-MailMessage -From $From -to $To -Cc $Cc -Subject $Subject `

  -Body $BodySuccess -SmtpServer $SMTPServer -port $SMTPPort

          

  }

Write-Host "Complete"

Exit 0

# COMPLETED

0 Kudos
25 Replies
LucD
Leadership
Leadership

Not sure exactly what you are asking.

Do you want to be able to specify a datastorecluster instead of an individual datastore ?

You can use a datastorecluster on the Datastore parameter on the New-VM cmdlet, but then a number of the tests you are doing would be obsolete.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
lukeglazebrook
Enthusiast
Enthusiast

Absolutely yes mate, apologies should have been more clear.  The part that calculates the free space in advance is no longer absolutely essential just a nicety really and can be excluded if it breaks the rest.  Initially I though it would be super easy to tweak it for this change but is always seems to end up in a disaster for me Smiley Sad       

0 Kudos
lukeglazebrook
Enthusiast
Enthusiast

The final penultimate destination of the VMs should directed to a datastore cluster rather than a specific datastore (which works in that configuration).

0 Kudos
LucD
Leadership
Leadership

Create a new variable that will hold the name of the target datastorecluster.

On the New-VM use that variable on the Datastore parameter.

The Datastore parameter accepts any StorageResource (datastore or datastorecluster)

And remove the free datastore space check from the script

$targetDSC = 'MyDSC'

New-VM -Datastore $targetDSC ....


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
lukeglazebrook
Enthusiast
Enthusiast

Thank-you for your advice mate, I have tweaked and am no doubt doing something silly...

After having modified the script (shown below) I am getting..

Screen Shot 2015-12-13 at 14.18.54.png

Its complaining about a required "datastore" property any idea's where I should inserting that?

# ==============================================================================================

# NAME: RecoverVMs

#

# AUTHOR: Luke Glazebrook

# DATE  : 09/10/2015

#

# COMMENT: Recovers cloned VMs and uses passed param to specify which cycle of VMs to restore,

#   and removes the -$CYRPYYMMDD ammendment at the end of the VM name.   

#

#

#

# * Software Dependencies: *

# - Microsoft PowerShell *

# - VMWare PowerCLI *

# ==============================================================================================

# Parameters

# ==============================================================================================

# The below parameter supplied by Control-M refers to cycle and recovery point prefix,

# the date can be added automatically however this functionality has been disabled.

# Date stamp supplied parameter e.g VM1-20151212

param ([string]$CYRPYYMMDD)

# ==============================================================================================

# Functions

# ==============================================================================================

#Function to allow you to check if a command is loaded

Function Check-Command($cmdname)

{

    return [bool](Get-Command -Name $cmdname -ErrorAction SilentlyContinue)

}

# ==============================================================================================

# Varibles

# ==============================================================================================

# Add the vmware snapin for powershell

# Add-PSSnapin VMware.VimAutomation.Core

# Add the vmware snapin for powershell (stops you seeing the error messages)

if (Check-Command "Connect-VIServer")

{

  Write-Host "Automation Tool already loaded"

}

else

{

  #If not already loaded load the snapin

  Write-Host "Loading Automation Tools"

  Add-PSSnapin VMware.VimAutomation.Core

}

# backup = true appends date; false creates a clone with the same name.

$backup = "True"

# debug - true : will not clone vm; FALSE will clone the vm.

$debug = "FALSE"

# Target Datastore

$targetdatastore = "LS-H249-DS1-320GB"

#Refers to the percentage of free space for the DS space check

$freePerc = 5

# Target location - existing folder in vcenter structure, where the clones will be place

$targetlocation = "ProdFolder"

# Set date

$datestart = (get-date -uformat %Y%m%d)

# Name a logfile to capture results.

$logfile = $datestart + "_VMClones_bulk.txt"

#

write-output "New Log ($datestart) - ($logfile)" >> $logfile

# Gets the list of VMs from the file associated with this script

$VmFileList = Get-Content VmsToCloneList.list

#

$ds = Get-Datastore -Name $targetdatastore

$targetDSC = "LS-H249"

#Email varibles

$From = "vCenter@lbase.homeip.net"

$To = "luke@lbase.homeip.net"

$Cc = "luke@lbase.homeip.net"

#$Attachment = "C:\temp\Some random file.txt"

$Subject = "!! TEST DMAT Report TEST !!"

$BodySuccess = "The DMAT VMs have been sucessfully recovered to the specified destination datastore and inventory organisational folder within vSphere"

$BodyFailure1 = "The combined provisioned VMDK usage of the VM's exceeds the capacity of the destination datastore, exiting with code 1"

$BodyFailure2 = "There is insufficient space on the target datastore, increase Space to continue, Exiting with code 2"

$BodyFailure3 = "A VM by the name specified cant be found perhaps it does not exists? Exiting with code 3"

$SMTPServer = "192.168.0.101"

$SMTPPort = "25"

# Establish Connection

Connect-VIServer -Server 127.0.0.1 -User administrator@lbase -Password omega1

# ==============================================================================================

# Deletes current working test VMs in preperation for the recovery of the backup clones

# ==============================================================================================

foreach($vm in $VmFileList){

$active = Get-VM $vm

if($active.PowerState -eq "PoweredOn"){

Stop-VM -VM $vm -Confirm:$false

Start-Sleep -Seconds 10

Remove-VM -VM $vm -DeleteFromDisk -Confirm:$false -RunAsync}

else

{Remove-VM -VM $vm -DeleteFromDisk -Confirm:$false -RunAsync}

}

# ==============================================================================================

# Gets the VM total ProvisionedSpaceGB for all VM's in the list.

# Additionally ensures whitespaces and hashes are ignored effectively

# creating a clean list which calculates/creates the varible required for validation check 1

# ==============================================================================================

$vmCleanedList = New-Object system.Collections.ArrayList

# Loop through our VM file List and clean is up, check for incorrectly specified VM's

ForEach ($vmname in $VmFileList)

{

  if ([string]::IsNullOrWhiteSpace($vmname) -or $vmname.StartsWith("#"))

  {

  write-host("Invalid machine name - $vmname")

  }

  else

  {

  #Should trim vmname to ensure we have no spaces front or end

  $vm = Get-VM $vmname

  $vmCleanedList.Add($vmname)

  $TotalRequiredGB += $vm.ProvisionedSpaceGB

  }

  Write-Host "Total Required = $TotalRequiredGB"

}

# ==============================================================================================

# Validation checks Prior to starting the clone script

# ==============================================================================================

#Hack + duplication of effort

#$VmListFile = Get-Content VmsToCloneList.list | Select-Object -Skip 3

ForEach ($vmname in $vmCleanedList)

            {

                        # The VM Object

  $RemoveCYRPYYMMDD = $vmname + "-" + $CYRPYYMMDD

                        $vm = Get-VM -Name $RemoveCYRPYYMMDD

                        # Target Host - use the same host as the current VM ( this is faster than cloning across hosts ).

                        $targethost = $vm.vmhost.name

                        # Target VM Name - name if BACKUP is FALSE

                        $vmtarget = $vmname

                        #

                        $datastore = get-datastore $targetdatastore -vmhost $targethost

# ==============================================================================================

# Begin the actual cloning script

# ==============================================================================================

                        if ($vm -ne $null)

                                    {

                                                Write-Host "A VM named $VM exists. Starting clone"

                                                Write-output "A VM named $VM exists. Starting clone"  >> $logfile

                                    }

                        else

                                    {

                                                Write-Host "A VM by the name specified cant be found perhaps it does not exists?"

                                                Write-Output "A VM by the name specified cant be found perhaps it does not exists?" >> $logfile

                                                Write-Host "Exiting with code 3"

                                                Write-Output "Exiting with code 3" >> $logfile

  Send-MailMessage -From $From -to $To -Cc $Cc -Subject $Subject `

  -Body $BodyFailure3 -SmtpServer $SMTPServer -port $SMTPPort

                                                exit 3

                                    }

                        if ($backup -eq "TRUE")

                                    {

                                                # Clone the VM to backup_vmname_todaysdate

                                                $vmtarget #= $vmtarget + "-" + $CYRPYYMMDD #+ "-" + $datestart

                                    }

                        # nice colors if you are watching the script run

                        write-host -foregroundcolor green "Cloning $vm to $vmtarget"

                        write-output -foregroundcolor green "Cloning $vm to $vmtarget" >> $logfile

                        new-vm -name $vmtarget -vm $vm -vmhost $targethost -datastore $targetDSC -Location $targetlocation -DiskStorageFormat thin

  Send-MailMessage -From $From -to $To -Cc $Cc -Subject $Subject `

  -Body $BodySuccess -SmtpServer $SMTPServer -port $SMTPPort

         

  }

Write-Host "Complete"

Exit 0

# COMPLETED

0 Kudos
LucD
Leadership
Leadership

Just tested again, this should be working with the later releases of vSphere and PowerCLI.

Which vSphere version are you running this ?

And which PowerCLI version (do a Get-PowerCliVersion).


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
LucD
Leadership
Leadership

You can do a simple test, to check if datastoreclusters are supported on the Datastore parameter.

Do the following (replace MyESX and MyDSC by valid names for your environment).

Does this create a VM ?

New-VM -Name Test -VMHost (Get-VMHost -Name MyESx) -Datastore MyDSC


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
lukeglazebrook
Enthusiast
Enthusiast

Here are the versions mate

Test/Lab environment

vSphere 5.5.0 Build 1993072

vCenter Server 5.5.0 Build 2183111

Production (where I will need to get this working)

vSphere 5.5.0 Build 1281650

vCenter Server 5.5.0 Build 1476327

When attempting your test in the lab I got the following ...

Screen Shot 2015-12-13 at 19.59.55.png

0 Kudos
LucD
Leadership
Leadership

Now that is very strange, Get-VMHost not recognised ?!?

Do you get the same error back when you just enter Get-VMHost at the PS prompt ?

And which PowerCLI version are you running ?

Do a

Get-PowerCLIVersion

at the PS prompt


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
lukeglazebrook
Enthusiast
Enthusiast

This I might have made a booboo and forgot to load the snap-in etc

PowerCLI version

Screen Shot 2015-12-13 at 21.19.14.png

I knocked up the below script to perform your test mate and indeed I did see vCenter saying "Applying DRS recommendations" and a mysterious VM was created named Test Smiley Happy  Apologies for being a doofus

# ==============================================================================================

# Functions

# ==============================================================================================

#Function to allow you to check if a command is loaded

Function Check-Command($cmdname)

{

    return [bool](Get-Command -Name $cmdname -ErrorAction SilentlyContinue)

}

if (Check-Command "Connect-VIServer")

{

  Write-Host "Automation Tool already loaded"

}

else

{

  #If not already loaded load the snapin

  Write-Host "Loading Automation Tools"

  Add-PSSnapin VMware.VimAutomation.Core

}

# Establish Connection

Connect-VIServer -Server 127.0.0.1 -User administrator@lbase -Password omega1

New-VM -Name Test -VMHost (Get-VMHost -Name 192.168.0.249) -Datastore TestCluster

0 Kudos
lukeglazebrook
Enthusiast
Enthusiast

Hmm, which makes me wonder why it doesn't work in the main script? 

0 Kudos
LucD
Leadership
Leadership

I think it might be related to the PowerCLI version you are using.

With PowerCLI 6R3 this cloning of an existing VM and specifying a datastorecluster, works for me.

Can you upgrade you PowerCLI version ?

Or at least test from another station that has the latest PowerCLI version ?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
lukeglazebrook
Enthusiast
Enthusiast

Just to be clear mate, you test script did create the VM.  Do you still think its the PowerCLI version, I will update it if thats what your suggesting.

0 Kudos
LucD
Leadership
Leadership

The test script created a new VM from scratch, while your other script clones a VM.

I suspect that a datastorecluster on the Datastore parameter for a clone operation, was not yet supported in the PowerCLI version you are using.

But we can easily test that.

In the test script, on the New-VM cmdlet, add a VM parameter that points to an existing VM.

That way you will be doing a clone operation, and we would know for sure.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
lukeglazebrook
Enthusiast
Enthusiast

I went ahead and updated to the latest version mate V6 RC3 same as yours, I don't see it installed on our production VC so I will use the same version there also.  When I get an opportunity I will retest and let you know the results, thanks for your assistance I'm extremely grateful.  

0 Kudos
LucD
Leadership
Leadership

You don't need to update the PowerCLI version on the production VC yet.

Let's first see what the test returns.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
lukeglazebrook
Enthusiast
Enthusiast

I know I am getting my syntax wrong somehow.  I knocked up a VM named "PreExistingVM" and ran the script and got the following error which I sort of partially expected.  How do I tell it the name it needs to be given? ... 

(just a point to highlight I did upgrade my PowerCLI V6 R3, apologies if you would have rather I did not do that.  I initially got the impression you were recommending it)

# ==============================================================================================

# Functions

# ==============================================================================================

#Function to allow you to check if a command is loaded

Function Check-Command($cmdname)

{

    return [bool](Get-Command -Name $cmdname -ErrorAction SilentlyContinue)

}

if (Check-Command "Connect-VIServer")

{

  Write-Host "Automation Tool already loaded"

}

else

{

  #If not already loaded load the snapin

  Write-Host "Loading Automation Tools"

  Add-PSSnapin VMware.VimAutomation.Core

}

# Establish Connection

Connect-VIServer -Server 127.0.0.1 -User administrator@lbase -Password omega1

New-VM -Name PreExistingVM1 -VMHost (Get-VMHost -Name 192.168.0.249) -Datastore TestCluster

0 Kudos
LucD
Leadership
Leadership

The error seems to say that the VM from which you clone, and which is called PreExistingVM1Clone, doesn't exist, or can bot be found.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
lukeglazebrook
Enthusiast
Enthusiast

Whoops wrong screenshot

0 Kudos