Hi everyone!
I'm quite new to this forum, to PowerShell, and to PowerCLI in general. So I may need your understanding and generous help on this...
I've created a simple script that should remove/unregister a VM (based on a text file), and register them to a new cluster based on the vmx file location extracted through a function called "Get-VMXPath" (get it here: Script Get the VMX Path for VMware VMs)
$filename = "ztest.txt"
$location = "C:\Scripts\_Migration\ztest"
$vmList = Get-Content "$location\$filename.txt"
foreach ($vm in $vmList)
{
$vmxpath = Get-VMXPath $vm | select VMXPath
Remove-VM -VM $vm -DeleteFromDisk:$false -Confirm:$false -RunAsync
New-VM -VMFilePath $vmxpath -ResourcePool (Get-Cluster Cluster_Name | Get-ResourcePool ResourcePool_Name)
}
I'm having issues with Line 8, particularly, the variable $vmxpath. When I use this variable, I get this error:
New-VM : 8/14/2017 4:01:22 PM New-VM '@{VMXPath=[datastore01] vmfolder/vm.vmx}' is not valid datastore path.
At line:1 char:1
+ New-VM -VMFilePath $vmxpath -ResourcePool (Get-Cluster Cluster_Name ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-VM], InvalidArgument
+ FullyQualifiedErrorId : Common_DatastorePathHelper_ValidateDatastorePath_InvalidPath,VMware.VimAutomation.ViCore.Cmdlets.Command
s.NewVM
But when I don't use the $vmxpath variable, and use the actual value of "[datastore01] vmfolder/vm.vmx" instead, it works.
As I've said, I'm new to PowerCLI and PowerShell in general, so I might be missing out on how to insert a variable to property or to the PowerCLI new-vm switch -VMFilePath.
Also, just a side note, we're migrating ~100+ vms from one cluster to another, but we're unable to vMotion due to some errors (which is still getting fixed). So I was hoping to use this script to perform the migration.
Hoping for your kind assistance on this, thanks!
The object in the variable $vm is not the newly registered VM, in fact that VM has just be unregistered.
Try like this
$filename = "vmList.txt"
$location = "x:\folder"
$TargetCluster = "Cluster_Name"
$TargetResourcePool = "ResourcePool_Name"
$TargetNetworkName = "Network_Label"
$vmList = Get-Content "$location\$filename"
foreach ($vm in (Get-VM -name $vmList))
{
Stop-VM -vm $vm -Confirm:$false
Remove-VM -VM $vm -DeleteFromDisk:$false -Confirm:$false -RunAsync
$newVM = New-VM -VMFilePath $vm.ExtensionData.Config.Files.VmPathName -ResourcePool (Get-Cluster $TargetCluster | Get-ResourcePool $TargetResourcePool)
Get-NetworkAdapter -VM $newVM | Set-NetworkAdapter -NetworkName $TargetNetworkName -Confirm:$false
Start-VM -vm $newVM
Get-VMQuestion -vm $newVM | Set-VMQuestion -Option "button.uuid.movedTheVM" -Confirm:$false
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
In your script, the $vmxpath variable contains an object with a VMXPath property. The variable does not contain a string. You should modify line 6 of your script into:
$vmxpath = Get-VMXPath $vm | select -ExpandProperty VMXPath
or
$vmxpath = (Get-VMXPath $vm).VMXPath
I prefer the second option.
Leave out the Get-VmxPath function, that vale is readily available from the VM.
Like this
$filename = "ztest.txt"
$location = "C:\Scripts\_Migration\ztest"
$vmList = Get-Content "$location\$filename.txt"
foreach ($vm in (Get-VM -Name $vmList))
{
Remove-VM -VM $vm -DeleteFromDisk:$false -Confirm:$false -RunAsync
New-VM -VMFilePath $vm.ExtensionData.Config.Files.VmPathName -ResourcePool (Get-Cluster Cluster_Name | Get-ResourcePool ResourcePool_Name)
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi RvdNieuwendijk and LucD, thanks for your replies!! You guys are awesome!
I've only tried RvdNieuwendijk's recommendation (2nd one) for the initial batch. It's working quite fine!
For the next batch, I'll try LucD's recommendation.
I'll let you guys know, thanks again!
Hi LucD
I've revised my script to include a few lines of commands required for the migration:
$filename = "vmList.txt"
$location = "X:\folder"
$TargetNetworkName = "NetworkLabel"
$vmList = Get-Content "$location\$filename"
foreach ($vm in $vmList)
{
$vmxpath = (Get-VMXPath $vm).VMXPath
Stop-VM -vm $vm -Confirm:$false
Remove-VM -VM $vm -DeleteFromDisk:$false -Confirm:$false -RunAsync
New-VM -VMFilePath $vmxpath -ResourcePool (Get-Cluster Cluster_Name | Get-ResourcePool ResourcePool_Name)
Get-VM $vm | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $TargetNetworkName -Confirm:$false
Start-VM -vm $vm
Get-VMQuestion -vm $vm | Set-VMQuestion -Option "button.uuid.movedTheVM" -Confirm:$false
}
Also, I've tried your recommendation to remove Line 7 [$vmxpath = (Get-VMXPath $vm).VMXPath], and changed Line 10 to New-VM -VMFilePath $vm.ExtensionData.Config.Files.VmPathName -ResourcePool (Get-Cluster Cluster_Name | Get-ResourcePool ResourcePool_Name), but I'm getting the following error:
New-VM : Cannot validate argument on parameter 'VMFilePath'. The argument is null or empty. Provide an argument that is not null or empty,
and then try the command again.
At line:10 char:24
+ ... New-VM -VMFilePath $vm.ExtensionData.Config.Files.VmPathName -Resour ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [New-VM], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.NewVM
I'm on PowerCLI 6.5 Release 1 build 4624819.
Did you also update the ForEach in line 4 as I showed?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Yes, I did forget to update the foreach line. Thanks!
The new-vm line now works. I like your recommended implementation because I wouldn't need the Get-VMXPath function to get this script running.
Here's my updated script with your recommendation:
$filename = "vmList.txt"
$location = "x:\folder"
$TargetCluster = "Cluster_Name"
$TargetResourcePool = "ResourcePool_Name"
$TargetNetworkName = "Network_Label"
$vmList = Get-Content "$location\$filename"
foreach ($vm in (Get-VM -name $vmList))
{
Stop-VM -vm $vm -Confirm:$false
Remove-VM -VM $vm -DeleteFromDisk:$false -Confirm:$false -RunAsync
New-VM -VMFilePath $vm.ExtensionData.Config.Files.VmPathName -ResourcePool (Get-Cluster $TargetCluster | Get-ResourcePool $TargetResourcePool)
Get-VM $vm | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $TargetNetworkName -Confirm:$false
Start-VM -vm $vm
Get-VMQuestion -vm $vm | Set-VMQuestion -Option "button.uuid.movedTheVM" -Confirm:$false
}
However, I'm now encountering new errors on the succeeding lines (13 and 14) for the start-vm and get-vmquestion.
I'm now getting the following error:
Start-VM : 8/15/2017 1:13:28 PM Start-VM
At line:13 char:5
+ Start-VM -vm $vm
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Start-VM], ManagedObjectNotFound
+ FullyQualifiedErrorId : Client20_VMServiceImpl_StartVM_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.StartVM
Get-VMQuestion : 8/15/2017 1:13:28 PM Get-VMQuestion The object has already been deleted or has not been completely
created
At line:14 char:5
+ Get-VMQuestion -vm $vm | Set-VMQuestion -Option "button.uuid.move ...
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-VMQuestion], ManagedObjectNotFound
+ FullyQualifiedErrorId : Client20_VMServiceImpl_GetVMQuestion_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVMQues
tion
But when I issue the start-vm and get-vmquestion commands without using the variable $vm, I'm able to start and answer the question.
The object in the variable $vm is not the newly registered VM, in fact that VM has just be unregistered.
Try like this
$filename = "vmList.txt"
$location = "x:\folder"
$TargetCluster = "Cluster_Name"
$TargetResourcePool = "ResourcePool_Name"
$TargetNetworkName = "Network_Label"
$vmList = Get-Content "$location\$filename"
foreach ($vm in (Get-VM -name $vmList))
{
Stop-VM -vm $vm -Confirm:$false
Remove-VM -VM $vm -DeleteFromDisk:$false -Confirm:$false -RunAsync
$newVM = New-VM -VMFilePath $vm.ExtensionData.Config.Files.VmPathName -ResourcePool (Get-Cluster $TargetCluster | Get-ResourcePool $TargetResourcePool)
Get-NetworkAdapter -VM $newVM | Set-NetworkAdapter -NetworkName $TargetNetworkName -Confirm:$false
Start-VM -vm $newVM
Get-VMQuestion -vm $newVM | Set-VMQuestion -Option "button.uuid.movedTheVM" -Confirm:$false
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I see, but it's weird because when I checked the value of $vm, it's showing the vm name (of the last vm name from the list, per foreach).
Anyhow, having the $newVM did the trick! Thanks a lot!!
Fyi, yes, the Name of the VM is the same.
vCentergets that from the DisplayName in the VMX file you registered.
But if you look at the Id field, you'll notice that these are different, and it's that field that is the unique identifier for the VM to the vCenter.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Oh, I see. I understand unique identifiers, but I haven't dug that deeper to see/compare them before and after registration. I'll take note of that, thanks a lot!!