The script below is used to storage vmotion Templates by first converting them into VMs, migrate them, then convert them back again to a template. Strangely, the Move-VM command starts a storage migration, as viewed in the vCenter GUI, however it also errors out!?? I cannot figure out why it is doing this! And it seems to be doing it with all my templates.
I tested this from a PowerShell command line and the PowerShell IDE- same result.
Function:
function Move-VMTemplate
{
# This function will migrate a template VM to the target datastore.
# The template is first converted to a VM,
# then migrated, then converted back to a template.
param(
[string] $TemplateName,
[string] $DatastoreName
)
# Try
# {
if($TemplateName -eq ""){Write-Host "Enter a Template name"}
if($DatastoreName -ne ""){$svmotion = $true}
# Firstly, verify we have a target datastore presented to the vCenter:
$TargetDS = Get-Datastore $DatastoreName -ErrorAction Stop
Write-Host "$LineItem2 Converting to VM." -ForegroundColor DarkCyan
# Convert the template to a VM.
$oTemplateAsVM = Set-Template -Template (Get-Template $TemplateName) -ToVM -ErrorAction Stop
Write-Host "$LineItem2 Migrate template to target datastore." -ForegroundColor DarkCyan
# Move the VM to the target datastore.
$MoveVMToDS = Move-VM -VM (Get-VM $oTemplateAsVM) -Datastore ($TargetDS) -Confirm:$false -ErrorAction Stop
# Move-VMThin (Get-VM $oTemplateAsVM) (Get-Datastore $fDatastore)
Write-Host "$LineItem2 Converting VM to template." -ForegroundColor DarkCyan
# Convert the VM back to a template.
(Get-VM $oTemplateAsVM | Get-View).MarkAsTemplate() | Out-Null
Write-Host "$LineItem2 Conversion done." -ForegroundColor Green
# }
<# Catch
{
Write-Host "$LineItem2 Error: $($PSItem.ToString())." -ForegroundColor Red
Write-Host "$LineItem2 Skipping template [$TemplateName]." -ForegroundColor Red
}
#> }
I took out the Try/Catch just to see if I could get more info.
The function is called with this line:
$MoveVMTemplate = Move-VMTemplate -template $TemplateName -datastore $NewDatastoreName
Here are the values of the variables:
$TemplateName
nashadow_RHEL6.5-x64_SOE_v1.1_mgt_t1_syd_vmdata_0001
$NewDatastoreName
mgt_t1_syd_vmdata_0003
$TargetDS
Name FreeSpaceGB CapacityGB
---- ----------- ----------
mgt_t1_syd_vmdata_0003 4,659.154 4,680.000
(Get-VM $oTemplateAsVM)
Name PowerState Num CPUs MemoryGB
---- ---------- -------- --------
nashadow_RHEL6.5-... PoweredOff 1 2.000
Template is currently sitting on datastore "mgt_t1_syd_vmdata_0001 ".
When the Move-VM line executes, a new task appears in the vCenter GUI showing the VM being migrated, and it completes without issues, however the script produces the following error:
$PSItem
Move-VM : 22/04/2023 6:01:33 PM Move-VM Operation is not valid due to the current state of the object.
At C:\Users\jmilano\Documents\PowerShell_Scripts\Datastores\2023-03-04 NetApp Datastore Migration\Storage-MigrateTemplates.ps1:102 char:23
+ ... oveVMToDS = Move-VM -VM (Get-VM $oTemplateAsVM) -Datastore ($TargetDS ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Move-VM], VimException
+ FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.MoveVM
The "CS/DVD Drive 1" is set to "Client Device" and not connected. The Template has one 60GB hard disk.
I can manually migrate the template once converted to a VM, using the vCenter GUI without issues. I can then migrate it back to its original datastore.
$PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
5 1 14393 5582
$PSVersionTable
Name Value
---- -----
PSVersion 5.1.14393.5582
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14393.5582
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
Did you also try with
$MoveVMToDS = Move-VM -VM (Get-VM -Name $TemplateName) -Datastore ($TargetDS) -Confirm:$false -ErrorAction Stop
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks LucD, same issue. It's so strange that I don't think there will be a fix for this. It just does not make sense!
The code I'm using actually came with another module to migrate the templates after they were converted to VMs, and I re-instated the module and it actually migrates the VMs with no issues. Here it is:
Call the new module using this line:
# $MoveVMToDS = Move-VM -VM (Get-VM -Name $oTemplateAsVM) -Datastore ($TargetDS) -Confirm:$false -ErrorAction Stop
Move-VMThin (Get-VM $oTemplateAsVM) (Get-Datastore $TargetDS)
function Move-VMThin
{
PARAM(
[Parameter(Mandatory=$true,ValueFromPipeline=$true,HelpMessage="Virtual Machine Objects to Migrate")]
[ValidateNotNullOrEmpty()]
[System.String]$VM,
[Parameter(Mandatory=$true,HelpMessage="Destination Datastore")]
[ValidateNotNullOrEmpty()]
[System.String]$Datastore
)
Begin
{
#Nothing Necessary to process
} #Begin
Process
{
#Prepare Migration info, uses .NET API to specify a transformation to thin disk
$vmView = Get-View -ViewType VirtualMachine -Filter @{"Name" = "$VM"}
$dsView = Get-View -ViewType Datastore -Filter @{"Name" = "$Datastore"}
#Abort Migration if free space on destination datastore is less than 50GB
if (($dsView.info.freespace / 1GB) -lt 50) {throw "Move-ThinVM ERROR: Destination Datastore $Datastore has less than 50GB of free space. This script requires at least 50GB of free space for safety. Please free up space or use the VMWare Client to perform this Migration"}
#Prepare VM Relocation Specificatoin
$spec = New-Object VMware.Vim.VirtualMachineRelocateSpec
$spec.datastore = $dsView.MoRef
$spec.transform = "sparse"
#Perform Migration
$vmView.RelocateVM($spec, $null)
$MoveResult = Move-VM -VM $VM -Datastore $Datastore
} #Process
}
Actually, this was a code module posted by you in this thread a while back:
So I really would love to know why the original Move-VM would migrate the template-convertedTo-VM and ALSO produce an error (Operation is not valid due to the current state of the object.).
Strange.
Did you check what is in $global:defaultVIServers?
Could there be a 2nd connection?
You could always open an SR.
It helps when you use the Get-ErrorReport to capture a log of the error and include that in your SR.
Contrary to what GSS might claim, you do not need a Developer Support contract to open a PowerCLI SR.
Point them to Online Documentation - PowerCLI 12.3.0 User’s Guide - VMware {code}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hmmm, with the new code it now no longer storage migrates the Template/VM and errors with:
$Error[0]
Exception calling "RelocateVM" with "2" argument(s): "Invalid configuration for device '13'."
At C:\Users\jmilano\Documents\PowerShell_Scripts\Datastores\2023-03-04 NetApp Datastore Migration\Storage-MigrateTemplates.ps1:150 char:9
+ $vmView.RelocateVM($spec, $null)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : VimException
I think this code exposes the "real" issue- that the connected portgroup to the template is not valid. I fixed the above issue by disconnecting the network from the VM and converting it back to a template and the script storage migrated it OK.
I'll keep testing to see what happens with the rest of the templates.
You could always automate the checking of the validity of the portgroup after the Template is converted to a VM.
And yes, a conversion of a Template to a VM does not check the validity of the vNIC connected portgroups
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Another code change I had to make was in the calling line:
# Move-VMThin (Get-VM $oTemplateAsVM) (Get-Datastore $TargetDS)
Move-VMThin -VM $($oTemplateAsVM.Name) -Datastore $DatastoreName
Had to change the -VM & Datastore to strings.
One other thing I need your help with is that, surprisingly to me, you can have more than one template in a vCenter with the SAME name!?
So this line returns multiple objects:
$vmView = Get-View -ViewType VirtualMachine -Filter @{"Name" = "$VM"}
If there's no way to fix this then all I can do is check for $vmView.Count and anything gt 1 will get a message to the user to say something like "Sorry, too many objects returned- do this one manually".
Yes, you can, provided they are in different folders.
Same goes for VMs.
You can select a specific VM by adding for example the folder.
Get-Folder -Name MyFolder | Get-VM -Name MyVM
If you are using Get-View, you can use the Folder as the value for the SearchRoot parameter.
$folder = Get-Folder -Name 'MyFolder'
Get-View -ViewType VirtualMachine -SearchRoot $folder.Id -Filter @{Name='MyVM'}
Another option is to use something like my Get-VIObjectByPath function.
Just be aware that it returns a vSphere object (the same as what Get-View returns).
To convert that to a .NET object you will need to use the
$obj = Get-VIObjectByPath -Path 'MyDatacenter/MyFolder/MyVM'
$vmView = $obj.Node
$vm = Get-VIObjectByVIView -VIView $obj.Node
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference