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
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
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
The final penultimate destination of the VMs should directed to a datastore cluster rather than a specific datastore (which works in that configuration).
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
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..
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
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
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
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 ...
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
This I might have made a booboo and forgot to load the snap-in etc
PowerCLI version
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 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
Hmm, which makes me wonder why it doesn't work in the main script?
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
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.
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
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.
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
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
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