julianwood
Enthusiast
Enthusiast

How to Keep or Disgard the UUID when powering on a VM

Jump to solution

We have a scenario where we are mirroring VMs from one site to another site for BCP that has a separate VC instance.

We are pre-registering the NFS hosted VMs in virtual center.

When we need to do the recovery we break the mirror and power on the machines.

VC then promp with the question, Do you want to Keep or Discard the UUID.

How can this be scripted as its easy to answer for a few VMs but a pain for possibly up to a hundred?

http://WoodITWork.com
0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership

There are a few things to keep in mind when you want to start the guests and answer the question this way.

1) The Start-VM cmdlet will wait for the guest to be started but since there is a pending question this will never happen.

==> the solution is to use the Start-VM cmdlet with the -RunAsync parameter, that way the cmdlet will not wait.

2) When a guest starts it will take some time before the question appears.

==> the solution is to wait with a loop till the question appears

3) to get the actual state of the guest the script needs to get the VirtualMachine object with every run through the loop.

The properties in the $vm variable are not automatically updated unless the script fetches the object again with the Get-View cmdlet.

4) the Question object is only present when the question appears. Before that point this object is $null.

==> to avoid executing the StartsWith method on an $null object the if statement first checks if the Question object is present.

The script relies on the fact that the two conditions that are combined with -and operator are executed left to right.

This is probably not a good programming practice and should be solved by using two nested if statements !

The following script implements all the points raised above.

Note that it can only be used for the msg.uuid.moved question.

The script answers with choice 2 which is the "Keep" choice.

$qMsgUuidMoved = "msg.uuid.moved:"
$choiceKeep = 2

$vmImpl = Get-VM "TestPC"
$vmImpl | Start-VM -RunAsync

do{
  $vm = $vmImpl | Get-View
  if($vm.Runtime.Question -ne $null -and $vm.Runtime.Question.Text.StartsWith($qMsgUuidMoved)){
    $vm.AnswerVM($vm.Runtime.Question.Id, $choiceKeep)
  }
} until ($vm.Runtime.PowerState -ne "poweredoff")

Write-Host $vm.Name "started"


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

0 Kudos
16 Replies
halr9000
Commander
Commander

Here is the SDK method to get you started.

PS > $a = Get-VM myvm | Get-View
PS > $a | gm *answer*

   TypeName: VMware.Vim.VirtualMachine

Name     MemberType Definition
----     ---------- ----------
AnswerVM Method     System.Void AnswerVM(String questionId, String answerChoice)



[PowerShell MVP|https://mvp.support.microsoft.com/profile=5547F213-A069-45F8-B5D1-17E5BD3F362F], VI Toolkit forum moderator

Author of the upcoming book: Managing VMware Infrastructure with PowerShell

Co-Host, PowerScripting Podcast (http://powerscripting.net)

Need general, non-VMware-related PowerShell Help? Try the forums at PowerShellCommunity.org

My signature used to be pretty, but then the forum software broked it. vExpert. Microsoft MVP (Windows PowerShell). Author, Podcaster, Speaker. I'm @halr9000
halr9000
Commander
Commander

Going further, here's the page in the SDK: http://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.VirtualMachine.html#an...

It's not very helpful. So, I searched for data objects and found QuestionInfo. Hmm. I don't have any VMs with questions right now to look at as an example. Ok, here's what the question would be if I had one--yours should have it:

$a.Runtime.Question

So look at that, and you should be able to come up with the question ID and choice to then provide to the AnswerVM() method.






[PowerShell MVP|https://mvp.support.microsoft.com/profile=5547F213-A069-45F8-B5D1-17E5BD3F362F], VI Toolkit forum moderator

Author of the upcoming book: Managing VMware Infrastructure with PowerShell

Co-Host, PowerScripting Podcast (http://powerscripting.net)

Need general, non-VMware-related PowerShell Help? Try the forums at PowerShellCommunity.org

My signature used to be pretty, but then the forum software broked it. vExpert. Microsoft MVP (Windows PowerShell). Author, Podcaster, Speaker. I'm @halr9000
0 Kudos
tonygent
Enthusiast
Enthusiast

Sorry to sound a bit thick Smiley Happy (but I am).

But could someone provide some example code on how to receive the question and then submit the answer. I have a similar issue with replicated Datastores and controller changes from BUS to LSI logic etc. And have the PowerShell answer the question (as it only happens when the machine tries to boot) would make life far more robust.

Any help would be much appreciated.

If I do find the answer myself - I'll post as well.

TG

0 Kudos
LucD
Leadership
Leadership

Receiving the question(s) can be done like this

Get-VM | Get-View | %{
  if ($_.Runtime.Question -ne $null){
   Write-Host -foregroundcolor blue "==>" $_.Name 
   Write-Host -foregroundcolor blue $_.Runtime.Question.Id
   Write-Host $_.Runtime.Question.Text
   foreach($choice in $_.Runtime.Question.Choice.ChoiceInfo){
     Write-Host -foregroundcolor green $choice.Key $choice.Summary
   }
}

Answering the question via a script is a bit more tricky.

Not the method how you can answer but the algorithm you would use to make a selection from the valid answers.

It would be dangerous (in my opinion) to always go for the same answer for the same question id.

Once you know the reply giving the answer to the question is straight forward

Get-VM | Get-View | %{
  if ($_.Runtime.Question -ne $null){
    $_.AnswerVM($_.Runtime.Question.Id, <selected-choice-key>)
}

The question id for a SCSI controller change from Bus to Lsi logic is always 4.

It could be handy to foresee answers to the different questions (see property Question.Id) that are possible.

That could for example be done via a switch statement.

I wasn't able to find a list of all the possible question ids.

If someone could provide a pointer ?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
cody_bunch
Hot Shot
Hot Shot

Mr LucD, you are quick. Your's is much more elegant, but this is what I came up with: http://professionalvmware.com/2009/01/18/answering-vm-questions-with-powershell/

-Cody Bunch

http://professionalvmware.com

-Cody Bunch http://professionalvmware.com
0 Kudos
tonygent
Enthusiast
Enthusiast

Hi Both,

Well - I'm glad I took the time to post. Both of you have provided exactly what I needed.

Many many thanks, You've saved me hours Smiley Happy

TG

0 Kudos
ickyboo
Contributor
Contributor

Hi,

We were faced with the same problem but did not want to provide any interactive input during startup.

So we decided to simply set the extraConfig entry for 'uuid.action' to 'keep' in all the VMs before starting them.

That way, it never asks - and you can always set the value back to 'create' if you need to.

Just thought you might like another option.

Thanks

0 Kudos
julianwood
Enthusiast
Enthusiast

I've only had a chance recently to look at this again.

Thanks again LucD for a great script.

However I've come across a scenario where I need some more help.

The script I'm working on is to automate bringing up VMs mirrored from primary site to a BCP site.

I have everything done so that the storage breaks the mirror and the iSCSI LUNs are presented and the VMs found and added to the inventory. (I'll post the script when I've finished)

Now the problem comes with the UUID. There is no question available to answer until you actually power a VM on.

Problem is once you power a group of VMs on in a script the script will wait for the answer before continuing which means I can't answer the question until I've powered the VMs on but the script won't continue until I answer the question. (If that makes any sense)

I've cut down the rest of the script and this is what I would like to happen:

$vmfolder = "BCP Servers" # Folder to place found VMs - Must be unique in VC

#Get all VMs in $vmfolder

$vms = get-vm -Location (get-folder $vmfolder)

#Answer Question to Keep UUID

$vms | Get-View | %{if ($_.Runtime.Question -ne $null){$_.AnswerVM($_.Runtime.Question.Id, 2)}}

#Power on VMs

$vms | Start-VM

Unfortunately #Answer Question to Keep UUID does not return anything at this stage and so when Start-VM initialises it still has the questions to answer but I can't power on the VMs first as the script pauses waiting for my answer.

I've tried a few different ways of combining the statements but can't seem to find the right one.

Something like this

#Power on VMs and Answer Questions

$vms | Start-VM | Get-View | %{if ($_.Runtime.Question -ne $null){$_.AnswerVM($_.Runtime.Question.Id, 2)}}How can I group the power on and answer into one statement which would work on a group of VMs?

Any ideas?

http://WoodITWork.com
0 Kudos
LucD
Leadership
Leadership

There are a few things to keep in mind when you want to start the guests and answer the question this way.

1) The Start-VM cmdlet will wait for the guest to be started but since there is a pending question this will never happen.

==> the solution is to use the Start-VM cmdlet with the -RunAsync parameter, that way the cmdlet will not wait.

2) When a guest starts it will take some time before the question appears.

==> the solution is to wait with a loop till the question appears

3) to get the actual state of the guest the script needs to get the VirtualMachine object with every run through the loop.

The properties in the $vm variable are not automatically updated unless the script fetches the object again with the Get-View cmdlet.

4) the Question object is only present when the question appears. Before that point this object is $null.

==> to avoid executing the StartsWith method on an $null object the if statement first checks if the Question object is present.

The script relies on the fact that the two conditions that are combined with -and operator are executed left to right.

This is probably not a good programming practice and should be solved by using two nested if statements !

The following script implements all the points raised above.

Note that it can only be used for the msg.uuid.moved question.

The script answers with choice 2 which is the "Keep" choice.

$qMsgUuidMoved = "msg.uuid.moved:"
$choiceKeep = 2

$vmImpl = Get-VM "TestPC"
$vmImpl | Start-VM -RunAsync

do{
  $vm = $vmImpl | Get-View
  if($vm.Runtime.Question -ne $null -and $vm.Runtime.Question.Text.StartsWith($qMsgUuidMoved)){
    $vm.AnswerVM($vm.Runtime.Question.Id, $choiceKeep)
  }
} until ($vm.Runtime.PowerState -ne "poweredoff")

Write-Host $vm.Name "started"


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

0 Kudos
julianwood
Enthusiast
Enthusiast

LucD, as usual that is excellent.

I will post separately when I have the complete script to share what I have come up with.

It will be two scripts. One to create consistent VM and mirror them to a remote site and the second script to recoer the VMs in the remote site. Think of it has SRM for free!

http://WoodITWork.com
0 Kudos
julianwood
Enthusiast
Enthusiast

Oops, I didn't actually post the script that all worked.

I'll write another post for the mirroring script but here's the easy way to power on all VMs in a folder and answer the question.

Can't ever seem to get this quoting thing right especially with indents...anyway

  1. Get All VMs in pariticular VC folder

$vms = get-vm -Location (get-folder "BCP Servers")

  1. Disconnect Networking if required FOR TESTING ONLY

$vms | get-networkadapter | where {'ext_vswitch1' -contains $_.NetworkName} | Set-NetworkAdapter -StartConnected:$false -Confirm:$false

  1. Power on VMs even with questions pending

$vms | Start-VM -RunAsync

$qMsgUuidMoved = "msg.uuid.moved:"

$choiceKeep = 2

ForEach ($vm in $vms)

{do

{

$vmview = $vm | Get-View

if($vmview.Runtime.Question -ne $null -and $vmview.Runtime.Question.Text.StartsWith($qMsgUuidMoved))

{

$vmview.AnswerVM($vmview.Runtime.Question.Id, $choiceKeep)

}

}

until ($vmview.Runtime.PowerState -ne "poweredoff")

}

http://WoodITWork.com
0 Kudos
tonygent
Enthusiast
Enthusiast

Hi all, thought the following code may help others who are trying to get VMDK's to attached to one VM that were created on another. It helps by answering NO to the question "Do you want to change the disk controller type" at bootup. Note - this code seems quite long, but I'm a beginner and I like to write where I can see exactly what's happening, so you will note a LOT of Write-host statements, feel free to remove if you like.

$sPowerOnMsg = "msg.disk.adapterMismatch:"

$sWinProxy = "VCB_Proxy"

$iChoice = 1 # choice of 1 does NOT change the disk type (choice of 0 does) If you do NOT change (ie - 1) then the question will re-occure each time you boot the VM.

$iVMRestartTimeout = 200

$oWinVM = Get-VM -name $sWinProxy -ea silentlycontinue

$oWinVMv = $oWinVM | get-view

  1. Restart the Proxy VM.

if ($oWinVM.PowerState -eq "PoweredOff")

{

Write-host "VM is Powered Off - Restarting VM : " $sWinProxy

$oWinVM | Start-vm -RunAsync

write-host "started"

Do

{

sleep 10

$iVMRestartTimeout = $iVMRestartTimeout - 10

if ($iVMRestartTimeout -lt 0) {throw "Timeout Error Restarting Proxy VM : $sWinProxy"}

#Recheck the VM state

$oWinVM = Get-VM -name $sWinProxy

$oWinVMv = $oWinVM | get-view

if($oWinVMv.Runtime.Question -ne $null -and $oWinVMv.Runtime.Question.Text.StartsWith($sPowerOnMsg))

{

Write-host $oWinVMv.Runtime.Question.ID

Write-host $oWinVMv.Runtime.Question.Text

Write-host "ProxyVM Asked weather to change DIsk Types, Answering NO ($iChoice)"

Write-host "ANSWERING QUESTION with answer $iChoice"

$oWinVMv.AnswerVM($oWinVMv.Runtime.Question.Id, $iChoice)

}

$sPowerState = $oWinVM.PowerState

Write-host "Sleeping, Timeout is currently $iVMRestartTimeout, PowerState is $sPowerState"

} until ($oWinVM.PowerState -eq "PoweredOn")

}

elseif ($oWinVM.PowerState -eq "Suspended")

{

Write-host "VM is in a Suspended State : " $sWinProxy

throw "Proxy VM is in a suspended state, please shutddown th VM and re-run script: $sWinProxy"

}

else

{

Write-host "VM is already in a Powered on state : " $sWinProxy

throw "Proxy VM is already powered on, please shutddown th VM and re-run script: $sWinProxy"

}

Write-host "Proxy is Powered on : " $sWinProxy

Hope this helps someone Smiley Happy

0 Kudos
R0Ge
Contributor
Contributor

Hi LucD,

With vSphere 4 update 1, I know there is a new Set-VMQuestion cmdlet but I could not configured it correctly,

Your script can also be used for the "msg.uuid.altered:" question with vSphere update1 .

And the script worked great.

Robert

0 Kudos
LucD
Leadership
Leadership

That is correct Robert.

Did you try something like this

Get-VM <VM-name> | Get-VMQuestion -QuestionText "*UUID*" | Set-VMQuestion -Option "Ok"

You have several options for the reply, you can go for the -DefaultOption parameter or you can select a specific answer with -Option where you will have to provide a string with the answer (e.g. "ok", "cancel"...)

____________

Blog: LucD notes

Twitter: lucd22


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
R0Ge
Contributor
Contributor

Hi LucD,

Have used your script serveral times and with datacenter migrations for unknown reason, sometimes a vm loses the path to datastores, and when powered-on with the original script in a loop with serveral vm's, the script is wating for that corrupt vm. (Can also be simulated by editing vmx to non existing vmdk).

I am learning PowerCLI and now modified it see below with some error handeling so it continues and create a errorfile with vmname.

By the way great book " PowerCLI Reference"  Smiley Happy

Regards Robert.

##################################
# Declare global and static variables
# VMware VirtualCenter server name
#################################
CLS
$vcserver="xxx"
$Inputfile = "c:\Input_scripts\Servers.txt"
$TaskErrorFile = "c:\ErrorLog\TaskError.txt"
$TaskError_VMname = "c:\ErrorLog\TaskErrorVMname.txt"

# For ESX 3.5x "msg.uuid.moved:"
#$qMsgUuidMoved = "msg.uuid.moved:"

#For ESX 4.x "msg.uuid.altered:"
$qMsgUuidMoved = "msg.uuid.altered:"
$choiceKeep = 2

#################
# Add VI-toolkit
#################
Add-PSsnapin VMware.VimAutomation.Core -ErrorAction SilentlyContinue


Connect-VIServer $vcserver -User yyy -Password zzz


# *************   Start Process   *********************************************

foreach ($vmname in Get-Content $Inputfile)
{

$vmImpl = Get-VM $vmname
# Note -RunAsync does not work with -ErrorVariable
$vmImpl | Start-VM -ErrorVariable StartError -ErrorAction:SilentlyContinue
If ($StartError) {
# Create output file for working with
Write-Output $StartError | Out-File $TaskErrorFile

# Get data and create variable with line that contains VirtualMachine*
$ErrorData = Get-Content $TaskErrorFile | Select-String -Pattern "VirtualMachine" -SimpleMatch
$ErrorData = $ErrorData.Line

# Create Array from data and filter for vm_id
$vm_ID = ($ErrorData).Split(" ") | where { $_ -match "VirtualMachine*"}

#Get vm properies for VMname and create errorfile with VMname which failed to start
$VM = Get-VM -Id $vm_ID
Write-Output $VM.Name | Out-file $TaskError_VMname

#Remove temp file(s)
Remove-Item $TaskErrorFile
}
Else {
do{
  $vm = $vmImpl | Get-View
  if($vm.Runtime.Question -ne $null -and $vm.Runtime.Question.Text.StartsWith($qMsgUuidMoved)){
    $vm.AnswerVM($vm.Runtime.Question.Id, $choiceKeep)
  }
} until ($vm.Runtime.PowerState -ne "poweredoff")

Write-Host $vm.Name "started"
}


}
# *************   End Process   ***********************************************
DisConnect-VIServer -confirm:$false -Force:$true

0 Kudos
LucD
Leadership
Leadership

Thanks Robert.

Great script, thanks for sharing.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos