Hi,
I've got this script (from vc1 or Site A) to help copy a template, convert to VM, migrate VM to vCenter2 in Site B and convert VM to template but I now need to do the following:
1. Instead of doing each VM one by one, I want to do all of them at the same time in parralel so it doesnt take so long.
2. Instead of have two separate scripts for linux and windows and 2 different template csv's, have 1 script and manage all but have some smarts to recognise its a linux template or windows template (perhaps in the CSV have template name and OS name). Also the linux and windows templates need to land on different ESXi and datastores in vc2.
thanks for your help.
#Variables
$vc1 = 'vc1'
$vc2 = 'vc2'
$credentials = Get-Credential
#Connect to vCenters
Connect-VIServer -Server $vc1 -Credential $credentials
Connect-VIServer -Server $vc2 -Credential $credentials
#Import CSV file with template names
$currentTemplates = Import-csv templates.csv
foreach($template in $currentTemplates){
#Check if all templates exist in vCenter 2. If found, delete template permanently (inventory and files). If not found (error action), go to Catch.
Try{
$checkTemplates = Get-Template -Name $($template.template) -Server $vc2 -ErrorAction Stop
Remove-Template -Template $checkTemplates -Server $vc2 -DeletePermanently -Confirm:$false
Write-Output "Removed template $($template.template) on vCenter $vc2"
}
Catch{
Write-Output "Template $($template.template) not found on vCenter $vc2"
}
#Clone existing templates in vCenter1 to vCenter1 in the same folder with a "-clone" amended to the name.
$newTemplate = "$($template.template)-clone"
New-Template -Template $($template.template) -Name $newTemplate -Confirm:$false
Write-Output "Cloned template $($template.template) to $newTemplate on vCenter $vc1"
# Get destination host and datastore
$esx2 = Get-VMHost -Name host2 -Server $vc2
$ds2 = Get-Datastore -Name ds2 -Server $vc2
Write-Output "Converting template $newTemplate to a VM on vCenter $vc1....."
Set-Template -Template $newTemplate -ToVM -Confirm:$false -Server $vc1
#Remove the NIC from VM and migrate to vCenter 2
Write-Output "Migrating VM $newTemplate to vCenter $vc2 on host $esx2 and datastore $ds2..."
$nic = Get-NetworkAdapter -VM $newTemplate
Remove-NetworkAdapter -NetworkAdapter $nic -Confirm:$false
Move-VM -VM $newTemplate -Destination $esx2 -Datastore $ds2
New-NetworkAdapter -VM $newTemplate -NetworkName "PortGroup Name" -StartConnected -Type Vmxnet3
Write-Output "Renaming VM $newTemplate to $($template.template) on vCenter $vc2...."
$newVM = Set-VM -VM $newTemplate -Name $($template.template) -Confirm:$false -Server $vc2
Move-VM -VM $newVM -destination "myfolder" -Server$vc2
Write-Output "Converting VM $newVM to a template on vCenter $vc2....."
Set-VM -VM $newVM -ToTemplate -Confirm:$false -Server $vc2
}
Disconnect-VIServer -Server $vc1 -Confirm:$false
Disconnect-VIServer -Server $vc2 -Confirm:$false
Does this mean my reply in Re: Mware -clone to template (from template) powercli was incorrect (since you didn't mark it with a Correct Answer)?
And since you are not using the InventoryLocation parameter, I assume you are still on the older PowerCLI version?
Is it not possible to add the destination ESXi and datastores in the CSV?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi LucD,
I was trying to reply on that post but it wouldnt let me.
Its not incorrect but I needed a work around in the interm. Yes still using old version.
Yes its possible to add in the CSV but how would that look like in the script?
When you add two columns in the CSV (VMHost and Datastore), you could do something like this
#Variables
$vc1 = 'vc1'
$vc2 = 'vc2'
$credentials = Get-Credential
#Connect to vCenters
Connect-VIServer -Server $vc1 -Credential $credentials
Connect-VIServer -Server $vc2 -Credential $credentials
#Import CSV file with template names
$currentTemplates = Import-csv templates.csv
foreach($template in $currentTemplates){
#Check if all templates exist in vCenter 2. If found, delete template permanently (inventory and files). If not found (error action), go to Catch.
Try{
$checkTemplates = Get-Template -Name $($template.template) -Server $vc2 -ErrorAction Stop
Remove-Template -Template $checkTemplates -Server $vc2 -DeletePermanently -Confirm:$false
Write-Output "Removed template $($template.template) on vCenter $vc2"
}
Catch{
Write-Output "Template $($template.template) not found on vCenter $vc2"
}
#Clone existing templates in vCenter1 to vCenter1 in the same folder with a "-clone" amended to the name.
$newTemplate = "$($template.template)-clone"
New-Template -Template $($template.template) -Name $newTemplate -Confirm:$false
Write-Output "Cloned template $($template.template) to $newTemplate on vCenter $vc1"
# Get destination host and datastore
$esx2 = Get-VMHost -Name $template.VMHost -Server $vc2
$ds2 = Get-Datastore -Name $template.Datastore -Server $vc2
Write-Output "Converting template $newTemplate to a VM on vCenter $vc1....."
Set-Template -Template $newTemplate -ToVM -Confirm:$false -Server $vc1
#Remove the NIC from VM and migrate to vCenter 2
Write-Output "Migrating VM $newTemplate to vCenter $vc2 on host $esx2 and datastore $ds2..."
$nic = Get-NetworkAdapter -VM $newTemplate
Remove-NetworkAdapter -NetworkAdapter $nic -Confirm:$false
Move-VM -VM $newTemplate -Destination $esx2 -Datastore $ds2
New-NetworkAdapter -VM $newTemplate -NetworkName "PortGroup Name" -StartConnected -Type Vmxnet3
Write-Output "Renaming VM $newTemplate to $($template.template) on vCenter $vc2...."
$newVM = Set-VM -VM $newTemplate -Name $($template.template) -Confirm:$false -Server $vc2
Move-VM -VM $newVM -destination "myfolder" -Server$vc2
Write-Output "Converting VM $newVM to a template on vCenter $vc2....."
Set-VM -VM $newVM -ToTemplate -Confirm:$false -Server $vc2
}
Disconnect-VIServer -Server $vc1 -Confirm:$false
Disconnect-VIServer -Server $vc2 -Confirm:$false
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
oh nice! so it means if I have this in a CSV
Template | VMHost | Datastore |
template1 | host1 | datastore1 |
template2 | host2 | datastore2 |
template3 | host1 | datastore1 |
each loop will run through each row?.. example.. template1, host1, datastore1 THEN template2, host2, datastore2 THEN template3, host1, datastore1
Correct, each row will create a new VM on the VMHost and Datastore in that row.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
thanks LucD.
One more question per my original post. If I want to run all the templates in parallel rather than one by one through each loop, how can I achieve this?
In this case I would opt for PowerShell background jobs (Start-Job).
The alternative is to use background tasks on vSphere (RunAsync), but seen the many actions needed to copy 1 template, I'm afraid that would make the script needlessly complex.
With Start-Job the script mostly stays the same, you just need to pass the variables for the specific run.
There is also the question of how many of these background jobs you can reasonable run on your workstation.
Each background PowerShell job requires resources.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
sorry can I ask a silly question, how dou know when to use:
$($template.template) or $template.template / $template.datastore... basically whats the difference $($x.x) over $x.x
It's all about variable substitution in a string.
On a parameter you can use the value like this (variable.property)
$esx2 = Get-VMHost -Name $template.VMHost -Server $vc2
But in a string it is important to tell the variable substitution process what to do.
For example in
"$($template.VMHost)"
we tell the mechanism that it first has to replace everything between the $() with the value of $template.VMHost.
If we would do
"$template.VMHost"
the mechanism would fetch the value of $template, and then append the literal text '.VMHost'
The result would be two different strings.
When you need to use a property of a variable in a string, always place it between $().
That way the substitution mechanism (in strings) knows what to do.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
thanks LucD..perfect explanation.
i've setup this script in a task windows scheduler but it seems to fail on vMotion to vc2 as it needs a username / password. I run the script using a service account.
error: Move-VM : 3/10/2018 11:12:57 AM Move-VM In order to migrate a VM to a different vCenter Server you need to connect to the destination server by username and password.
Script
#Variables
$vcho = 'vc1'
$vcbrs = 'vc2'
#Connect to vCenters
Connect-VIServer -Server $vcho
Connect-VIServer -Server $vcbrs
any ideas?
Can you logon with that service account?
If yes, you could create with New-VICredentialStoreItem en entry for VC2.
$vcsa = 'vc2'
$user = 'Administrator@vsphere.local'
$pswd = 'VMware1!'
New-VICredentialStoreItem -Host $vcsa -User $user -Password $pswd
That way you can pick up the credentials in your scheduled script, something like this
$cred = Get-VICredentialStoreItem -File $CredFile -Host $vc2
$srv = Connect-VIServer -Server $vc2 -User $cred.User -Password $cred.Password
Note that you have to create that VICredentialStoreItem with the same account and on the same computer with which you run the scheduled task.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks LucD.
I can logon with the service account.
Question, this seems to store credentials in an xml file under %APPDATA%\VMware\credstore\vicredentials.xml.
Is it encrypted? Just doesn't seem safe...
thanks
Yes, it is encrypted.
It uses DPAPI, the MSFT cryptographic API available in Windows (which is also the reason why the VICredentialStore cmdlets are not supported on PowerShell Core).
The encrypted password is indeed stored on your station, and can only be decrypted on that same station and by the same user.
The reason is that the encryption key is also stored on the station and linked to the user account.
Is it secure?
Yes and no.
For day-to-day use it is considered safe, but an experienced hacker can reverse the DPAPI encryption.
There have been reported methods on how to do that.
Ultimately, if security is of the utmost importance in your environment, you will need to go further then just encrypted passwords.
Procedures with 2FA and/or a security token should be considered.
On the side, we had an interesting thread on a similar subject some time ago, see Is there a way to log onto vsphere clients without seeing clear text password?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi LucD,
I've tried the below like this:
#Variables
$vc1 = 'vc01'
$vc2 = 'vc02'
$credfile = 'vicredentials.xml'
$cred = Get-VICredentialStoreItem -File $credfile -Host $vc2
#Connect to vCenters
Connect-VIServer -Server $vc1
Connect-VIServer -Server $vc2 -User $cred.User -Password $cred.Password
Its actually working but I also get this error message:
Get-VICredentialStoreItem : Cannot bind parameter 'File' to the target. Exception setting "File": "Credentials file doesn't exist."
At line:12 char:41
+ $cred = Get-VICredentialStoreItem -File $credfile -Host $vc2
+ ~~~~~~~~~
+ CategoryInfo : WriteError: (:) [Get-VICredentialStoreItem], ParameterBindingException
+ FullyQualifiedErrorId : ParameterBindingFailed,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVICredentialStoreItem
Again its working by just running the script manually (havent tried the scedule task yet) but I still get the error above. Should I be concerned about it?
Also confirming I can see %APPDATA%\VMware\credstore\vicredentials.xml
thanks
Did you try specifying the full path, instead of just the filename, to the $credfile variable?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I havent tried that yet but why is it still working?
Are you sure there are no open connections when you run the script?
Check the content of $global:defaultviservers.
The Connect-VIServer to vc2 definitely fails, and according to the message because it can't find the credentials XML file.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference