I have an environment with 6 vCenters. I have a read-only NFS datastore (SharedTemplates) where common templates for all vCenters live. The names will be constant, so could be static in the script, but would prefer not to.
I am trying to write a script that would copy all the VM files from the Shared Templates datastore to the local datastore of each vCenter so that they're much faster to deploy.
I don't want the VMs to be in inventory on the SharedTemplates datastore, only on the local datastore. But I need to manually add them in order to occasionally update them.
I'm trying to determine the best way to tackle this. Not sure if copy-datastoreitem with hardcoded paths is the best way, or if there's some other way to delete the local DS VM, then bring the VM into inventory on the SharedTemplates DS, clone it to a new template on the local DS, then remove the VM on the SharedTemplates DS from inventory. Or even just use a bash shell to ssh beneath the vCenter.
I can write the loops for the vCenters & templates, just need help doing the actual writing from one DS to another.
Appreciate any insight or feedback.
Stu Duncan
Follow up to this.
I set the permissions for the user I was testing just a move-vm to be ReadOnly+Browse for the SharedTemplates DS. It still removed the actual files. Not sure how or why it did that...
The NFS isn't actually readonly as I need to be able to update the master. So I'm controlling it by permissions.
Just to clarify, are you talking of vSphere templates (Get-Template) or VMs (Get-VM) that serve as a template ?
In any case, I would suggest the Copy-DatastoreItem cmdlet and copy the VM's/template's folder to the destination datastore.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Well, yes and no.
The master templates live on the SharedTemplates DS, but aren't in inventory from there. They're only in inventory from the local datastore.
This is my logical workflow:
foreach($v in $vCenters){
connect to vCenter $v
foreach($t in $templates){
remove-template $t
copy-datastoreitem ds:\SharedTemplates\$t ds:\local\$t
add-template $t
}
disconnect $v
}
If that works, I just have to worry about which sub folder to put them in, but I could get that info from $t.
That looks a good algorithm, provided the Remove-Template is to unregister the template from the vCenter (use the -DeletePermanently:$false switch).
And I assume the add-template is intended to register the new copy of the template on the local datastore.
You can find the path/folder from $t.ExtensionData.Config.Files.VmPathName
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
So like this?
foreach($v in $vCenters){
connect to vCenter $v
foreach($t in $templates){
$filelocation = $t.ExtensionData.Config.Files.SnapshotDirectory
$folderlocation = get-vm $t | get-vmfolderpath
remove-template $t -confirm:$false
copy-datastoreitem ds:\NFS\$t\* $filelocation\ -force
new-template $t -TemplateFilePath $filelocation -location $folderlocation
}
disconnect $v
}
Seems to work all except the copy-datatstore item.
This doesn't fail, but doesn't copy the 21GB of files either:
copy-datastoreitem -item "[zSharedTemplates] $t/*" -destination "[SystemsSAN] $t/" -force
Fully pathing it out with the template name doesn't work or fail either:
copy-datastoreitem -item "[zSharedTemplates] w2k8r2_64bit_withUtilities/w2k8r2_64bit_withUtilities.vmdk" -destination "[SystemsSAN] w2k8r2_64bit_withUtilities/" -force
No percentage notice or anything. And no file copied over either
Do you get any messages ?
From where do you run the script, the PowerCLI prompt ?
Which PowerCLI version are you using ? Do a Get-PowerCLIVersion.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
No messages at all. Comes back immediately.
Running from a script in powershellISE or from its command line.
PS C:\Windows\system32> Get-PowerCLIVersion
PowerCLI Version
----------------
VMware vSphere PowerCLI 5.5 Release 2 Patch 1 build 1931983
---------------
Snapin Versions
---------------
VMWare AutoDeploy PowerCLI Component 5.5 build 1890764
VMWare ImageBuilder PowerCLI Component 5.5 build 1890764
VMware License PowerCLI Component 5.5 build 1265954
VMware VDS PowerCLI Component 5.5 build 1926677
VMware vSphere PowerCLI Component 5.5 Patch 1 build 1926677
Need this version due to Compellent plugin requirements.
Wondering if the PS-drive is still a requirement?
Apparently it is. This was a test script I wrote which worked:
add-pssnapin VMware.VimAutomation.Core
connect-viserver vcentersystems.dev.fco -user user@vsphere.local -password user
$ds1 = Get-Datastore zSharedTemplates
$ds2 = Get-Datastore SystemsSAN
$t = "w2k8r2_64bit_withUtilities"
New-PSDrive -Location $ds1 -Name source -PSProvider VimDatastore -Root '\'
New-PSDrive -Name dest -PSProvider ViMdatastore -Root '\' -location $ds2
Copy-DatastoreItem dest:\$t\* -Destination source:\$t\ -Force
disconnect-viserver vcentersystems.dev.fco
I had to give 'user' admin privileges on both datastores before it would work though.
So that's my solution.
Thanks for helping!
So this is the final script in total, in case anyone else ever wants to use a master set of templates on a shared datastore to deploy to several vcenters.
#Assumes template name = file name = folder name, all templates are in "_Templates" folder
#Assumes SANS are named $teamSAN, vcenter is vcenter$team.dev.fco
if (-not (Get-PSSnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue)) {
Add-PSSnapin VMware.VimAutomation.Core
}
$team = "team1", "team2"
foreach($tm in $team){
connect-viserver ("vcenter"+$tm+".dev.fco") -user user@vsphere.local -password user
$ds1 = Get-Datastore zSharedTemplates
$ds2 = Get-Datastore ($tm + "SAN")
New-PSDrive -Location $ds1 -Name source -PSProvider VimDatastore -Root '\'
New-PSDrive -Name dest -PSProvider ViMdatastore -Root '\' -location $ds2
$templates = get-folder _Templates | get-template
foreach($tmpl in $templates){
$folderID = (get-template $tmpl).folderid
remove-template $tmpl -DeletePermanently:$false -confirm:$false
Copy-DatastoreItem source:\$tmpl\* -Destination dest:\$tmpl\ -Force -Recurse
new-template -Name $tmpl -TemplateFilePath "[$ds2] $tmpl/$tmpl.vmtx" -location (get-folder -id $folderID) -vmhost (Get-VMHost | Where { $_.ConnectionState -eq "Connected" } | Get-Random) #Doesn't work with -DiskStorageFormat Thin
}
disconnect-viserver ("vcenter"+$tm+".dev.fco") -confirm:$false
}
Only weirdness is that the new-template (also tried with new-vm) fails if I add the -DiskStorageFormat Thin, even though this is in the 5.5 new-template cmdlet.
Error is "Parameter set cannot be resolved using the specified named parameters."
Works fine, but now all the templates are thick provisioned. Which isn't good.
LucD any idea how to get around this, or do I have to go the long route like you did here:
http://www.lucd.info/2013/06/30/hl-tools-part-1-clone-a-vm-without-vcenter/
Yes, the DiskStorageFormat issue (see Datastore Clusters Not Working) is annoying.
That long path from my post could be a solution though.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks for the confirmation, Luc. Irritating bug.
This was my solution.
remove:
Copy-DatastoreItem source:\$tmpl\* -Destination dest:\$tmpl\ -Force -Recurse
Add:
get-harddisk -Datastore $ds1 -DatastorePath "[$ds1] $tmpl/$tmpl.vmdk" | copy-harddisk -DestinationPath "[$ds2] $tmpl/" -Force
Copy-DatastoreItem source:\$tmpl\$tmpl.vmtx -Destination dest:\$tmpl\ -Force
Copy-DatastoreItem source:\$tmpl\$tmpl.vmxf -Destination dest:\$tmpl\ -Force
Copy-DatastoreItem source:\$tmpl\$tmpl.vmsd -Destination dest:\$tmpl\ -Force
Not as pretty, not as fast (10+min to copy 2.6GB), but fully functional now.
Thanks for all the help!