Hi all. My objective is the following:
1) Stop VM
2) Take snapshot
3) Update video ram to new value
4) Start VM
I want each task to be confirmed as complete before proceeding to the next task.
The VMs are in a CSV file.
The stop VM and take snapshot completes successfully. Although there's an error in the second part (screen output).
It doesn't actually update the video ram but just prints out the part stating the script will complete before powering on the VM and it gets stuck there because the VMs are actually not powered on.
The screen output is below:
*****************************************************************************************
PS C:\PowerCLI\scripts\set_video_ram> C:\PowerCLI\Scripts\set_video_ram\update_vram_poweroff_snapshot.ps1
vm1 is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task...
vm2 is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task...
Name PowerState Num CPUs MemoryGB
---- ---------- -------- --------
vm1 PoweredOff 1 4.000
Snapshot of vm1 is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task...
Exception calling "ContainsKey" with "1" argument(s): "Key cannot be null.
Parameter name: key"
At H:\PowerCLI\Scripts\set_video_ram\update_vram_poweroff_snapshot.ps1:68 char:2
+ elseif($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error"){
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentNullException
vm2 PoweredOff 1 2.000
Snapshot of vm2 is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task...
Exception calling "ContainsKey" with "1" argument(s): "Key cannot be null.
Parameter name: key"
At H:\PowerCLI\Scripts\set_video_ram\update_vram_poweroff_snapshot.ps1:68 char:2
+ elseif($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error"){
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentNullException
The scrript will wait for the configuration task to be complete before the VMs are powered on
The scrript will wait for the configuration task to be complete before the VMs are powered on
The scrript will wait for the configuration task to be complete before the VMs are powered on
The scrript will wait for the configuration task to be complete before the VMs are powered on
The scrript will wait for the configuration task to be complete before the VMs are powered on
The scrript will wait for the configuration task to be complete before the VMs are powered on
The scrript will wait for the configuration task to be complete before the VMs are powered on
The scrript will wait for the configuration task to be complete before the VMs are powered on
The scrript will wait for the configuration task to be complete before the VMs are powered on
The script snippet is below:
***********************************************************************************
$newVideoRamSize = 9000
$vmlist = Import-Csv .\vmlist.csv -UseCulture
$vmlist1 = $vmlist | select -ExpandProperty VM
$taskTab = @{}
#Shutdown VMs
foreach ($vm in $vmlist1) {
#if($vm.Powerstate -eq "PoweredOn") { //FYI If this part is not commented out, the script will run without doing anything.
Write-Host $vm is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task... -foregroundcolor green
$taskTab[(Stop-VM -VM $vm -Confirm:$false -RunAsync).Id] = $vm
}
#}
#Take snapshot of VMs
$runningTasks = $taskTab.Count
while($runningTasks -gt 0){
Get-Task | % {
if($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success"){
Get-VM $taskTab[$_.Id]
Write-Host Snapshot of $taskTab[$_.Id] is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task... -foregroundcolor green
$tasktab[(New-Snapshot -VM $taskTab[$_.Id] -Name BeforeVideoRamChange -RunAsync).Id] = $vm
$taskTab.Remove($_.Id)
$runningTasks--
}
}
elseif($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error"){
$taskTab.Remove($_.Id)
$runningTasks--
}
}
Start-Sleep -Seconds 15
#Update Video Ram
$runningTasks = $taskTab.Count
while($runningTasks -gt 0){
Get-Task | % {
if($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success"){
Get-VM $taskTab[$_.Id]
if($taskTab[$_.Id].Powerstate -eq "PoweredOn")
{return "One or more VMs is still powered on. Manually power off VMs before re-attempting."}
$vid = $taskTab[$_.Id].ExtensionData.Config.Hardware.Device | ?{$_.GetType().Name -eq "VirtualMachineVideoCard"}
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$devChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
$devChange.Operation = 'edit'
$vid.videoRamSizeInKB = $newVideoRamSize
if ((!$devChange.Operation) -or (!$vid.videoRamSizeInKB))
{return "ERROR: Unable to set video memory on $taskTab[$_.Id]}. Ensure it is powered off."}
Write-Host Video Memory on VM: $taskTab[$_.Id] has been successfully set to $vid.videoRamSizeInKB -foregroundcolor green
$devChange.Device += $vid
$spec.DeviceChange += $devChange
$taskTab[$_.Id].ExtensionData.ReconfigVM($spec)
$taskTab.Remove($_.Id)
$runningTasks--
}
elseif($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error"){
$taskTab.Remove($_.Id)
$runningTasks--
}
Start-Sleep -Seconds 15
Write-Host The script will wait for the configuration task to be complete before the VMs are powered on -foregroundcolor green
}
}
#Power on VMs
$runningTasks = $taskTab.Count
while($runningTasks -gt 0){
Get-Task | % {
if($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success"){
Get-VM $taskTab[$_.Id]
if($taskTab[$_.Id].Powerstate -eq "PoweredOff") {
Write-Host $taskTab[$_.Id] is now being powered on. Please wait five to ten minutes before verifying new configuration -foregroundcolor green
$taskTab[(Start-VM -VM $taskTab[$_.Id] -Confirm:$false -RunAsync).Id] = $vm
}
}
}
}
*****************************************************************************************
Any help to point out the issues and/or fix the script would be greatly appreciated.
The issue is most likely because you the VirtualMachine in the hash table (with the Key of the TakId).
But such a VirtualMachine object is not updated automatically.
You will for example not see that the powerstate of the VM has changed.
For that you have to 'refresh' the object, by doing a new Get-VM.
Something like this
$vmlist = Import-Csv .\vmlist.csv -UseCulture
$vmlist1 = $vmlist | select -ExpandProperty VM
$taskTab = @{ }
#Shutdown VMs
foreach ($vm in $vmlist1) {
#if($vm.Powerstate -eq "PoweredOn") { //FYI If this part is not commented out, the script will run without doing anything.
Write-Host $vm is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task... -foregroundcolor green
$taskTab[(Stop-VM -VM $vm -Confirm:$false -RunAsync).Id] = $vm
}
#}
#Take snapshot of VMs
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
$vm = Get-VM $taskTab[$_.Id]
Write-Host "Snapshot of $($vm.Name) is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task..." -foregroundcolor green
$tasktab[(New-Snapshot -VM $vm -Name BeforeVideoRamChange -RunAsync).Id] = $vm
$taskTab.Remove($_.Id)
$runningTasks--
}
elseif ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error") {
$taskTab.Remove($_.Id)
$runningTasks--
}
}
Start-Sleep -Seconds 15
#Update Video Ram
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
$vm = Get-VM -Name ($taskTab[$_.Id]).Name
if ($vm.Powerstate -eq "PoweredOn") {
return "One or more VMs is still powered on. Manually power off VMs before re-attempting."
}
$vid = $vm.ExtensionData.Config.Hardware.Device | ? { $_.GetType().Name -eq "VirtualMachineVideoCard" }
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$devChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
$devChange.Operation = 'edit'
$vid.videoRamSizeInKB = $newVideoRamSize
if ((!$devChange.Operation) -or (!$vid.videoRamSizeInKB)){
return "ERROR: Unable to set video memory on $taskTab[$_.Id]}. Ensure it is powered off."
}
Write-Host Video Memory on VM: $taskTab[$_.Id] has been successfully set to $vid.videoRamSizeInKB -foregroundcolor green
$devChange.Device += $vid
$spec.DeviceChange += $devChange
$vm.ExtensionData.ReconfigVM($spec)
$taskTab.Remove($_.Id)
$runningTasks--
}
elseif ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error") {
$taskTab.Remove($_.Id)
$runningTasks--
}
Start-Sleep -Seconds 15
Write-Host The script will wait for the configuration task to be complete before the VMs are powered on -foregroundcolor green
}
}
#Power on VMs
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
$vm = Get-VM -Name (Get-VM $taskTab[$_.Id]).Name
if ($vm.Powerstate -eq "PoweredOff") {
Write-Host "$($vm.Name) is now being powered on. Please wait five to ten minutes before verifying new configuration" -foregroundcolor green
$taskTab[(Start-VM -VM $vm -Confirm:$false -RunAsync).Id] = $vm
}
}
}
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
If there are client-side tasks, there will not be an Id property, hence the error.
Try changing those lines to
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi LucD,
Thanks for your response, and I appreciate your help always. I did make the changes as suggested but got the same errors.
There must be one or more tasks that do not have an Id.
Can you check with
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Do you mean logging in to the vCSA and running this?
PS C:\Users\myuserid> Get-Task | Select Name,StartTime,Id
Result of the above here:
Name StartTime Id
---- --------- --
CloneVM_Task 10/08/2019 15:04:16 Task-task-234068
UpgradeVM_Task 10/08/2019 15:04:46 Task-task-234589
ReconfigVM_Task 10/08/2019 15:04:57 Task-task-234565
ReconfigVM_Task 10/08/2019 15:05:13 Task-task-234665
CloneVM_Task 10/08/2019 15:05:33 Task-task-234555
UpgradeVM_Task 10/08/2019 15:05:53 Task-task-233445
Or do you mean I need to update the script with the Get-Task | Select Name,StartTime,Id?
I had another look at your script, and there is a brace too much after the if-statement.
The elseif part was not inside the foreach block.
Change the code to
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
Get-VM $taskTab[$_.Id]
Write-Host Snapshot of $taskTab[$_.Id] is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task... -foregroundcolor green
$tasktab[(New-Snapshot -VM $taskTab[$_.Id] -Name BeforeVideoRamChange -RunAsync).Id] = $vm
$taskTab.Remove($_.Id)
$runningTasks--
} # Removed extra brace <===
elseif ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error") {
$taskTab.Remove($_.Id)
$runningTasks--
}
}
Start-Sleep -Seconds 15
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hmm. Tried that but it says it's missing a closing brace. See attached image.
When you take a brace away there, you have to add one at the end.
$vmlist = Import-Csv .\vmlist.csv -UseCulture
$vmlist1 = $vmlist | select -ExpandProperty VM
$taskTab = @{ }
#Shutdown VMs
foreach ($vm in $vmlist1) {
#if($vm.Powerstate -eq "PoweredOn") { //FYI If this part is not commented out, the script will run without doing anything.
Write-Host $vm is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task... -foregroundcolor green
$taskTab[(Stop-VM -VM $vm -Confirm:$false -RunAsync).Id] = $vm
}
#}
#Take snapshot of VMs
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
Get-VM $taskTab[$_.Id]
Write-Host Snapshot of $taskTab[$_.Id] is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task... -foregroundcolor green
$tasktab[(New-Snapshot -VM $taskTab[$_.Id] -Name BeforeVideoRamChange -RunAsync).Id] = $vm
$taskTab.Remove($_.Id)
$runningTasks--
}
elseif ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error") {
$taskTab.Remove($_.Id)
$runningTasks--
}
}
Start-Sleep -Seconds 15
#Update Video Ram
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
Get-VM $taskTab[$_.Id]
if ($taskTab[$_.Id].Powerstate -eq "PoweredOn") {
return "One or more VMs is still powered on. Manually power off VMs before re-attempting."
}
$vid = $taskTab[$_.Id].ExtensionData.Config.Hardware.Device | ? { $_.GetType().Name -eq "VirtualMachineVideoCard" }
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$devChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
$devChange.Operation = 'edit'
$vid.videoRamSizeInKB = $newVideoRamSize
if ((!$devChange.Operation) -or (!$vid.videoRamSizeInKB)){
return "ERROR: Unable to set video memory on $taskTab[$_.Id]}. Ensure it is powered off."
}
Write-Host Video Memory on VM: $taskTab[$_.Id] has been successfully set to $vid.videoRamSizeInKB -foregroundcolor green
$devChange.Device += $vid
$spec.DeviceChange += $devChange
$taskTab[$_.Id].ExtensionData.ReconfigVM($spec)
$taskTab.Remove($_.Id)
$runningTasks--
}
elseif ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error") {
$taskTab.Remove($_.Id)
$runningTasks--
}
Start-Sleep -Seconds 15
Write-Host The script will wait for the configuration task to be complete before the VMs are powered on -foregroundcolor green
}
}
#Power on VMs
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
Get-VM $taskTab[$_.Id]
if ($taskTab[$_.Id].Powerstate -eq "PoweredOff") {
Write-Host $taskTab[$_.Id] is now being powered on. Please wait five to ten minutes before verifying new configuration -foregroundcolor green
$taskTab[(Start-VM -VM $taskTab[$_.Id] -Confirm:$false -RunAsync).Id] = $vm
}
}
}
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Yep. You're right. I updated the script. Thank you.
It took only the snapshot of one of the 2 VMs though. Also, now it's just stuck at "The script will wait for the configuration task to be complete before the VMs are powered on" and doesn't progress to update the video ram and start up the VMs. See results below. Any ideas?
*********************************************************************************************
PS C:\PowerCLI\> C:\PowerCLI\update_vram_poweroff_snapshot.ps1
VM1 is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task...
VM2 is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task...
Name PowerState Num CPUs MemoryGB
---- ---------- -------- --------
VM1 PoweredOff 1 4.000
Snapshot of VM1 is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task...
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
The script will wait for the configuration task to be complete before the VMs are powered on
PS C:\PowerCLI\>
Do I need to change this:
$_.Id) -and $_.State -eq "Success") to this:
$_.Status) -and $_.State -eq "Completed") to match the tab name and actual results in vCenter tasks perhaps?
I'd also like to add, I have another version of this script, which actually does everything but I don't think the wait-task works. Here it is:
******************************************************************************************************************************************************
$newVideoRamSize = 9000
$vmlist1 = $vmlist | select -ExpandProperty VM
#Shutdown VMs
foreach ($vm in $vmlist1) {
$guestname = Get-VM $vm
if($guestname.Powerstate -eq "PoweredOn") {
Write-Host $guestname is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task... -foregroundcolor green
$shutvmtask = Stop-VM -VM $guestname -Confirm:$false -RunAsync | Out-Null }
Wait-Task $shutvmtask
Start-Sleep -Seconds 15
}
#Take snapshot of VMs
foreach ($vm in $vmlist1) {
$guestname = Get-VM $vm
Write-Host Snapshot of $guestname is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task... -foregroundcolor green
$snapshotvmtask = New-Snapshot -VM $guestname -Name BeforeVideoRamChange -RunAsync | Out-Null }
Wait-Task $snapshotvmtask
Start-Sleep -Seconds 15
#Update Video Ram
foreach ($vm in $vmlist1) {
$guestname = Get-VM $vm
if($guestname.Powerstate -eq "PoweredOn")
{return "One or more VMs is still powered on. Manually power off VMs before re-attempting."}
$vid = $guestname.ExtensionData.Config.Hardware.Device | ?{$_.GetType().Name -eq "VirtualMachineVideoCard"}
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$devChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
$devChange.Operation = 'edit'
$vid.videoRamSizeInKB = $newVideoRamSize
if ((!$devChange.Operation) -or (!$vid.videoRamSizeInKB))
{return "ERROR: Unable to set video memory on $guestname}. Ensure it is powered off."}
Write-Host Video Memory on VM: $guestname has been successfully set to $vid.videoRamSizeInKB -foregroundcolor green
$devChange.Device += $vid
$spec.DeviceChange += $devChange
$vramconfigtask = $guestname.ExtensionData.ReconfigVM($spec)
Wait-Task $vramconfigtask
Start-Sleep -Seconds 15
Write-Host The script will wait for the configuration task to be complete before the VMs are powered on -foregroundcolor green
}
#Power on VMs
foreach ($vm in $vmlist1) {
$guestname = Get-VM $vm
if($guestname.Powerstate -eq "PoweredOff") {
Write-Host $guestname is now being powered on. Please wait five to ten minutes before verifying new configuration -foregroundcolor green
Start-VM -VM $guestname -Confirm:$false -RunAsync | Out-Null }
}
******************************************************************************************************************************************************
The output is below:
******************************************************************************************************************************************************
VM1 is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task...
Wait-Task : Cannot validate argument on parameter 'Task'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\PowerCLI\update_vram_poweroff_snapshot-Copy.ps1:53 char:15
+ Wait-Task $shutvmtask
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Wait-Task], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.WaitTask
VM2 is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task...
Wait-Task : Cannot validate argument on parameter 'Task'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\PowerCLI\update_vram_poweroff_snapshot-Copy.ps1:53 char:15
+ Wait-Task $shutvmtask
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Wait-Task], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.WaitTask
Snapshot of VM1 is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task...
Snapshot of VM2 is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task...
Wait-Task : Cannot validate argument on parameter 'Task'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\PowerCLI\update_vram_poweroff_snapshot-Copy.ps1:62 char:15
+ Wait-Task $snapshotvmtask
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Wait-Task], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.WaitTask
Video Memory on VM: VM1 has been successfully set to 9000
Wait-Task : Cannot validate argument on parameter 'Task'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\PowerCLI\update_vram_poweroff_snapshot-Copy.ps1:85 char:19
+ Wait-Task $vramconfigtask
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Wait-Task], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.WaitTask
The scrript will wait for the configuration task to be complete before the VMs are powered on
Video Memory on VM: VM2 has been successfully set to 9000
Wait-Task : Cannot validate argument on parameter 'Task'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\PowerCLI\update_vram_poweroff_snapshot-Copy.ps1:85 char:19
+ Wait-Task $vramconfigtask
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Wait-Task], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.WaitTask
The scrript will wait for the configuration task to be complete before the VMs are powered on
VM1 is now being powered on. Please wait five to ten minutes before verifying new configuration
VM2 is now being powered on. Please wait five to ten minutes before verifying new configuration
The issue is most likely because you the VirtualMachine in the hash table (with the Key of the TakId).
But such a VirtualMachine object is not updated automatically.
You will for example not see that the powerstate of the VM has changed.
For that you have to 'refresh' the object, by doing a new Get-VM.
Something like this
$vmlist = Import-Csv .\vmlist.csv -UseCulture
$vmlist1 = $vmlist | select -ExpandProperty VM
$taskTab = @{ }
#Shutdown VMs
foreach ($vm in $vmlist1) {
#if($vm.Powerstate -eq "PoweredOn") { //FYI If this part is not commented out, the script will run without doing anything.
Write-Host $vm is now being powered off. The script will confirm all VMs are powered off before proceeding to the next task... -foregroundcolor green
$taskTab[(Stop-VM -VM $vm -Confirm:$false -RunAsync).Id] = $vm
}
#}
#Take snapshot of VMs
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
$vm = Get-VM $taskTab[$_.Id]
Write-Host "Snapshot of $($vm.Name) is being taken before configuration change. The script will confirm all VM snapshots are complete before proceeding to the next task..." -foregroundcolor green
$tasktab[(New-Snapshot -VM $vm -Name BeforeVideoRamChange -RunAsync).Id] = $vm
$taskTab.Remove($_.Id)
$runningTasks--
}
elseif ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error") {
$taskTab.Remove($_.Id)
$runningTasks--
}
}
Start-Sleep -Seconds 15
#Update Video Ram
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
$vm = Get-VM -Name ($taskTab[$_.Id]).Name
if ($vm.Powerstate -eq "PoweredOn") {
return "One or more VMs is still powered on. Manually power off VMs before re-attempting."
}
$vid = $vm.ExtensionData.Config.Hardware.Device | ? { $_.GetType().Name -eq "VirtualMachineVideoCard" }
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$devChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
$devChange.Operation = 'edit'
$vid.videoRamSizeInKB = $newVideoRamSize
if ((!$devChange.Operation) -or (!$vid.videoRamSizeInKB)){
return "ERROR: Unable to set video memory on $taskTab[$_.Id]}. Ensure it is powered off."
}
Write-Host Video Memory on VM: $taskTab[$_.Id] has been successfully set to $vid.videoRamSizeInKB -foregroundcolor green
$devChange.Device += $vid
$spec.DeviceChange += $devChange
$vm.ExtensionData.ReconfigVM($spec)
$taskTab.Remove($_.Id)
$runningTasks--
}
elseif ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error") {
$taskTab.Remove($_.Id)
$runningTasks--
}
Start-Sleep -Seconds 15
Write-Host The script will wait for the configuration task to be complete before the VMs are powered on -foregroundcolor green
}
}
#Power on VMs
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
$vm = Get-VM -Name (Get-VM $taskTab[$_.Id]).Name
if ($vm.Powerstate -eq "PoweredOff") {
Write-Host "$($vm.Name) is now being powered on. Please wait five to ten minutes before verifying new configuration" -foregroundcolor green
$taskTab[(Start-VM -VM $vm -Confirm:$false -RunAsync).Id] = $vm
}
}
}
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks. I updated the script but unfortunately it's the same result as before,i.e. "The script will wait for the configuration task to be complete before the VMs are powered on" and doesn't progress to update the video ram and start up the VMs.
I'll go through the script again more carefully and post results later today or tomorrow. Thank you so much for all your time!
Hey LucD, I made some modifications. Now the script works. I had to however remove some of the "tasktab" and error control portions in the #Shutdown VMs and #Power on VMs sections of the script for it to work. I'm sure I'm just missing something small but I needed to get this working ASAP and also don't have the knowledge yet to fix it quickly. Anyway, here's the final script. If you or anyone else can enhance it that would be greatly appreciated! Thanks so much for all your help!
******************************************************************************************************************************************************************************
$newVideoRamSize = 9000
$vmlist = Import-Csv .\vmlist.csv -UseCulture
$vmlist1 = $vmlist | select -ExpandProperty VM
$taskTab = @{ }
#Shutdown VMs
foreach ($vm in $vmlist1) {
Write-Host $vm will shutdown in preparation for the Video Ram configuration change. -foregroundcolor green
$taskTab[(Stop-VM -VM $vm -Confirm:$false -RunAsync).Id] = $vm
}
Start-Sleep -Seconds 30
#Take snapshot of VMs
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
$vm = Get-VM $taskTab[$_.Id]
Write-Host $vm snapshot is being taken before the configuration change should a rollback be necessary. -foregroundcolor green
$tasktab[(New-Snapshot -VM $taskTab[$_.Id] -Name BeforeVideoRamChange -RunAsync).Id] = $vm
$taskTab.Remove($_.Id)
$runningTasks--
}
elseif ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error") {
$taskTab.Remove($_.Id)
$runningTasks--
}
}
}
Start-Sleep -Seconds 30
#Update Video Ram
foreach ($vm in $vmlist1) {
$runningTasks = $taskTab.Count
while ($runningTasks -gt 0) {
Get-Task | % {
if ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Success") {
$vm = Get-VM ($taskTab[$_.Id]).Name
if ($vm.Powerstate -eq "PoweredOn") {
return "$vm is still powered on. Manually power off VMs before re-attempting."
}
$vid = $vm.ExtensionData.Config.Hardware.Device | ? { $_.GetType().Name -eq "VirtualMachineVideoCard" }
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$devChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
$devChange.Operation = 'edit'
$vid.videoRamSizeInKB = $newVideoRamSize
if ((!$devChange.Operation) -or (!$vid.videoRamSizeInKB)){
return "ERROR: Unable to set video memory on $($vm.Name). Ensure it is powered off."
}
Write-Host $($vm.Name) video memory has been successfully set to $newVideoRamSize -foregroundcolor green
$devChange.Device += $vid
$spec.DeviceChange += $devChange
$vm.ExtensionData.ReconfigVM($spec)
$taskTab.Remove($_.Id)
$runningTasks--
}
elseif ($taskTab.ContainsKey($_.Id) -and $_.State -eq "Error") {
$taskTab.Remove($_.Id)
$runningTasks--
}
}
}
}
Start-Sleep -Seconds 30
#Power on VMs
foreach ($vm in $vmlist1) {
Write-Host $vm is being powered back on. -foregroundcolor green
$taskTab[(Start-VM -VM $vm -Confirm:$false -RunAsync).Id] = $vm
}
Start-Sleep -Seconds 30
Write-Host Configuration complete. Confirm new change in 5 to 10 minutes. -foregroundcolor green