With the introduction of vSPhere the types of Tasks you can select when you create a new Scheduled Task has increased. This is a very useful feature that allows you to schedule for example your (s)vMotions, your Snapshots, your Imports and Exports and so on.
In the PowerCLI Community there was a recent question on how these Scheduled Tasks can be created from PowerShell (see relocate vm’s from csv file and create schedule task in VC).
Being able to create a Scheduled Task for a svMotion for several guests from a PowerShell script, instead of clicking away in the vSphere Client, would be another step on the path of vSphere automation.
The current PowerCLI 4 (build 162509) unfortunately has no cmdlets for Scheduled Tasks. But the SDK contains the CreateScheduledTask method that can be used for this purpose.
The key parameter to this method is the ScheduledTaskSpec object. In the action property of this object you specify which type of action you want the scheduled task to take. If we want to schedule a Task, we will have to select the MethodAction extension object.
But then it looks as if we’re stuck. The SDK Reference doesn’t say which are the accepted values for the name property in the MethodAction object.
Luckily, with a bit of reverse engineering and with the help of Fiddler (see my The Onyx alternative ? post), I was able to get the accepted values for the name property.
In fact the set up is quite straightforward, the name property holds the name of the SDK method that performs the type of task requested. And the argument property, which is an array, will hold all the parameters that go with the called method.
An example.
We want to “Migrate a virtual machine” and move the VM to another datastore.
This is a svMotion.
That means we need the RelocateVM_Task method.
This method requires 2 parameters.
We will have to pass those parameters for the method in the argument array in the MethodAction object. Schematically, the MethodAction object will look like this
MethodAction name values
The following table shows which SDK method corresponds with which Task. With the name of the SDK method you can find the parameters that need to go in the MethodAction.argument property.
Task | MethodAction.name |
Add a host | AddStandaloneHost_Task |
Change resource settings of Resource Pool or Virtual Machine | UpdateConfig |
Change the power state of a virtual machine | ResetVM_Task |
Check compliance for a profile | CheckProfileCompliance_Task |
Clone a virtual machine | CloneVM_Task |
Create a virtual machine | CreateVM_Task |
Deploy a virtual machine | CloneVM_Task |
Make a snapshot of a virtual machine | CreateSnapshot_Task |
Migrate a virtual machine | RelocateVM_Task |
Note1: The import and export a virtual machine tasks do not use the MethodAction. They use CreateTaskAction and the TaskTypeId is respectively com.vmware.converter.Import and com.vmware.converter.Export
Note2: The Scan and Remediate tasks also use CreateTaskAction. The TaskTypeId is respectively com.vmware.vcIntegrity.ScanTask and com.vmware.vcIntegrity.RemediateTask
The script
The Virtual Machine names come from a CSV file with 1 column and with the header VMname.
The script looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
$csvName = "C:\Test.csv" $tgtDatastore = "Datastore1" $emailAddr = "lucd@lucd.info" $startTime = [Datetime]"10/21/2009 20:00" $startInterval = 5 $si = get-view ServiceInstance $scheduledTaskManager = Get-View $si.Content.ScheduledTaskManager $offset = 0 Import-Csv $csvName | % { $vm = Get-View -ViewType VirtualMachine -Filter @{"Name"=$_.VMname} $spec = New-Object VMware.Vim.ScheduledTaskSpec $spec.Name = "svMotion " + $_.VMname $spec.Description = "Migrate " + $_.VMname + " to " + $tgtDatastore $spec.Enabled = $true $spec.Notification = $emailAddr $spec.Scheduler = New-Object VMware.Vim.OnceTaskScheduler $spec.Scheduler.runat = $startTime.AddMinutes($offset) $offset += $startInterval $spec.Action = New-Object VMware.Vim.MethodAction $spec.Action.Name = "RelocateVM_Task" $arg1 = New-Object VMware.Vim.MethodActionArgument $arg1.Value = New-Object VMware.Vim.VirtualMachineRelocateSpec $arg1.Value.datastore = (Get-Datastore $tgtDatastore | Get-View).MoRef $arg1.Value.pool = $vm.ResourcePool $arg1.Value.host = $vm.Runtime.Host $spec.Action.Argument += $arg1 $arg2 = New-Object VMware.Vim.MethodActionArgument $arg2.Value = [VMware.Vim.VirtualMachineMovePriority]"defaultPriority" $spec.Action.Argument += $arg2 $scheduledTaskManager.CreateScheduledTask($vm.MoRef, $spec) } |
Task |
simbol
Hi all,
I`m struggling with my Script to schedule a Snapshot-remove. Is this even possible via script? In the other hand, create a scheduled snapshot create task works fine.
thanks a lot
$vm = Get-VM -Name “test”
$si = get-view ServiceInstance
$scheduledTaskManager = Get-View $si.Content.ScheduledTaskManager
$spec = New-Object VMware.Vim.ScheduledTaskSpec
$spec.Scheduler = New-Object VMware.Vim.OnceTaskScheduler
# Validate datetime value and convert to UTC
try { $castRunTime = ([datetime]$runTime).ToUniversalTime() } catch { “Unable to convert runtime parameter to date time value”; break }
if ( [datetime]$runTime -lt (Get-Date) ) { “Single run tasks can not be scheduled to run in the past. Please adjust start time and try again.”; break }
$spec.Scheduler.RunAt = $castRunTime
$spec.Name = $snapName
$spec.Enabled = $true
$spec.Action = New-Object VMware.Vim.MethodAction
$spec.Action.Name = “RemoveSnapshot_Task”
@($snapName) | %{
$arg = New-Object VMware.Vim.MethodActionArgument
$arg.Value = $_
$spec.Action.Argument += $arg
}
$scheduledTaskManager.CreateObjectScheduledTask($vm.MoRef,$spec)
—————————-
ESXi Version 6.5
Error Output:
Exception calling “CreateObjectScheduledTask” with “2” argument(s): ”
Required parameter obj is missing
while parsing call information for method CreateObjectScheduledTask
at line 1, column 171
while parsing SOAP body
at line 1, column 64
while parsing SOAP envelope
at line 1, column 0
while parsing HTTP request for method createObjectScheduledTask
on object of type vim.scheduler.ScheduledTaskManager
at line 1, column 0″
At line:1 char:1
+ $scheduledTaskManager.CreateObjectScheduledTask($vm.MoRef, $spec)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : VimException
marius
I made an extensive use of scripts based on the srcipts in this page ant they solved a lot of problems for me.
So, many thanks, LucD!
Let ma ask for an additional improvement: while migrating a VM can I specify that I want to change the disk format from thin to thick or from thick to thin?
Regards and thanks again
LucD
Hi Marius,
In theory that is possible, you can define the complete VirtualMachineRelocateSpec object (1st argument) in the Scheduled Task.
But since converting the disk type needs to be done per disk, you will need to target VMs with the same number of VMDK and the DeviceId, which you also need to specify, needs to be the same on all VMs.
Bobby
Hi Luc,
Thank you for the wonderful and helpful script. I got a question, anyway we can add a status report of this migration to where it will export to a CSV file, perhaps ending on c:\Temp\report.csv/txt?
If like Provisioned size (MB) same from the source?
VMname, disk count mounted? etc.
Thanks,
LucD
Hi Bobby,
These MethodAction tasks just call one method, there is no script involved.
And we would need a script to add more functionality, like writing to a log.
You can schedule a script as well, although on VCSA systems this is a bit more tricky, due to the fact that a VCSA is to be considered a ‘black box’.
The easiest way, without voiding the support on your VCSA, would be to use an external scheduler.
Jo
Hi Luc,
great article, as always!
As Ryan asked years ago, how can we check if the task already exists and in case remove/edit it?
Thanks
Jo
Nevermind, I did it.
I found this https://www.eehelp.com/question/reconfigure-the-scheduled-task/, which wasn’t working. However, I’ve adapted it and found a way to make it working. Here the extra code:
# Check if the task already exists
$scheduledTaskManager.RetrieveEntityScheduledTask($vm.MoRef) | %{
$t = (Get-View ScheduledTaskManager).ScheduledTask | %{ (Get-View $_).Info } | Where-Object {$_.Name -eq $spec.Name}
$scheduledTask = Get-View -Id $_ | Where-Object {$t.Name -eq $spec.Name}
}
# If the task already exists then update it, otherwise create it
if($scheduledTask){
$scheduledTask.ReconfigureScheduledTask($spec)
}
else{
$scheduledTaskManager.CreateScheduledTask($vm.MoRef, $Spec)
}
Marius
Great code!
I tested it and it works fine for powered off VMs.
My only trouble is: it looks that VMware.Vim.VirtualMachineRelocateSpec always creates a task to change either datastore and host; if I don’t specify anything the current host is kept.
If the VM is powered on the task attempts to change the host instead of changing the datastore.
How can I specify that I want to change only the datastore?
Regards
marius
LucD
In the $arg1.Value you are in fact creating the VirtualMachineRelocateSpec object. In the script I used datastore, pool and host.
Did you already try by just entering the datastore ?
Marius
Excellent and useful script!
Still valid many years later…
My only concern is that when I review the scheduled task created with the script I see that “Change both host and datastore” is selected, while I want only to change the datastore.
How can I specify that I want to change only the datastore?
Regards
Anastasia
Hi, i try to use your script to migrate 2 VMs to another datastore but i get error
PowerCLI C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI> c:\vmC
ne_migrate.ps1
Type Value
—- —–
ScheduledTask schedule-1
Exception calling “CreateScheduledTask” with “2” argument(s): ”
Required parameter entity is missing
while parsing call information for method CreateScheduledTask
at line 1, column 218
while parsing SOAP body
at line 1, column 207
while parsing SOAP envelope
at line 1, column 38
while parsing HTTP request for method create
on object of type vim.scheduler.ScheduledTaskManager
at line 1, column 0″
At C:\vmClone_migrate.ps1:34 char:1
+ $scheduledTaskManager.CreateScheduledTask($vm.MoRef, $spec)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : VimException
Only one task for first VM from CSV created.
$csvName = “C:\Test0.csv”
$tgtDatastore = “internal_1_old”
$startTime = [Datetime]”05/08/2015 19:00″
$startInterval = 1
$si = get-view ServiceInstance
$scheduledTaskManager = Get-View $si.Content.ScheduledTaskManager
$offset = 0
Import-Csv $csvName | % {
$vm = Get-View -ViewType VirtualMachine -Filter @{“Name”=$_.VMname}
$spec = New-Object VMware.Vim.ScheduledTaskSpec
$spec.Name = “svMotion ” + $_.VMname
$spec.Description = “Migrate ” + $_.VMname + ” to ” + $tgtDatastore
$spec.Enabled = $true
$spec.Scheduler = New-Object VMware.Vim.OnceTaskScheduler
$spec.Scheduler.runat = $startTime.AddMinutes($offset)
$offset += $startInterval
$spec.Action = New-Object VMware.Vim.MethodAction
$spec.Action.Name = “RelocateVM_Task”
$arg1 = New-Object VMware.Vim.MethodActionArgument
$arg1.Value = New-Object VMware.Vim.VirtualMachineRelocateSpec
$arg1.Value.datastore = (Get-Datastore $tgtDatastore | Get-View).MoRef
$arg1.Value.pool = $vm.ResourcePool
$arg1.Value.host = $vm.Runtime.Host
$spec.Action.Argument += $arg1
$arg2 = New-Object VMware.Vim.MethodActionArgument
$arg2.Value = [VMware.Vim.VirtualMachineMovePriority]”defaultPriority”
$spec.Action.Argument += $arg2
$scheduledTaskManager.CreateScheduledTask($vm.MoRef, $spec)
}
Thank you
Werner
Excellent script!
Got an error at first:
Object reference not set to an instance of an object.
If you get that as well; make the CSV inport file like so:
VMname
and so on
Thanks Luc for this great script!
Michael
Hello,
I would like to use this script to convert Think to Thin disks. How can I do this? I am running ESXi v5 and thank you.
Andrew Berk
I cannot get this script to work, I get the following error:
Exception calling “CreateScheduledTask” with “2” argument(s): ”
Error processing attribute “type” with value “vm”
while parsing MoRef for ManagedObject of type vim.ManagedEntity
at line 1, column 320
while parsing call information for method CreateScheduledTask
at line 1, column 218
while parsing SOAP body
at line 1, column 207
while parsing SOAP envelope
at line 1, column 38
while parsing HTTP request for method create
on object of type vim.scheduler.ScheduledTaskManager
at line 1, column 0″
At line:34 char:42
+ $scheduledTaskManager.CreateScheduledTask <<<< ($vm.ExtensionData.Moref.Value, $spec)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Luis B
@Jeff C.
I was getting this error too when I found something out. The time that’s entered in the script is in UTC time!! So make sure you’re accounting for that in the time settings of the script. So if you want it to execute 5 minutes from now add 8 hours and 5 minutes from now and enter that time in the script.
Ryan
Luc, how would you check if the task already exists and if so reconfigure the existing task? Or, delete the existing and create a new one?
Jeff C.
@Jeff C.
I figured it out. I had entered the time format incorrectly (9:30 vs 09:30). And as always, great script Luc!
LucD
Hi Jeff, thanks for figuring it out.
The SDK API can be picky about their parameters sometimes 😉
Jeff C.
Luc, Looks like this is some great code… I am having trouble with it though. Geting this error. Any thoughts?
Exception calling “CreateScheduledTask” with “2” argument(s): “A specified para
meter was not correct.
Powercli 4.1 build 264274
vcenter 4.1
Thanks as always,
Jeff